@entity-access/entity-access 1.0.252 → 1.0.254

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/.vscode/launch.json +2 -1
  2. package/dist/common/symbols/symbols.d.ts +1 -0
  3. package/dist/common/symbols/symbols.d.ts.map +1 -1
  4. package/dist/common/symbols/symbols.js +1 -0
  5. package/dist/common/symbols/symbols.js.map +1 -1
  6. package/dist/decorators/ForeignKey.d.ts +8 -7
  7. package/dist/decorators/ForeignKey.d.ts.map +1 -1
  8. package/dist/decorators/ForeignKey.js +43 -8
  9. package/dist/decorators/ForeignKey.js.map +1 -1
  10. package/dist/decorators/IColumn.d.ts +6 -3
  11. package/dist/decorators/IColumn.d.ts.map +1 -1
  12. package/dist/decorators/Relate.d.ts.map +1 -1
  13. package/dist/decorators/Relate.js +8 -6
  14. package/dist/decorators/Relate.js.map +1 -1
  15. package/dist/entity-query/EntityType.d.ts +5 -1
  16. package/dist/entity-query/EntityType.d.ts.map +1 -1
  17. package/dist/entity-query/EntityType.js +61 -25
  18. package/dist/entity-query/EntityType.js.map +1 -1
  19. package/dist/migrations/postgres/PostgresAutomaticMigrations.js +1 -1
  20. package/dist/migrations/postgres/PostgresAutomaticMigrations.js.map +1 -1
  21. package/dist/migrations/postgres/PostgresMigrations.d.ts +1 -1
  22. package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js +1 -1
  23. package/dist/migrations/sql-server/SqlServerAutomaticMigrations.js.map +1 -1
  24. package/dist/migrations/sql-server/SqlServerMigrations.d.ts +1 -1
  25. package/dist/model/EntityModel.js +2 -2
  26. package/dist/model/EntityModel.js.map +1 -1
  27. package/dist/model/EntitySource.d.ts +6 -1
  28. package/dist/model/EntitySource.d.ts.map +1 -1
  29. package/dist/model/EntitySource.js.map +1 -1
  30. package/dist/model/SourceExpression.d.ts +1 -22
  31. package/dist/model/SourceExpression.d.ts.map +1 -1
  32. package/dist/model/SourceExpression.js +116 -98
  33. package/dist/model/SourceExpression.js.map +1 -1
  34. package/dist/model/changes/ChangeEntry.d.ts.map +1 -1
  35. package/dist/model/changes/ChangeEntry.js +62 -25
  36. package/dist/model/changes/ChangeEntry.js.map +1 -1
  37. package/dist/model/changes/ChangeSet.d.ts +2 -1
  38. package/dist/model/changes/ChangeSet.d.ts.map +1 -1
  39. package/dist/model/changes/ChangeSet.js +4 -3
  40. package/dist/model/changes/ChangeSet.js.map +1 -1
  41. package/dist/model/identity/IdentityMap.d.ts +23 -0
  42. package/dist/model/identity/IdentityMap.d.ts.map +1 -0
  43. package/dist/model/identity/IdentityMap.js +113 -0
  44. package/dist/model/identity/IdentityMap.js.map +1 -0
  45. package/dist/model/identity/RelationMapper.d.ts +2 -3
  46. package/dist/model/identity/RelationMapper.d.ts.map +1 -1
  47. package/dist/model/identity/RelationMapper.js +60 -27
  48. package/dist/model/identity/RelationMapper.js.map +1 -1
  49. package/dist/model/identity/SearchIndex.d.ts +17 -0
  50. package/dist/model/identity/SearchIndex.d.ts.map +1 -0
  51. package/dist/model/identity/SearchIndex.js +109 -0
  52. package/dist/model/identity/SearchIndex.js.map +1 -0
  53. package/dist/model/verification/VerificationSession.d.ts +1 -1
  54. package/dist/model/verification/VerificationSession.d.ts.map +1 -1
  55. package/dist/model/verification/VerificationSession.js +18 -16
  56. package/dist/model/verification/VerificationSession.js.map +1 -1
  57. package/dist/query/ast/ExpressionToSql.d.ts.map +1 -1
  58. package/dist/query/ast/ExpressionToSql.js +74 -52
  59. package/dist/query/ast/ExpressionToSql.js.map +1 -1
  60. package/dist/query/expander/QueryExpander.d.ts.map +1 -1
  61. package/dist/query/expander/QueryExpander.js +41 -10
  62. package/dist/query/expander/QueryExpander.js.map +1 -1
  63. package/dist/tests/db-tests/tests/multi-fk-tests.d.ts +3 -0
  64. package/dist/tests/db-tests/tests/multi-fk-tests.d.ts.map +1 -0
  65. package/dist/tests/db-tests/tests/multi-fk-tests.js +38 -0
  66. package/dist/tests/db-tests/tests/multi-fk-tests.js.map +1 -0
  67. package/dist/tests/expressions/left-joins/child-joins.js +7 -7
  68. package/dist/tests/model/ShoppingContext.d.ts +9 -0
  69. package/dist/tests/model/ShoppingContext.d.ts.map +1 -1
  70. package/dist/tests/model/ShoppingContext.js +34 -0
  71. package/dist/tests/model/ShoppingContext.js.map +1 -1
  72. package/dist/tests/security/tests/include-items.d.ts.map +1 -1
  73. package/dist/tests/security/tests/include-items.js +1 -0
  74. package/dist/tests/security/tests/include-items.js.map +1 -1
  75. package/dist/tsconfig.tsbuildinfo +1 -1
  76. package/package.json +1 -1
  77. package/src/common/symbols/symbols.ts +2 -1
  78. package/src/decorators/ForeignKey.ts +66 -28
  79. package/src/decorators/IColumn.ts +4 -3
  80. package/src/decorators/Relate.ts +8 -6
  81. package/src/entity-query/EntityType.ts +64 -26
  82. package/src/migrations/postgres/PostgresAutomaticMigrations.ts +1 -1
  83. package/src/migrations/sql-server/SqlServerAutomaticMigrations.ts +1 -1
  84. package/src/model/EntityModel.ts +2 -2
  85. package/src/model/EntitySource.ts +6 -1
  86. package/src/model/SourceExpression.ts +132 -132
  87. package/src/model/changes/ChangeEntry.ts +68 -25
  88. package/src/model/changes/ChangeSet.ts +4 -3
  89. package/src/model/identity/IdentityMap.ts +126 -0
  90. package/src/model/identity/RelationMapper.ts +71 -27
  91. package/src/model/identity/SearchIndex.ts +120 -0
  92. package/src/model/verification/VerificationSession.ts +19 -16
  93. package/src/query/ast/ExpressionToSql.ts +77 -61
  94. package/src/query/expander/QueryExpander.ts +52 -28
  95. package/src/tests/db-tests/tests/multi-fk-tests.ts +46 -0
  96. package/src/tests/expressions/left-joins/child-joins.ts +7 -7
  97. package/src/tests/model/ShoppingContext.ts +32 -0
  98. package/src/tests/security/tests/include-items.ts +1 -0
@@ -1,3 +1,4 @@
1
+ import EntityAccessError from "../../common/EntityAccessError.js";
1
2
  import QueryCompiler from "../../compiler/QueryCompiler.js";
2
3
  import EntityType, { IEntityProperty } from "../../entity-query/EntityType.js";
3
4
  import EntityQuery from "../../model/EntityQuery.js";
@@ -225,33 +226,27 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
225
226
 
226
227
  this.scope.create({ parameter: select.sourceParameter, model: relatedModel, selectStatement: select });
227
228
  select[filteredSymbol] = true;
228
- const targetKey = MemberExpression.create({
229
- target: parameter,
230
- property: Identifier.create({
231
- value: targetType.keys[0].columnName
232
- })
233
- });
234
-
235
- const relatedKey = MemberExpression.create({
236
- target: select.sourceParameter,
237
- property: Identifier.create({
238
- value: relation.relation.fkColumn.columnName
239
- })
240
- });
241
-
242
-
243
- const join = Expression.equal(targetKey, relatedKey);
244
229
 
245
230
  let where = select.where;
246
231
 
247
- if (where) {
248
- where = BinaryExpression.create({
249
- left: select.where,
250
- operator: "AND",
251
- right: join
232
+ for (const { fkColumn, relatedKeyColumn } of relation.relation.fkMap) {
233
+ const targetKey = MemberExpression.create({
234
+ target: parameter,
235
+ property: Identifier.create({
236
+ value: relatedKeyColumn.columnName
237
+ })
252
238
  });
253
- } else {
254
- where = join;
239
+
240
+ const relatedKey = MemberExpression.create({
241
+ target: select.sourceParameter,
242
+ property: Identifier.create({
243
+ value: fkColumn.columnName
244
+ })
245
+ });
246
+ const join = Expression.equal(targetKey, relatedKey);
247
+ where = where
248
+ ? Expression.logicalAnd(where, join)
249
+ : join;
255
250
  }
256
251
 
257
252
  select.where = where;
@@ -282,36 +277,33 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
282
277
  this.scope.alias(param1, select.sourceParameter, select);
283
278
  select.sourceParameter = param1;
284
279
  select[filteredSymbol] = true;
285
- const targetKey = MemberExpression.create({
286
- target: parameter,
287
- property: Identifier.create({
288
- value: targetType.keys[0].columnName
289
- })
290
- });
291
-
292
- const relatedKey = MemberExpression.create({
293
- target: param1,
294
- property: Identifier.create({
295
- value: relation.relation.fkColumn.columnName
296
- })
297
- });
298
280
 
281
+ let where = select.where;
282
+ where = where
283
+ ? Expression.logicalAnd(where, body.body)
284
+ : body.body;
299
285
 
300
- const join = Expression.logicalAnd(
301
- Expression.equal(targetKey, relatedKey),
302
- body.body
303
- );
286
+ for (const { fkColumn, relatedKeyColumn } of relation.relation.relatedRelation.fkMap) {
304
287
 
305
- let where = select.where;
288
+ const targetKey = MemberExpression.create({
289
+ target: parameter,
290
+ property: Identifier.create({
291
+ value: relatedKeyColumn.columnName
292
+ })
293
+ });
306
294
 
307
- if (where) {
308
- where = BinaryExpression.create({
309
- left: select.where,
310
- operator: "AND",
311
- right: join
295
+ const relatedKey = MemberExpression.create({
296
+ target: param1,
297
+ property: Identifier.create({
298
+ value: fkColumn.columnName
299
+ })
312
300
  });
313
- } else {
314
- where = join;
301
+
302
+ const join = Expression.equal(targetKey, relatedKey);
303
+
304
+ where = where
305
+ ? Expression.logicalAnd(where, join)
306
+ : join;
315
307
  }
316
308
 
317
309
  select.where = where;
@@ -723,16 +715,18 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
723
715
  }
724
716
  if (relation) {
725
717
 
726
- const { fkColumn } = relation;
727
-
728
718
  if (!relation.isCollection) {
729
719
 
730
- let columnName = fkColumn.columnName;
731
- // for inverse relation, we need to
732
- // use primary key of current model
733
- if (relation.isInverseRelation) {
734
- columnName = peModel.keys[0].columnName;
735
- }
720
+ // let columnName = fkColumn.columnName;
721
+ // // for inverse relation, we need to
722
+ // // use primary key of current model
723
+ // if (relation.isInverseRelation) {
724
+ // columnName = peModel.keys[0].columnName;
725
+ // }
726
+
727
+ const fkMap = relation.fkMap ?? relation.relatedRelation.fkMap;
728
+
729
+ const isNullable = fkMap.some(({ fkColumn }) => fkColumn.nullable);
736
730
 
737
731
  const select = scope?.selectStatement ?? this.source?.selectStatement;
738
732
  if (select) {
@@ -743,20 +737,42 @@ export default class ExpressionToSql extends Visitor<ITextQuery> {
743
737
  this.scope.create({ parameter: join.as as ParameterExpression, model: join.model, selectStatement: select });
744
738
  return join.as;
745
739
  }
746
- const joinType = select.preferLeftJoins ? "LEFT" : (fkColumn.nullable ? "LEFT" : "INNER");
740
+ const joinType = select.preferLeftJoins ? "LEFT" : (isNullable ? "LEFT" : "INNER");
747
741
  const joinParameter = ParameterExpression.create({
748
742
  name: relation.relatedEntity.name[0],
749
743
  model: relation.relatedEntity
750
744
  });
745
+ let where: Expression;
746
+ for (const {fkColumn, relatedKeyColumn} of fkMap) {
747
+ let peColumn;
748
+ let joinColumn;
749
+ if (fkColumn.entityType === pe.model) {
750
+ peColumn = fkColumn;
751
+ } else if (relatedKeyColumn.entityType === pe.model) {
752
+ peColumn = relatedKeyColumn;
753
+ } else {
754
+ throw new EntityAccessError(`Invalid configuration`);
755
+ }
756
+ if (fkColumn.entityType === joinParameter.model) {
757
+ joinColumn = fkColumn;
758
+ } else if (relatedKeyColumn.entityType === joinParameter.model) {
759
+ joinColumn = relatedKeyColumn;
760
+ } else {
761
+ throw new EntityAccessError(`Invalid configuration`);
762
+ }
763
+ const joinOn = Expression.equal(
764
+ Expression.member(pe, peColumn.columnName),
765
+ Expression.member(joinParameter, joinColumn.columnName));
766
+ where = where
767
+ ? Expression.logicalAnd(where, joinOn)
768
+ : joinOn;
769
+ }
751
770
  join = JoinExpression.create({
752
771
  as: joinParameter,
753
772
  joinType,
754
773
  model: joinParameter.model,
755
774
  source: Expression.identifier(relation.relatedEntity.name),
756
- where: Expression.equal(
757
- Expression.member(pe, columnName),
758
- Expression.member(joinParameter, relation.relatedEntity.keys[0].columnName)
759
- )
775
+ where
760
776
  });
761
777
  select.joins.push(join);
762
778
  this.scope.create({ parameter: joinParameter, model: relation.relatedEntity, selectStatement: select});
@@ -98,7 +98,7 @@ export class QueryExpander {
98
98
  // let where: Expression;
99
99
  // let joinWhere: Expression;
100
100
 
101
- const fk = relation.fkColumn ?? relation.relatedRelation.fkColumn;
101
+ const fk = relation.fkMap ?? relation.relatedRelation.fkMap;
102
102
 
103
103
  key += "." + relation.name;
104
104
 
@@ -107,15 +107,17 @@ export class QueryExpander {
107
107
  return relationSet;
108
108
  }
109
109
 
110
+ let where: Expression;
111
+
110
112
  if(relation.isInverseRelation) {
111
113
 
112
- const keyColumn = model.keys[0].columnName;
113
- let columnName = fk.columnName;
114
- // for inverse relation, we need to
115
- // use primary key of current model
116
- if (!relation.isCollection) {
117
- columnName = select.model.keys[0].columnName;
118
- }
114
+ // const keyColumn = model.keys[0].columnName;
115
+ // let columnName = fk.columnName;
116
+ // // for inverse relation, we need to
117
+ // // use primary key of current model
118
+ // if (!relation.isCollection) {
119
+ // columnName = select.model.keys[0].columnName;
120
+ // }
119
121
 
120
122
 
121
123
  const joins = (select.joins ??= []);
@@ -124,21 +126,32 @@ export class QueryExpander {
124
126
  // This join has to be INNER JOIN as we are only interested
125
127
  // in the results that matches parent query exactly
126
128
 
129
+ for (const { fkColumn, relatedKeyColumn } of relation.relatedRelation.fkMap) {
130
+ const joinColumn = fkColumn.entityType === joinParameter.model ? fkColumn : relatedKeyColumn;
131
+ const relatedColumn = relatedKeyColumn.entityType === select.sourceParameter.model ? relatedKeyColumn : fkColumn;
132
+ const joinOn = Expression.equal(
133
+ Expression.member(joinParameter, Expression.identifier(joinColumn.columnName)),
134
+ Expression.member(select.sourceParameter, Expression.identifier(relatedColumn.columnName))
135
+ );
136
+ where = where ? Expression.logicalAnd(where, joinOn) : joinOn;
137
+ }
138
+
127
139
  joins.push(JoinExpression.create({
128
140
  joinType: "INNER",
129
141
  source: { ... parent },
130
142
  as: joinParameter,
131
143
  model: parent.model,
132
- where: Expression.equal(
133
- Expression.member(
134
- joinParameter,
135
- Expression.identifier(keyColumn)
136
- ),
137
- Expression.member(
138
- select.sourceParameter,
139
- Expression.identifier(columnName)
140
- )
141
- )
144
+ where
145
+ // where: Expression.equal(
146
+ // Expression.member(
147
+ // joinParameter,
148
+ // Expression.identifier(keyColumn)
149
+ // ),
150
+ // Expression.member(
151
+ // select.sourceParameter,
152
+ // Expression.identifier(columnName)
153
+ // )
154
+ // )
142
155
  }));
143
156
 
144
157
  // if (parent.where) {
@@ -192,22 +205,33 @@ export class QueryExpander {
192
205
  // This join has to be INNER JOIN as we are only interested
193
206
  // in the results that matches parent query exactly
194
207
 
208
+ for (const { fkColumn, relatedKeyColumn } of relation.fkMap) {
209
+ const joinOn = Expression.equal(
210
+ Expression.member(selectJoinParameter,
211
+ Expression.identifier(fkColumn.columnName)),
212
+ Expression.member(select.sourceParameter,
213
+ Expression.identifier(relatedKeyColumn.columnName))
214
+ );
215
+ where = where ? Expression.logicalAnd(where, joinOn) : joinOn;
216
+ }
217
+
195
218
  selectJoins.push(JoinExpression.create({
196
219
  joinType: "INNER",
197
220
  source: { ... parent },
198
221
  as: selectJoinParameter,
199
222
  model: parent.model,
223
+ where
200
224
  // model,
201
- where: Expression.equal(
202
- Expression.member(
203
- selectJoinParameter,
204
- Expression.identifier(fk.columnName)
205
- ),
206
- Expression.member(
207
- select.sourceParameter,
208
- Expression.identifier(relation.relatedEntity.keys[0].columnName)
209
- )
210
- )
225
+ // where: Expression.equal(
226
+ // Expression.member(
227
+ // selectJoinParameter,
228
+ // Expression.identifier(fk.columnName)
229
+ // ),
230
+ // Expression.member(
231
+ // select.sourceParameter,
232
+ // Expression.identifier(relation.relatedEntity.keys[0].columnName)
233
+ // )
234
+ // )
211
235
  }));
212
236
 
213
237
  this.include.push(select);
@@ -0,0 +1,46 @@
1
+ import assert from "assert";
2
+ import { TestConfig } from "../../TestConfig.js";
3
+ import { createContext } from "../../model/createContext.js";
4
+
5
+ export default async function(this: TestConfig) {
6
+
7
+ if (!this.db) {
8
+ return;
9
+ }
10
+
11
+ const context = await createContext(this.driver);
12
+
13
+ const { userID } = await context.users.asQuery().first();
14
+ const { categoryID } = await context.categories.asQuery().first();
15
+
16
+ await context.userCategories.saveDirect({
17
+ mode: "insert",
18
+ changes: {
19
+ userID,
20
+ categoryID
21
+ }
22
+ });
23
+
24
+ await context.userCategoryTags.saveDirect({
25
+ mode: "insert",
26
+ changes: {
27
+ categoryID,
28
+ userID,
29
+ tag: "A"
30
+ }
31
+ });
32
+ await context.userCategoryTags.saveDirect({
33
+ mode: "insert",
34
+ changes: {
35
+ categoryID,
36
+ userID,
37
+ tag: "B"
38
+ }
39
+ });
40
+
41
+ const first = await context.userCategories.asQuery()
42
+ .include((x) => x.tags)
43
+ .first();
44
+
45
+ assert.notEqual(void 0, first.tags);
46
+ }
@@ -14,7 +14,7 @@ FROM products AS p1
14
14
  WHERE EXISTS (SELECT
15
15
  1
16
16
  FROM order_items AS o
17
- WHERE (p1.product_id = o.product_id) AND (o.product_id = $1))`;
17
+ WHERE (o.product_id = $1) AND (p1.product_id = o.product_id))`;
18
18
 
19
19
  const sql2 = `SELECT
20
20
  p1.product_id,
@@ -26,10 +26,10 @@ FROM products AS p1
26
26
  WHERE EXISTS (SELECT
27
27
  1
28
28
  FROM order_items AS o
29
- WHERE (p1.product_id = o.product_id) AND (o.product_id = $1)) AND EXISTS (SELECT
29
+ WHERE (o.product_id = $1) AND (p1.product_id = o.product_id)) AND EXISTS (SELECT
30
30
  1
31
31
  FROM order_items AS o1
32
- WHERE (p1.product_id = o1.product_id) AND (o1.amount > $2))`;
32
+ WHERE (o1.amount > $2) AND (p1.product_id = o1.product_id))`;
33
33
 
34
34
  const sql3 = `SELECT
35
35
  p1.product_id,
@@ -41,11 +41,11 @@ FROM products AS p1
41
41
  WHERE EXISTS (SELECT
42
42
  1
43
43
  FROM order_items AS o
44
- WHERE (p1.product_id = o.product_id) AND (o.product_id = $1)) AND EXISTS (SELECT
44
+ WHERE (o.product_id = $1) AND (p1.product_id = o.product_id)) AND EXISTS (SELECT
45
45
  1
46
46
  FROM order_items AS o1
47
47
  INNER JOIN orders AS o2 ON o1.order_id = o2.order_id
48
- WHERE (p1.product_id = o1.product_id) AND (o2.order_date > $2))`;
48
+ WHERE (o2.order_date > $2) AND (p1.product_id = o1.product_id))`;
49
49
 
50
50
  const productJoin = `SELECT
51
51
  p1.product_id,
@@ -77,10 +77,10 @@ p1.product_description
77
77
  FROM products AS p1
78
78
  WHERE EXISTS
79
79
  (SELECT 1 FROM order_items AS o
80
- WHERE (p1.product_id = o.product_id) AND (o.product_id = $1)) AND
80
+ WHERE (o.product_id = $1) AND (p1.product_id = o.product_id)) AND
81
81
  NOT (EXISTS (SELECT 1 FROM order_items AS o1
82
82
  INNER JOIN orders AS o2 ON o1.order_id = o2.order_id
83
- WHERE (p1.product_id = o1.product_id) AND (o2.order_date > $2)))
83
+ WHERE (o2.order_date > $2) AND (p1.product_id = o1.product_id)))
84
84
  `;
85
85
 
86
86
  export default function() {
@@ -6,6 +6,7 @@ import Index from "../../decorators/Index.js";
6
6
  import DateTime from "../../types/DateTime.js";
7
7
  import { UserFile } from "./UseFile.js";
8
8
  import Sql from "../../sql/Sql.js";
9
+ import MultiForeignKeys from "../../decorators/ForeignKey.js";
9
10
 
10
11
  export const statusPublished = "published";
11
12
 
@@ -34,6 +35,8 @@ export class ShoppingContext extends EntityContext {
34
35
  public userFiles = this.model.register(UserFile);
35
36
 
36
37
  public emailAddresses = this.model.register(EmailAddress);
38
+
39
+ public userCategoryTags = this.model.register(UserCategoryTag);
37
40
  }
38
41
 
39
42
  @Table("Users")
@@ -191,6 +194,35 @@ export class UserCategory {
191
194
  public user: User;
192
195
 
193
196
  public category: Category;
197
+
198
+ public tags: UserCategoryTag[];
199
+ }
200
+
201
+ @Table("UserCategoryTags")
202
+ export class UserCategoryTag {
203
+
204
+ @Column({ key: true, dataType: "BigInt", generated: "identity"})
205
+ tagID: number;
206
+
207
+ @Column({ dataType: "Char", length: 200 })
208
+ tag: string;
209
+
210
+ @Column({ dataType: "BigInt"})
211
+ public userID: number;
212
+
213
+ @Column({ dataType: "Char", length: 200 })
214
+ public categoryID: string;
215
+
216
+ @MultiForeignKeys(UserCategory, {
217
+ inverseProperty: (x) => x.tags,
218
+ foreignKeys: [
219
+ { foreignKey: (x) => x.userID, key: (x) => x.userID },
220
+ { foreignKey: (x) => x.categoryID, key: (x) => x.categoryID}
221
+ ]
222
+ }
223
+ )
224
+ public userCategory: UserCategory;
225
+
194
226
  }
195
227
 
196
228
  @Table("Products")
@@ -15,5 +15,6 @@ export default async function (this: TestConfig) {
15
15
  .first();
16
16
 
17
17
  assert.notEqual(null, order);
18
+ assert.notEqual(undefined, order.orderItems);
18
19
 
19
20
  }