@@ -257,6 +257,104 @@ class AssociationHasManyThroughFirstSQLTests: GRDBTestCase {
257
257
}
258
258
}
259
259
260
+ func testHasManyThroughHasManyFirst( ) throws {
261
+ struct A : TableRecord , EncodableRecord {
262
+ static let b = belongsTo ( B . self)
263
+ static let c = hasMany ( C . self, through: b, using: B . c)
264
+ static let d = hasMany ( D . self, through: c. first, using: C . d)
265
+ func encode( to container: inout PersistenceContainer ) {
266
+ container [ " bId " ] = 1
267
+ }
268
+ }
269
+ struct B : TableRecord {
270
+ static let c = hasMany ( C . self)
271
+ }
272
+ struct C : TableRecord {
273
+ static let d = hasMany ( D . self)
274
+ }
275
+ struct D : TableRecord {
276
+ }
277
+
278
+ let dbQueue = try makeDatabaseQueue ( )
279
+ try dbQueue. write { db in
280
+ try db. create ( table: " b " ) { t in
281
+ t. autoIncrementedPrimaryKey ( " id " )
282
+ }
283
+ try db. create ( table: " a " ) { t in
284
+ t. autoIncrementedPrimaryKey ( " id " )
285
+ t. column ( " bId " ) . references ( " b " )
286
+ }
287
+ try db. create ( table: " c " ) { t in
288
+ t. autoIncrementedPrimaryKey ( " id " )
289
+ t. column ( " bId " ) . references ( " b " )
290
+ }
291
+ try db. create ( table: " d " ) { t in
292
+ t. autoIncrementedPrimaryKey ( " id " )
293
+ t. column ( " cId " ) . references ( " c " )
294
+ }
295
+
296
+ do {
297
+ let association = A . d
298
+ XCTFail ( " TODO: fix generated SQL " )
299
+ // TODO: remove the d from the subquery
300
+ try assertMatchSQL ( db, A . all ( ) . including ( required: association) , """
301
+ SELECT " a " .*, " d " .*
302
+ FROM " a "
303
+ JOIN " b " ON " b " . " id " = " a " . " bId "
304
+ JOIN " c " ON " c " . " id " = (
305
+ SELECT " c " . " id "
306
+ FROM " c "
307
+ JOIN " d " ON " d " . " cId " = " c " . " id "
308
+ WHERE " c " . " bId " = " b " . " id "
309
+ LIMIT 1)
310
+ JOIN " d " ON " d " . " cId " = " c " . " id "
311
+ """ )
312
+ // TODO: remove the d from the subquery
313
+ try assertMatchSQL ( db, A . all ( ) . including ( optional: association) , """
314
+ SELECT " a " .*, " d " .*
315
+ FROM " a "
316
+ LEFT JOIN " b " ON " b " . " id " = " a " . " bId "
317
+ LEFT JOIN " c " ON " c " . " id " = (
318
+ SELECT " c " . " id "
319
+ FROM " c "
320
+ LEFT JOIN " d " ON " d " . " cId " = " c " . " id "
321
+ WHERE " c " . " bId " = " b " . " id "
322
+ LIMIT 1)
323
+ LEFT JOIN " d " ON " d " . " cId " = " c " . " id "
324
+ """ )
325
+ // TODO: remove the d from the subquery
326
+ // TODO: include the d in the outer query
327
+ try assertMatchSQL ( db, A . all ( ) . joining ( required: association) , """
328
+ SELECT " a " .*
329
+ FROM " a "
330
+ JOIN " b " ON " b " . " id " = " a " . " bId "
331
+ JOIN " c " ON " c " . " id " = (
332
+ SELECT " c " . " id "
333
+ FROM " c "
334
+ JOIN " d " ON " d " . " cId " = " c " . " id "
335
+ WHERE " c " . " bId " = " b " . " id " LIMIT 1)
336
+ """ )
337
+ // TODO: remove the d from the subquery
338
+ // TODO: include the d in the outer query
339
+ try assertMatchSQL ( db, A . all ( ) . joining ( optional: association) , """
340
+ SELECT " a " .*
341
+ FROM " a "
342
+ LEFT JOIN " b " ON " b " . " id " = " a " . " bId "
343
+ LEFT JOIN " c " ON " c " . " id " = (
344
+ SELECT " c " . " id "
345
+ FROM " c "
346
+ LEFT JOIN " d " ON " d " . " cId " = " c " . " id "
347
+ WHERE " c " . " bId " = " b " . " id " LIMIT 1)
348
+ """ )
349
+ // TODO: implement
350
+ // Not implemented: loading multiple records associated to a `first` or `last` to-one association
351
+ // try assertMatchSQL(db, A().request(for: association), """
352
+ // SELECT ...
353
+ // """)
354
+ }
355
+ }
356
+ }
357
+
260
358
func testAssociationFilteredByOtherAssociation( ) throws {
261
359
struct Pet : TableRecord {
262
360
static let child = belongsTo ( Child . self)
@@ -389,11 +487,11 @@ class AssociationHasManyThroughFirstSQLTests: GRDBTestCase {
389
487
JOIN " child " " child1 " ON ( " child1 " . " id " = " pet " . " childId " ) AND (1)
390
488
JOIN " toy " ON " toy " . " childId " = " child1 " . " id "
391
489
JOIN " child " " child2 " ON " child2 " . " id " = (
392
- SELECT " child2 " . " id "
393
- FROM " child " " child2 "
394
- WHERE ( " child2 " . " id " = " pet " . " childId " ) AND (1 + 1) AND ( " child2 " . " parentId " = 1)
490
+ SELECT " child " . " id "
491
+ FROM " child "
492
+ WHERE ( " child " . " id " = " pet " . " childId " ) AND (1 + 1) AND ( " child " . " parentId " = 1)
395
493
LIMIT 1)
396
- LIMIT 1
494
+ LIMIT 1
397
495
""" )
398
496
}
399
497
do {
0 commit comments