@casekit/orm 0.0.1-alpha.7 → 0.0.1-alpha.9

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 (245) hide show
  1. package/lib/migrate/commands/implode.js +1 -1
  2. package/lib/migrate/commands/implode.js.map +1 -1
  3. package/lib/migrate/sql/createTableSql.test.js +1 -0
  4. package/lib/migrate/sql/createTableSql.test.js.map +1 -1
  5. package/lib/orm.d.ts.map +1 -1
  6. package/lib/orm.js +4 -2
  7. package/lib/orm.js.map +1 -1
  8. package/lib/queries/clauses/ReturningClause.d.ts +2 -3
  9. package/lib/queries/clauses/ReturningClause.d.ts.map +1 -1
  10. package/lib/queries/clauses/SelectClause.d.ts +2 -3
  11. package/lib/queries/clauses/SelectClause.d.ts.map +1 -1
  12. package/lib/queries/clauses/WhereClause.d.ts +1 -1
  13. package/lib/queries/clauses/WhereClause.d.ts.map +1 -1
  14. package/lib/queries/clauses/helpers/OptionalColumn.d.ts +4 -5
  15. package/lib/queries/clauses/helpers/OptionalColumn.d.ts.map +1 -1
  16. package/lib/queries/clauses/helpers/OptionalParams.d.ts +2 -2
  17. package/lib/queries/clauses/helpers/OptionalParams.d.ts.map +1 -1
  18. package/lib/queries/clauses/helpers/RequiredColumn.d.ts +2 -3
  19. package/lib/queries/clauses/helpers/RequiredColumn.d.ts.map +1 -1
  20. package/lib/queries/clauses/helpers/RequiredParams.d.ts +2 -2
  21. package/lib/queries/clauses/helpers/RequiredParams.d.ts.map +1 -1
  22. package/lib/queries/clauses/where/buildWhereClauses.d.ts +1 -1
  23. package/lib/queries/clauses/where/buildWhereClauses.d.ts.map +1 -1
  24. package/lib/queries/clauses/where/buildWhereClauses.js.map +1 -1
  25. package/lib/queries/clauses/where/buildWhereClauses.test.js +1 -1
  26. package/lib/queries/clauses/where/buildWhereClauses.test.js.map +1 -1
  27. package/lib/queries/clauses/where/types/WhereClauseValue.d.ts +1 -1
  28. package/lib/queries/clauses/where/types/WhereClauseValue.d.ts.map +1 -1
  29. package/lib/queries/count/buildCount.d.ts.map +1 -1
  30. package/lib/queries/count/buildCount.js +33 -29
  31. package/lib/queries/count/buildCount.js.map +1 -1
  32. package/lib/queries/count/countToSql.d.ts.map +1 -1
  33. package/lib/queries/count/countToSql.js +12 -17
  34. package/lib/queries/count/countToSql.js.map +1 -1
  35. package/lib/queries/count/types/CountBuilder.d.ts +12 -4
  36. package/lib/queries/count/types/CountBuilder.d.ts.map +1 -1
  37. package/lib/queries/count.d.ts.map +1 -1
  38. package/lib/queries/count.js +3 -1
  39. package/lib/queries/count.js.map +1 -1
  40. package/lib/queries/create/buildCreate.d.ts +1 -1
  41. package/lib/queries/create/buildCreate.d.ts.map +1 -1
  42. package/lib/queries/create/buildCreate.js +1 -1
  43. package/lib/queries/create/buildCreate.js.map +1 -1
  44. package/lib/queries/create/createResultSchema.d.ts.map +1 -1
  45. package/lib/queries/create/createResultSchema.js +3 -1
  46. package/lib/queries/create/createResultSchema.js.map +1 -1
  47. package/lib/queries/create/createToSql.d.ts.map +1 -1
  48. package/lib/queries/create/createToSql.js +2 -2
  49. package/lib/queries/create/createToSql.js.map +1 -1
  50. package/lib/queries/create/types/CreateManyParams.d.ts +1 -1
  51. package/lib/queries/create/types/CreateManyParams.d.ts.map +1 -1
  52. package/lib/queries/create/types/CreateManyResult.d.ts +1 -1
  53. package/lib/queries/create/types/CreateManyResult.d.ts.map +1 -1
  54. package/lib/queries/create/types/CreateOneParams.d.ts +1 -1
  55. package/lib/queries/create/types/CreateOneParams.d.ts.map +1 -1
  56. package/lib/queries/create/types/CreateOneResult.d.ts +1 -1
  57. package/lib/queries/create/types/CreateOneResult.d.ts.map +1 -1
  58. package/lib/queries/createMany.d.ts.map +1 -1
  59. package/lib/queries/createMany.js +3 -1
  60. package/lib/queries/createMany.js.map +1 -1
  61. package/lib/queries/delete/buildDelete.d.ts +1 -1
  62. package/lib/queries/delete/buildDelete.d.ts.map +1 -1
  63. package/lib/queries/delete/buildDelete.js +1 -1
  64. package/lib/queries/delete/buildDelete.js.map +1 -1
  65. package/lib/queries/delete/deleteResultSchema.d.ts.map +1 -1
  66. package/lib/queries/delete/deleteResultSchema.js +3 -1
  67. package/lib/queries/delete/deleteResultSchema.js.map +1 -1
  68. package/lib/queries/delete/deleteToSql.js +1 -1
  69. package/lib/queries/delete/deleteToSql.js.map +1 -1
  70. package/lib/queries/delete/types/DeleteManyResult.d.ts +1 -1
  71. package/lib/queries/delete/types/DeleteManyResult.d.ts.map +1 -1
  72. package/lib/queries/delete/types/DeleteOneResult.d.ts +1 -1
  73. package/lib/queries/delete/types/DeleteOneResult.d.ts.map +1 -1
  74. package/lib/queries/delete/types/DeleteParams.d.ts +1 -1
  75. package/lib/queries/delete/types/DeleteParams.d.ts.map +1 -1
  76. package/lib/queries/deleteMany.d.ts.map +1 -1
  77. package/lib/queries/deleteMany.js +3 -1
  78. package/lib/queries/deleteMany.js.map +1 -1
  79. package/lib/queries/find/buildFind.d.ts.map +1 -1
  80. package/lib/queries/find/buildFind.js +34 -30
  81. package/lib/queries/find/buildFind.js.map +1 -1
  82. package/lib/queries/find/findResultSchema.d.ts.map +1 -1
  83. package/lib/queries/find/findResultSchema.js +9 -2
  84. package/lib/queries/find/findResultSchema.js.map +1 -1
  85. package/lib/queries/find/findToSql.d.ts.map +1 -1
  86. package/lib/queries/find/findToSql.js +12 -17
  87. package/lib/queries/find/findToSql.js.map +1 -1
  88. package/lib/queries/find/tests/findMany.nullable-relations.test.d.ts +2 -0
  89. package/lib/queries/find/tests/findMany.nullable-relations.test.d.ts.map +1 -0
  90. package/lib/queries/find/tests/findMany.nullable-relations.test.js +118 -0
  91. package/lib/queries/find/tests/findMany.nullable-relations.test.js.map +1 -0
  92. package/lib/queries/find/types/FindBuilder.d.ts +12 -4
  93. package/lib/queries/find/types/FindBuilder.d.ts.map +1 -1
  94. package/lib/queries/find/types/FindManyParams.d.ts +2 -2
  95. package/lib/queries/find/types/FindManyParams.d.ts.map +1 -1
  96. package/lib/queries/find/types/FindOneParams.d.ts +1 -1
  97. package/lib/queries/find/types/FindOneParams.d.ts.map +1 -1
  98. package/lib/queries/findMany.d.ts.map +1 -1
  99. package/lib/queries/findMany.js +17 -9
  100. package/lib/queries/findMany.js.map +1 -1
  101. package/lib/queries/update/buildUpdate.d.ts +1 -1
  102. package/lib/queries/update/buildUpdate.d.ts.map +1 -1
  103. package/lib/queries/update/buildUpdate.js +1 -1
  104. package/lib/queries/update/buildUpdate.js.map +1 -1
  105. package/lib/queries/update/types/UpdateManyResult.d.ts +1 -1
  106. package/lib/queries/update/types/UpdateManyResult.d.ts.map +1 -1
  107. package/lib/queries/update/types/UpdateOneResult.d.ts +1 -1
  108. package/lib/queries/update/types/UpdateOneResult.d.ts.map +1 -1
  109. package/lib/queries/update/types/UpdateParams.d.ts +1 -1
  110. package/lib/queries/update/types/UpdateParams.d.ts.map +1 -1
  111. package/lib/queries/update/types/UpdateValues.d.ts +1 -1
  112. package/lib/queries/update/types/UpdateValues.d.ts.map +1 -1
  113. package/lib/queries/update/updateResultSchema.d.ts.map +1 -1
  114. package/lib/queries/update/updateResultSchema.js +3 -1
  115. package/lib/queries/update/updateResultSchema.js.map +1 -1
  116. package/lib/queries/update/updateToSql.js +1 -1
  117. package/lib/queries/update/updateToSql.js.map +1 -1
  118. package/lib/queries/updateMany.d.ts.map +1 -1
  119. package/lib/queries/updateMany.js +3 -1
  120. package/lib/queries/updateMany.js.map +1 -1
  121. package/lib/queries/util/rowToObject.d.ts.map +1 -1
  122. package/lib/queries/util/rowToObject.js +1 -1
  123. package/lib/queries/util/rowToObject.js.map +1 -1
  124. package/lib/schema/types/base/BaseRelation.d.ts +1 -0
  125. package/lib/schema/types/base/BaseRelation.d.ts.map +1 -1
  126. package/lib/schema/types/helpers/ColumnName.d.ts +2 -3
  127. package/lib/schema/types/helpers/ColumnName.d.ts.map +1 -1
  128. package/lib/schema/types/helpers/ColumnType.d.ts +2 -2
  129. package/lib/schema/types/helpers/ColumnType.d.ts.map +1 -1
  130. package/lib/schema/types/helpers/Columns.d.ts +2 -3
  131. package/lib/schema/types/helpers/Columns.d.ts.map +1 -1
  132. package/lib/schema/types/helpers/HasDefault.d.ts +2 -3
  133. package/lib/schema/types/helpers/HasDefault.d.ts.map +1 -1
  134. package/lib/schema/types/helpers/IsNullable.d.ts +2 -3
  135. package/lib/schema/types/helpers/IsNullable.d.ts.map +1 -1
  136. package/lib/schema/types/helpers/IsProvided.d.ts +2 -3
  137. package/lib/schema/types/helpers/IsProvided.d.ts.map +1 -1
  138. package/lib/schema/types/helpers/IsSerial.d.ts +2 -3
  139. package/lib/schema/types/helpers/IsSerial.d.ts.map +1 -1
  140. package/lib/schema/types/loose/LooseRelationDefinition.d.ts +1 -0
  141. package/lib/schema/types/loose/LooseRelationDefinition.d.ts.map +1 -1
  142. package/lib/schema/types/relations/ManyToManyRelation.d.ts +2 -2
  143. package/lib/schema/types/relations/ManyToManyRelation.d.ts.map +1 -1
  144. package/lib/schema/types/relations/ManyToOneRelation.d.ts +1 -1
  145. package/lib/schema/types/relations/ManyToOneRelation.d.ts.map +1 -1
  146. package/lib/schema/types/relations/OneToManyRelation.d.ts +2 -1
  147. package/lib/schema/types/relations/OneToManyRelation.d.ts.map +1 -1
  148. package/lib/test/db/index.d.ts +40 -0
  149. package/lib/test/db/index.d.ts.map +1 -1
  150. package/lib/test/db/models/post.model.d.ts +9 -0
  151. package/lib/test/db/models/post.model.d.ts.map +1 -1
  152. package/lib/test/db/models/post.model.js +6 -0
  153. package/lib/test/db/models/post.model.js.map +1 -1
  154. package/lib/test/db/models/post.relations.d.ts +6 -0
  155. package/lib/test/db/models/post.relations.d.ts.map +1 -1
  156. package/lib/test/db/models/post.relations.js +6 -0
  157. package/lib/test/db/models/post.relations.js.map +1 -1
  158. package/lib/test/db/models/user.model.d.ts +9 -0
  159. package/lib/test/db/models/user.model.d.ts.map +1 -1
  160. package/lib/test/db/models/user.model.js +6 -0
  161. package/lib/test/db/models/user.model.js.map +1 -1
  162. package/lib/test/db/models/user.relations.d.ts +16 -0
  163. package/lib/test/db/models/user.relations.d.ts.map +1 -1
  164. package/lib/test/db/models/user.relations.js +16 -0
  165. package/lib/test/db/models/user.relations.js.map +1 -1
  166. package/lib/test/db/models.d.ts +18 -0
  167. package/lib/test/db/models.d.ts.map +1 -1
  168. package/lib/test/db/relations.d.ts +22 -0
  169. package/lib/test/db/relations.d.ts.map +1 -1
  170. package/lib/test/seed/index.d.ts +40 -0
  171. package/lib/test/seed/index.d.ts.map +1 -1
  172. package/lib/types/ModelType.d.ts +10 -3
  173. package/lib/types/ModelType.d.ts.map +1 -1
  174. package/package.json +1 -1
  175. package/src/migrate/commands/implode.ts +1 -1
  176. package/src/migrate/sql/createTableSql.test.ts +1 -0
  177. package/src/orm.ts +5 -2
  178. package/src/queries/clauses/ReturningClause.ts +4 -6
  179. package/src/queries/clauses/SelectClause.ts +4 -6
  180. package/src/queries/clauses/WhereClause.ts +1 -1
  181. package/src/queries/clauses/helpers/OptionalColumn.ts +7 -11
  182. package/src/queries/clauses/helpers/OptionalParams.ts +2 -2
  183. package/src/queries/clauses/helpers/RequiredColumn.ts +5 -6
  184. package/src/queries/clauses/helpers/RequiredParams.ts +2 -2
  185. package/src/queries/clauses/where/buildWhereClauses.test.ts +1 -1
  186. package/src/queries/clauses/where/buildWhereClauses.ts +1 -1
  187. package/src/queries/clauses/where/types/WhereClauseValue.ts +1 -1
  188. package/src/queries/count/buildCount.ts +39 -33
  189. package/src/queries/count/countToSql.ts +27 -32
  190. package/src/queries/count/types/CountBuilder.ts +23 -6
  191. package/src/queries/count.ts +4 -1
  192. package/src/queries/create/buildCreate.ts +2 -2
  193. package/src/queries/create/createResultSchema.ts +3 -1
  194. package/src/queries/create/createToSql.ts +6 -2
  195. package/src/queries/create/types/CreateManyParams.ts +1 -1
  196. package/src/queries/create/types/CreateManyResult.ts +1 -1
  197. package/src/queries/create/types/CreateOneParams.ts +1 -1
  198. package/src/queries/create/types/CreateOneResult.ts +1 -1
  199. package/src/queries/createMany.ts +4 -1
  200. package/src/queries/delete/buildDelete.ts +2 -2
  201. package/src/queries/delete/deleteResultSchema.ts +3 -1
  202. package/src/queries/delete/deleteToSql.ts +1 -1
  203. package/src/queries/delete/types/DeleteManyResult.ts +1 -1
  204. package/src/queries/delete/types/DeleteOneResult.ts +1 -1
  205. package/src/queries/delete/types/DeleteParams.ts +1 -1
  206. package/src/queries/deleteMany.ts +4 -1
  207. package/src/queries/find/buildFind.ts +40 -34
  208. package/src/queries/find/findResultSchema.ts +9 -2
  209. package/src/queries/find/findToSql.ts +27 -32
  210. package/src/queries/find/tests/findMany.nullable-relations.test.ts +127 -0
  211. package/src/queries/find/types/FindBuilder.ts +23 -6
  212. package/src/queries/find/types/FindManyParams.ts +2 -2
  213. package/src/queries/find/types/FindOneParams.ts +1 -1
  214. package/src/queries/findMany.ts +25 -17
  215. package/src/queries/update/buildUpdate.ts +2 -2
  216. package/src/queries/update/types/UpdateManyResult.ts +1 -1
  217. package/src/queries/update/types/UpdateOneResult.ts +1 -1
  218. package/src/queries/update/types/UpdateParams.ts +1 -1
  219. package/src/queries/update/types/UpdateValues.ts +1 -1
  220. package/src/queries/update/updateResultSchema.ts +3 -1
  221. package/src/queries/update/updateToSql.ts +1 -1
  222. package/src/queries/updateMany.ts +4 -1
  223. package/src/queries/util/rowToObject.ts +5 -1
  224. package/src/schema/types/base/BaseRelation.ts +1 -0
  225. package/src/schema/types/helpers/ColumnName.ts +5 -6
  226. package/src/schema/types/helpers/ColumnType.ts +2 -2
  227. package/src/schema/types/helpers/Columns.ts +2 -6
  228. package/src/schema/types/helpers/HasDefault.ts +5 -7
  229. package/src/schema/types/helpers/IsNullable.ts +4 -6
  230. package/src/schema/types/helpers/IsProvided.ts +4 -6
  231. package/src/schema/types/helpers/IsSerial.ts +4 -6
  232. package/src/schema/types/loose/LooseRelationDefinition.ts +1 -1
  233. package/src/schema/types/relations/ManyToManyRelation.ts +2 -2
  234. package/src/schema/types/relations/ManyToOneRelation.ts +1 -1
  235. package/src/schema/types/relations/OneToManyRelation.ts +2 -1
  236. package/src/test/db/models/post.model.ts +6 -0
  237. package/src/test/db/models/post.relations.ts +6 -0
  238. package/src/test/db/models/user.model.ts +6 -0
  239. package/src/test/db/models/user.relations.ts +16 -0
  240. package/src/types/ModelType.ts +16 -3
  241. package/lib/queries/clauses/helpers/ModelValues.d.ts +0 -8
  242. package/lib/queries/clauses/helpers/ModelValues.d.ts.map +0 -1
  243. package/lib/queries/clauses/helpers/ModelValues.js +0 -2
  244. package/lib/queries/clauses/helpers/ModelValues.js.map +0 -1
  245. package/src/queries/clauses/helpers/ModelValues.ts +0 -9
@@ -14,27 +14,29 @@ export const buildFind = (
14
14
  _tableIndex = 0,
15
15
  ): FindBuilder => {
16
16
  const builder: FindBuilder = {
17
- tableIndex: _tableIndex,
18
17
  columns: [],
19
- tables: [],
18
+ table: {
19
+ table: config.models[m]["table"],
20
+ model: m,
21
+ schema: config.models[m]["schema"],
22
+ alias: tableAlias(_tableIndex++),
23
+ where: config.middleware.find?.where
24
+ ? config.middleware.find.where(query.where, {
25
+ config,
26
+ model: m,
27
+ })
28
+ : query.where,
29
+ joins: [],
30
+ },
20
31
  orderBy: [],
32
+ tableIndex: _tableIndex,
21
33
  };
22
34
 
23
35
  const model = config.models[m];
24
36
 
25
- const alias = tableAlias(builder.tableIndex++);
37
+ const alias = builder.table.alias;
26
38
  let colIndex = 0;
27
39
 
28
- builder.tables.push({
29
- name: config.models[m]["table"],
30
- model: m,
31
- schema: config.models[m]["schema"],
32
- alias: alias,
33
- where: config.middleware.find?.where
34
- ? config.middleware.find.where(query.where, { config, model: m })
35
- : query.where,
36
- });
37
-
38
40
  // make sure we always select the model's primary key,
39
41
  // and if necessary the foreign key for a lateral join
40
42
  // - we'll strip them out later
@@ -64,34 +66,38 @@ export const buildFind = (
64
66
  [...path, r],
65
67
  builder.tableIndex++,
66
68
  );
67
- const [joinedTable, ...otherTables] = joinBuilder.tables;
68
- builder.tables.push({
69
- ...joinedTable,
70
- joins: [
71
- ...(joinedTable.joins ?? []),
72
- {
73
- from: {
74
- table: alias,
75
- columns: ensureArray(relation.foreignKey).map(
76
- (c) => model.columns[c].name,
77
- ),
78
- },
79
- to: {
80
- table: joinedTable.alias,
81
- columns: joinedModel.primaryKey.map(
82
- (c) => joinedModel.columns[c].name,
83
- ),
84
- },
69
+ const joinedTable = joinBuilder.table;
70
+ builder.table.joins.push(
71
+ {
72
+ from: {
73
+ schema: config.models[m].schema,
74
+ table: config.models[m].table,
75
+ alias,
76
+ model: m,
77
+ columns: ensureArray(relation.foreignKey).map(
78
+ (c) => model.columns[c].name,
79
+ ),
85
80
  },
86
- ],
87
- });
81
+ to: {
82
+ schema: joinedModel.schema,
83
+ table: joinedTable.table,
84
+ alias: joinedTable.alias,
85
+ model: relation.model,
86
+ columns: joinedModel.primaryKey.map(
87
+ (c) => joinedModel.columns[c].name,
88
+ ),
89
+ },
90
+ type: relation.optional ? "left" : "inner",
91
+ where: joinedTable.where,
92
+ },
93
+ ...joinedTable.joins,
94
+ );
88
95
  // this is admittedly a bit weird,
89
96
  // we wouldn't expect N:1 relations to specify
90
97
  // ordering, skipping, and limiting, and typescript
91
98
  // prevents users from doing this, but
92
99
  // we rely on them being present as part of the N:N
93
100
  // implementation
94
- builder.tables.push(...otherTables);
95
101
  builder.columns.push(...joinBuilder.columns);
96
102
  builder.orderBy.push(...joinBuilder.orderBy);
97
103
  builder.limit = min([builder.limit, joinBuilder.limit]);
@@ -12,13 +12,20 @@ export const findResultSchema = (
12
12
 
13
13
  query.select.forEach((field) => {
14
14
  const col = config.models[m].columns[field];
15
- obj[field] = col.nullable ? col.zodSchema.nullable() : col.zodSchema;
15
+ obj[field] = col.nullable
16
+ ? col.zodSchema.nullish().transform((x) => x ?? null)
17
+ : col.zodSchema;
16
18
  });
17
19
 
18
20
  for (const [field, subquery] of Object.entries(query.include || {})) {
19
21
  const relation = config.relations[m][field];
20
22
  const schema = findResultSchema(config, relation.model, subquery!);
21
- obj[field] = relation.type === "N:1" ? schema : z.array(schema);
23
+ obj[field] =
24
+ relation.type === "N:1"
25
+ ? relation.optional
26
+ ? schema.nullish().transform((x) => x ?? null)
27
+ : schema
28
+ : z.array(schema);
22
29
  }
23
30
 
24
31
  return z.object(obj);
@@ -13,7 +13,7 @@ export const findToSql = (
13
13
  builder: FindBuilder,
14
14
  ): SQLStatement => {
15
15
  const frag = new SQLStatement();
16
- const [table, ...joinedTables] = builder.tables;
16
+ const table = builder.table;
17
17
 
18
18
  if (builder.lateralBy) {
19
19
  const { columns, groupTable, itemTable } = builder.lateralBy;
@@ -43,46 +43,41 @@ export const findToSql = (
43
43
  ),
44
44
  );
45
45
 
46
- frag.push(pgfmt(`\nFROM %I.%I %I`, table.schema, table.name, table.alias));
46
+ frag.push(pgfmt(`\nFROM %I.%I %I`, table.schema, table.table, table.alias));
47
47
 
48
- for (const joinedTable of joinedTables) {
49
- if (!joinedTable.joins)
50
- throw new OrmError("Joined table without join clauses", {
51
- data: builder,
52
- });
48
+ for (const join of table.joins ?? []) {
49
+ if (join.from.columns.length !== join.to.columns.length) {
50
+ throw new OrmError(
51
+ "Number of foreign keys doesn't match number of primary keys in join",
52
+ { data: builder },
53
+ );
54
+ }
55
+
56
+ frag.push(join.type === "left" ? "\nLEFT JOIN" : "\nJOIN");
53
57
  frag.push(
54
58
  pgfmt(
55
- "\nJOIN %I.%I %I\n ON ",
56
- joinedTable.schema,
57
- joinedTable.name,
58
- joinedTable.alias,
59
+ " %I.%I %I\n ON ",
60
+ join.to.schema,
61
+ join.to.table,
62
+ join.to.alias,
59
63
  ),
60
64
  );
61
65
  frag.push(
62
- joinedTable.joins
63
- .flatMap((join) => {
64
- if (join.from.columns.length !== join.to.columns.length) {
65
- throw new OrmError(
66
- "Number of foreign keys doesn't match number of primary keys in join",
67
- { data: builder },
68
- );
69
- }
70
-
71
- return join.from.columns.map((from, i) =>
72
- pgfmt(
73
- "%I.%I = %I.%I",
74
- table.alias,
75
- from,
76
- joinedTable.alias,
77
- join.to.columns[i],
78
- ),
79
- );
80
- })
66
+ join.from.columns
67
+ .map((from, i) =>
68
+ pgfmt(
69
+ "%I.%I = %I.%I",
70
+ join.from.alias,
71
+ from,
72
+ join.to.alias,
73
+ join.to.columns[i],
74
+ ),
75
+ )
81
76
  .join(" AND "),
82
77
  );
83
- if (hasConditions(joinedTable.where)) {
78
+ if (hasConditions(join.where)) {
84
79
  frag.push(
85
- sql`\n AND ${buildWhereClauses(config, joinedTable, joinedTable.where)}`,
80
+ sql`\n AND ${buildWhereClauses(config, join.to, join.where)}`,
86
81
  );
87
82
  }
88
83
  }
@@ -0,0 +1,127 @@
1
+ import { describe, expect, test } from "vitest";
2
+
3
+ import { db } from "../../../test/db";
4
+ import { seed } from "../../../test/seed";
5
+
6
+ describe("findMany", () => {
7
+ test("optional N:1 relations don't prevent records being returned", async () => {
8
+ await db.transact(
9
+ async (db) => {
10
+ await seed(db, {
11
+ users: [
12
+ {
13
+ username: "Russell",
14
+ tenants: [
15
+ { name: "WFMA", posts: 1 },
16
+ { name: "Popova Park", posts: 0 },
17
+ ],
18
+ },
19
+ {
20
+ username: "Dan",
21
+ tenants: [{ name: "WFMA", posts: 2 }],
22
+ },
23
+ {
24
+ username: "Fairooz",
25
+ tenants: [{ name: "WFMA", posts: 0 }],
26
+ },
27
+ ],
28
+ });
29
+ const results = await db.findMany("post", {
30
+ select: ["id", "title"],
31
+ include: {
32
+ reviewedBy: {
33
+ select: ["id", "username"],
34
+ include: {
35
+ posts: { select: ["id", "title"] },
36
+ invitedBy: { select: ["id", "username"] },
37
+ },
38
+ },
39
+ },
40
+ orderBy: ["title"],
41
+ limit: 2,
42
+ });
43
+
44
+ expect(results.map((p) => [p.title, p.reviewedBy])).toEqual([
45
+ ["Post a", null],
46
+ ["Post b", null],
47
+ ]);
48
+ },
49
+ { rollback: true },
50
+ );
51
+ });
52
+
53
+ test("optional N:1 relations are returned if they exist", async () => {
54
+ await db.transact(
55
+ async (db) => {
56
+ const { users } = await seed(db, {
57
+ users: [
58
+ {
59
+ username: "Russell",
60
+ tenants: [
61
+ { name: "WFMA", posts: 1 },
62
+ { name: "Popova Park", posts: 0 },
63
+ ],
64
+ },
65
+ {
66
+ username: "Dan",
67
+ tenants: [{ name: "WFMA", posts: 2 }],
68
+ },
69
+ {
70
+ username: "Fairooz",
71
+ tenants: [{ name: "WFMA", posts: 0 }],
72
+ },
73
+ ],
74
+ });
75
+ await db.updateOne("user", {
76
+ where: { id: users["Dan"].id },
77
+ values: {
78
+ invitedById: users["Russell"].id,
79
+ },
80
+ });
81
+ const results = await db.findMany("user", {
82
+ select: ["username"],
83
+ include: {
84
+ invitedBy: {
85
+ select: ["username"],
86
+ },
87
+ tenants: {
88
+ select: ["name"],
89
+ orderBy: ["name"],
90
+ },
91
+ reviewedPosts: {
92
+ select: ["title"],
93
+ },
94
+ invitedUsers: {
95
+ select: ["username"],
96
+ },
97
+ },
98
+ orderBy: ["username"],
99
+ });
100
+ expect(results).toEqual([
101
+ {
102
+ username: "Dan",
103
+ invitedBy: { username: "Russell" },
104
+ tenants: [{ name: "WFMA" }],
105
+ reviewedPosts: [],
106
+ invitedUsers: [],
107
+ },
108
+ {
109
+ username: "Fairooz",
110
+ invitedBy: null,
111
+ tenants: [{ name: "WFMA" }],
112
+ reviewedPosts: [],
113
+ invitedUsers: [],
114
+ },
115
+ {
116
+ username: "Russell",
117
+ invitedBy: null,
118
+ tenants: [{ name: "Popova Park" }, { name: "WFMA" }],
119
+ reviewedPosts: [],
120
+ invitedUsers: [{ username: "Dan" }],
121
+ },
122
+ ]);
123
+ },
124
+ { rollback: true },
125
+ );
126
+ });
127
+ });
@@ -12,12 +12,12 @@ export type FindBuilder = {
12
12
  path: string[];
13
13
  }[];
14
14
 
15
- tables: {
16
- name: string;
15
+ table: {
16
+ table: string;
17
17
  model: string;
18
18
  schema: string;
19
19
  alias: string;
20
- joins?: Join[];
20
+ joins: Join[];
21
21
  conditions?: WhereClause<
22
22
  LooseModelDefinitions,
23
23
  ModelName<LooseModelDefinitions>
@@ -26,7 +26,7 @@ export type FindBuilder = {
26
26
  LooseModelDefinitions,
27
27
  ModelName<LooseModelDefinitions>
28
28
  >;
29
- }[];
29
+ };
30
30
 
31
31
  lateralBy?: {
32
32
  groupTable: string;
@@ -49,6 +49,23 @@ export type FindBuilder = {
49
49
  offset?: number;
50
50
  };
51
51
  export type Join = {
52
- from: { table: string; columns: string[] };
53
- to: { table: string; columns: string[] };
52
+ from: {
53
+ schema: string;
54
+ table: string;
55
+ alias: string;
56
+ model: string;
57
+ columns: string[];
58
+ };
59
+ to: {
60
+ schema: string;
61
+ table: string;
62
+ alias: string;
63
+ model: string;
64
+ columns: string[];
65
+ };
66
+ where?: WhereClause<
67
+ LooseModelDefinitions,
68
+ ModelName<LooseModelDefinitions>
69
+ >;
70
+ type?: "inner" | "left";
54
71
  };
@@ -12,12 +12,12 @@ export type FindManyParams<
12
12
  Relations extends LooseRelationsDefinitions<Models>,
13
13
  M extends ModelName<Models>,
14
14
  > = {
15
- select: SelectClause<Models, M>;
15
+ select: SelectClause<Models[M]>;
16
16
  include?: IncludeClause<Models, Relations, M>;
17
17
  where?: WhereClause<Models, M>;
18
18
  limit?: number;
19
19
  offset?: number;
20
20
  orderBy?: NonEmptyArray<
21
- ColumnName<Models, M> | [ColumnName<Models, M>, "asc" | "desc"]
21
+ ColumnName<Models[M]> | [ColumnName<Models[M]>, "asc" | "desc"]
22
22
  >;
23
23
  };
@@ -10,7 +10,7 @@ export type FindOneParams<
10
10
  Relations extends LooseRelationsDefinitions<Models>,
11
11
  M extends ModelName<Models>,
12
12
  > = {
13
- select: SelectClause<Models, M>;
13
+ select: SelectClause<Models[M]>;
14
14
  where?: WhereClause<Models, M>;
15
15
  include?: IncludeClause<Models, Relations, M>;
16
16
  };
@@ -27,7 +27,10 @@ export const findMany = async (
27
27
  values: statement.values,
28
28
  });
29
29
 
30
- if (!process.env.CI) console.log(statement.text);
30
+ if (process.env.ORM_VERBOSE_LOGGING) {
31
+ console.log(statement.text);
32
+ console.log(statement.values);
33
+ }
31
34
 
32
35
  const results = await conn
33
36
  .query(statement)
@@ -38,7 +41,6 @@ export const findMany = async (
38
41
  m,
39
42
  query,
40
43
  ).map(({ model, relation, query, path }) => {
41
- console.log("Fetching 1:N relation");
42
44
  const pk = config.models[model].primaryKey;
43
45
  const fk = ensureArray(relation.foreignKey);
44
46
  const lateralBy = fk.map((c, index) => ({
@@ -55,11 +57,14 @@ export const findMany = async (
55
57
  return hash(fk.map((c) => result[c]));
56
58
  });
57
59
  for (const result of results) {
58
- const key = hash(
59
- pk.map((c) => get(result, [...dropRight(path, 1), c])),
60
- );
61
- console.log([...path]);
62
- set(result, [...path], lookup[key] ?? []);
60
+ const parent =
61
+ path.length === 1
62
+ ? result
63
+ : get(result, dropRight(path, 1));
64
+ if (parent !== undefined) {
65
+ const key = hash(pk.map((c) => get(parent, c)));
66
+ set(result, path, lookup[key] ?? []);
67
+ }
63
68
  }
64
69
  });
65
70
  });
@@ -69,7 +74,6 @@ export const findMany = async (
69
74
  m,
70
75
  query,
71
76
  ).map(({ model, relation, query, path }) => {
72
- console.log("Fetching N:N relation");
73
77
  const joinFrom = Object.entries(config.relations[model]).find(
74
78
  ([, rel]) => rel.type === "1:N" && rel.model === relation.through,
75
79
  )?.[0];
@@ -102,15 +106,19 @@ export const findMany = async (
102
106
  return hash(fk.map((c) => result[c]));
103
107
  });
104
108
  for (const result of results) {
105
- const key = hash(
106
- pk.map((c) => get(result, [...dropRight(path, 1), c])),
107
- );
108
- console.log([...path]);
109
- set(
110
- result,
111
- [...path],
112
- (lookup[key] ?? []).map((r) => r[joinTo] ?? []),
113
- );
109
+ const parent =
110
+ path.length === 1
111
+ ? result
112
+ : get(result, dropRight(path, 1));
113
+
114
+ if (parent !== undefined) {
115
+ const key = hash(pk.map((c) => get(parent, c)));
116
+ set(
117
+ result,
118
+ path,
119
+ (lookup[key] ?? []).map((r) => r[joinTo] ?? []),
120
+ );
121
+ }
114
122
  }
115
123
  });
116
124
  });
@@ -9,7 +9,7 @@ import { BaseUpdateParams } from "./types/BaseUpdateParams";
9
9
 
10
10
  export type UpdateBuilder = {
11
11
  tableIndex: number;
12
- table: { name: string; model: string; alias: string; schema: string };
12
+ table: { table: string; model: string; alias: string; schema: string };
13
13
  where: WhereClause<LooseModelDefinitions, ModelName<LooseModelDefinitions>>;
14
14
  values: { name: string; value: unknown }[];
15
15
  returning: { name: string; path: string; alias: string }[];
@@ -24,7 +24,7 @@ export const buildUpdate = (
24
24
  const builder: UpdateBuilder = {
25
25
  tableIndex: _tableIndex,
26
26
  table: {
27
- name: config.models[m].table,
27
+ table: config.models[m].table,
28
28
  schema: config.models[m].schema,
29
29
  model: m,
30
30
  alias: tableAlias(_tableIndex++),
@@ -9,7 +9,7 @@ export type UpdateManyResult<
9
9
  M extends ModelName<Models>,
10
10
  P extends UpdateParams<Models, M>,
11
11
  > =
12
- P["returning"] extends ReturningClause<Models, M>
12
+ P["returning"] extends ReturningClause<Models[M]>
13
13
  ? Readonly<{
14
14
  [C in P["returning"][number]]: ColumnType<Models, M, C>;
15
15
  }>[]
@@ -9,7 +9,7 @@ export type UpdateOneResult<
9
9
  M extends ModelName<Models>,
10
10
  P extends UpdateParams<Models, M>,
11
11
  > =
12
- P["returning"] extends ReturningClause<Models, M>
12
+ P["returning"] extends ReturningClause<Models[M]>
13
13
  ? Readonly<{
14
14
  [C in P["returning"][number]]: ColumnType<Models, M, C>;
15
15
  }>
@@ -10,5 +10,5 @@ export type UpdateParams<
10
10
  > = {
11
11
  values: UpdateValues<Models, M>;
12
12
  where: WhereClause<Models, M>;
13
- returning?: ReturningClause<Models, M>;
13
+ returning?: ReturningClause<Models[M]>;
14
14
  };
@@ -8,5 +8,5 @@ export type UpdateValues<
8
8
  Models extends LooseModelDefinitions,
9
9
  M extends ModelName<Models>,
10
10
  > = Simplify<{
11
- [C in ColumnName<Models, M>]?: ColumnType<Models, M, C>;
11
+ [C in ColumnName<Models[M]>]?: ColumnType<Models, M, C>;
12
12
  }>;
@@ -14,7 +14,9 @@ export const updateResultSchema = (
14
14
 
15
15
  params.returning?.forEach((s) => {
16
16
  const col = config.models[m].columns[s];
17
- obj[s] = col.nullable ? col.zodSchema.nullable() : col.zodSchema;
17
+ obj[s] = col.nullable
18
+ ? col.zodSchema.nullish().transform((x) => x ?? null)
19
+ : col.zodSchema;
18
20
  });
19
21
 
20
22
  return z.object(obj);
@@ -14,7 +14,7 @@ export const updateToSql = (
14
14
 
15
15
  const frag = sql`UPDATE %I.%I AS %I\nSET`.withIdentifiers(
16
16
  table.schema,
17
- table.name,
17
+ table.table,
18
18
  table.alias,
19
19
  );
20
20
 
@@ -21,7 +21,10 @@ export const updateMany = async (
21
21
  values: statement.values,
22
22
  });
23
23
 
24
- if (!process.env.CI) console.log(statement.text);
24
+ if (process.env.ORM_VERBOSE_LOGGING) {
25
+ console.log(statement.text);
26
+ console.log(statement.values);
27
+ }
25
28
 
26
29
  const result = await conn.query(statement);
27
30
  return params.returning
@@ -5,5 +5,9 @@ export type ColumnMapping = { path: string | string[]; alias: string };
5
5
  export const rowToObject =
6
6
  (columns: ColumnMapping[]) =>
7
7
  (row: Record<string, unknown>): Record<string, unknown> => {
8
- return columns.reduce((acc, c) => set(acc, c.path, row[c.alias]), {});
8
+ return columns.reduce(
9
+ (acc, c) =>
10
+ row[c.alias] !== null ? set(acc, c.path, row[c.alias]) : acc,
11
+ {},
12
+ );
9
13
  };
@@ -10,6 +10,7 @@ export type BaseRelation =
10
10
  model: string;
11
11
  type: "N:1";
12
12
  foreignKey: string | string[];
13
+ optional?: boolean;
13
14
  }
14
15
  | {
15
16
  model: string;
@@ -1,7 +1,6 @@
1
- import { LooseModelDefinitions } from "../loose/LooseModelDefinitions";
2
- import { ModelName } from "./ModelName";
1
+ import { LooseModelDefinition } from "../loose/LooseModelDefinition";
3
2
 
4
- export type ColumnName<
5
- Models extends LooseModelDefinitions,
6
- M extends ModelName<Models>,
7
- > = Extract<keyof Models[M]["columns"], string>;
3
+ export type ColumnName<Model extends LooseModelDefinition> = Extract<
4
+ keyof Model["columns"],
5
+ string
6
+ >;
@@ -8,7 +8,7 @@ import { ModelName } from "./ModelName";
8
8
  type NonNullableColumnType<
9
9
  Models extends LooseModelDefinitions,
10
10
  M extends ModelName<Models>,
11
- C extends ColumnName<Models, M>,
11
+ C extends ColumnName<Models[M]>,
12
12
  > =
13
13
  Models[M]["columns"][C]["zodSchema"] extends z.ZodType<unknown>
14
14
  ? z.infer<Models[M]["columns"][C]["zodSchema"]>
@@ -17,7 +17,7 @@ type NonNullableColumnType<
17
17
  export type ColumnType<
18
18
  Models extends LooseModelDefinitions,
19
19
  M extends ModelName<Models>,
20
- C extends ColumnName<Models, M>,
20
+ C extends ColumnName<Models[M]>,
21
21
  > = Models[M]["columns"][C]["nullable"] extends true
22
22
  ? NonNullableColumnType<Models, M, C> | null
23
23
  : NonNullableColumnType<Models, M, C>;
@@ -1,7 +1,3 @@
1
- import { LooseModelDefinitions } from "../loose/LooseModelDefinitions";
2
- import { ModelName } from "./ModelName";
1
+ import { LooseModelDefinition } from "../loose/LooseModelDefinition";
3
2
 
4
- export type Columns<
5
- Models extends LooseModelDefinitions,
6
- M extends ModelName<Models>,
7
- > = Models[M]["columns"];
3
+ export type Columns<Model extends LooseModelDefinition> = Model["columns"];
@@ -1,13 +1,11 @@
1
- import { LooseModelDefinitions } from "../loose/LooseModelDefinitions";
1
+ import { LooseModelDefinition } from "../loose/LooseModelDefinition";
2
2
  import { Columns } from "./Columns";
3
- import { ModelName } from "./ModelName";
4
3
 
5
4
  export type HasDefault<
6
- Models extends LooseModelDefinitions,
7
- M extends ModelName<Models>,
8
- C extends keyof Columns<Models, M>,
9
- > = null extends Columns<Models, M>[C]["default"]
5
+ Model extends LooseModelDefinition,
6
+ C extends keyof Columns<Model>,
7
+ > = null extends Columns<Model>[C]["default"]
10
8
  ? false
11
- : undefined extends Columns<Models, M>[C]["default"]
9
+ : undefined extends Columns<Model>[C]["default"]
12
10
  ? false
13
11
  : true;