@@ -22,33 +22,33 @@ class CustomAggregationTests : SQLiteTestCase {
2222 try ! InsertUser ( " Eve " , age: 28 , admin: false )
2323 }
2424
25- func testCustomSum ( ) {
25+ func testUnsafeCustomSum ( ) {
2626 let step = { ( bindings: [ Binding ? ] , state: UnsafeMutablePointer < Int64 > ) in
2727 if let v = bindings [ 0 ] as? Int64 {
2828 state. pointee += v
2929 }
3030 }
31-
31+
3232 let final = { ( state: UnsafeMutablePointer < Int64 > ) -> Binding ? in
3333 let v = state. pointee
3434 let p = UnsafeMutableBufferPointer ( start: state, count: 1 )
3535 p. deallocate ( )
3636 return v
3737 }
38- let _ = db. createAggregation ( " mySUM " , step: step, final: final) {
38+ let _ = db. createAggregation ( " mySUM1 " , step: step, final: final) {
3939 let v = UnsafeMutableBufferPointer< Int64> . allocate( capacity: 1 )
4040 v [ 0 ] = 0
4141 return v. baseAddress!
4242 }
43- let result = try ! db. prepare ( " SELECT mySUM (age) AS s FROM users " )
43+ let result = try ! db. prepare ( " SELECT mySUM1 (age) AS s FROM users " )
4444 let i = result. columnNames. index ( of: " s " ) !
4545 for row in result {
4646 let value = row [ i] as? Int64
4747 XCTAssertEqual ( 83 , value)
4848 }
4949 }
5050
51- func testCustomSumGrouping ( ) {
51+ func testUnsafeCustomSumGrouping ( ) {
5252 let step = { ( bindings: [ Binding ? ] , state: UnsafeMutablePointer < Int64 > ) in
5353 if let v = bindings [ 0 ] as? Int64 {
5454 state. pointee += v
@@ -60,14 +60,71 @@ class CustomAggregationTests : SQLiteTestCase {
6060 p. deallocate ( )
6161 return v
6262 }
63- let _ = db. createAggregation ( " mySUM " , step: step, final: final) {
63+ let _ = db. createAggregation ( " mySUM2 " , step: step, final: final) {
6464 let v = UnsafeMutableBufferPointer< Int64> . allocate( capacity: 1 )
6565 v [ 0 ] = 0
6666 return v. baseAddress!
6767 }
68- let result = try ! db. prepare ( " SELECT mySUM (age) AS s FROM users GROUP BY admin ORDER BY s " )
68+ let result = try ! db. prepare ( " SELECT mySUM2 (age) AS s FROM users GROUP BY admin ORDER BY s " )
6969 let i = result. columnNames. index ( of: " s " ) !
7070 let values = result. compactMap { $0 [ i] as? Int64 }
7171 XCTAssertTrue ( values. elementsEqual ( [ 28 , 55 ] ) )
7272 }
73+
74+ func testCustomSum( ) {
75+ let reduce : ( Int64 , [ Binding ? ] ) -> Int64 = { ( last, bindings) in
76+ let v = ( bindings [ 0 ] as? Int64 ) ?? 0
77+ return last + v
78+ }
79+ let _ = db. createAggregation ( " myReduceSUM1 " , initialValue: Int64 ( 2000 ) , reduce: reduce, result: { $0 } )
80+ let result = try ! db. prepare ( " SELECT myReduceSUM1(age) AS s FROM users " )
81+ let i = result. columnNames. index ( of: " s " ) !
82+ for row in result {
83+ let value = row [ i] as? Int64
84+ XCTAssertEqual ( 2083 , value)
85+ }
86+ }
87+
88+ func testCustomSumGrouping( ) {
89+ let reduce : ( Int64 , [ Binding ? ] ) -> Int64 = { ( last, bindings) in
90+ let v = ( bindings [ 0 ] as? Int64 ) ?? 0
91+ return last + v
92+ }
93+ let _ = db. createAggregation ( " myReduceSUM2 " , initialValue: Int64 ( 3000 ) , reduce: reduce, result: { $0 } )
94+ let result = try ! db. prepare ( " SELECT myReduceSUM2(age) AS s FROM users GROUP BY admin ORDER BY s " )
95+ let i = result. columnNames. index ( of: " s " ) !
96+ let values = result. compactMap { $0 [ i] as? Int64 }
97+ XCTAssertTrue ( values. elementsEqual ( [ 3028 , 3055 ] ) )
98+ }
99+
100+ func testCustomObjectSum( ) {
101+ {
102+ let initial = TestObject ( value: 1000 )
103+ let reduce : ( TestObject , [ Binding ? ] ) -> TestObject = { ( last, bindings) in
104+ let v = ( bindings [ 0 ] as? Int64 ) ?? 0
105+ return TestObject ( value: last. value + v)
106+ }
107+ let _ = db. createAggregation ( " myReduceSUMX " , initialValue: initial, reduce: reduce, result: { $0. value } )
108+ // end this scope to ensure that the initial value is retained
109+ // by the createAggregation call.
110+ } ( )
111+ let result = try ! db. prepare ( " SELECT myReduceSUMX(age) AS s FROM users " )
112+ let i = result. columnNames. index ( of: " s " ) !
113+ for row in result {
114+ let value = row [ i] as? Int64
115+ XCTAssertEqual ( 1083 , value)
116+ }
117+ }
118+ }
119+
120+ /// This class is used to test that aggregation state variables
121+ /// can be reference types and are properly memory managed when
122+ /// crossing the Swift<->C boundary multiple times.
123+ class TestObject {
124+ var value : Int64
125+ init ( value: Int64 ) {
126+ self . value = value
127+ }
128+ deinit {
129+ }
73130}
0 commit comments