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

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 (147) 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/where/buildWhereClauses.d.ts +1 -1
  9. package/lib/queries/clauses/where/buildWhereClauses.d.ts.map +1 -1
  10. package/lib/queries/clauses/where/buildWhereClauses.js.map +1 -1
  11. package/lib/queries/clauses/where/buildWhereClauses.test.js +1 -1
  12. package/lib/queries/clauses/where/buildWhereClauses.test.js.map +1 -1
  13. package/lib/queries/count/buildCount.d.ts.map +1 -1
  14. package/lib/queries/count/buildCount.js +33 -29
  15. package/lib/queries/count/buildCount.js.map +1 -1
  16. package/lib/queries/count/countToSql.d.ts.map +1 -1
  17. package/lib/queries/count/countToSql.js +12 -17
  18. package/lib/queries/count/countToSql.js.map +1 -1
  19. package/lib/queries/count/types/CountBuilder.d.ts +12 -4
  20. package/lib/queries/count/types/CountBuilder.d.ts.map +1 -1
  21. package/lib/queries/count.d.ts.map +1 -1
  22. package/lib/queries/count.js +3 -1
  23. package/lib/queries/count.js.map +1 -1
  24. package/lib/queries/create/buildCreate.d.ts +1 -1
  25. package/lib/queries/create/buildCreate.d.ts.map +1 -1
  26. package/lib/queries/create/buildCreate.js +1 -1
  27. package/lib/queries/create/buildCreate.js.map +1 -1
  28. package/lib/queries/create/createResultSchema.d.ts.map +1 -1
  29. package/lib/queries/create/createResultSchema.js +3 -1
  30. package/lib/queries/create/createResultSchema.js.map +1 -1
  31. package/lib/queries/create/createToSql.d.ts.map +1 -1
  32. package/lib/queries/create/createToSql.js +2 -2
  33. package/lib/queries/create/createToSql.js.map +1 -1
  34. package/lib/queries/createMany.d.ts.map +1 -1
  35. package/lib/queries/createMany.js +3 -1
  36. package/lib/queries/createMany.js.map +1 -1
  37. package/lib/queries/delete/buildDelete.d.ts +1 -1
  38. package/lib/queries/delete/buildDelete.d.ts.map +1 -1
  39. package/lib/queries/delete/buildDelete.js +1 -1
  40. package/lib/queries/delete/buildDelete.js.map +1 -1
  41. package/lib/queries/delete/deleteResultSchema.d.ts.map +1 -1
  42. package/lib/queries/delete/deleteResultSchema.js +3 -1
  43. package/lib/queries/delete/deleteResultSchema.js.map +1 -1
  44. package/lib/queries/delete/deleteToSql.js +1 -1
  45. package/lib/queries/delete/deleteToSql.js.map +1 -1
  46. package/lib/queries/deleteMany.d.ts.map +1 -1
  47. package/lib/queries/deleteMany.js +3 -1
  48. package/lib/queries/deleteMany.js.map +1 -1
  49. package/lib/queries/find/buildFind.d.ts.map +1 -1
  50. package/lib/queries/find/buildFind.js +34 -30
  51. package/lib/queries/find/buildFind.js.map +1 -1
  52. package/lib/queries/find/findResultSchema.d.ts.map +1 -1
  53. package/lib/queries/find/findResultSchema.js +9 -2
  54. package/lib/queries/find/findResultSchema.js.map +1 -1
  55. package/lib/queries/find/findToSql.d.ts.map +1 -1
  56. package/lib/queries/find/findToSql.js +12 -17
  57. package/lib/queries/find/findToSql.js.map +1 -1
  58. package/lib/queries/find/tests/findMany.nullable-relations.test.d.ts +2 -0
  59. package/lib/queries/find/tests/findMany.nullable-relations.test.d.ts.map +1 -0
  60. package/lib/queries/find/tests/findMany.nullable-relations.test.js +118 -0
  61. package/lib/queries/find/tests/findMany.nullable-relations.test.js.map +1 -0
  62. package/lib/queries/find/types/FindBuilder.d.ts +12 -4
  63. package/lib/queries/find/types/FindBuilder.d.ts.map +1 -1
  64. package/lib/queries/findMany.d.ts.map +1 -1
  65. package/lib/queries/findMany.js +17 -9
  66. package/lib/queries/findMany.js.map +1 -1
  67. package/lib/queries/update/buildUpdate.d.ts +1 -1
  68. package/lib/queries/update/buildUpdate.d.ts.map +1 -1
  69. package/lib/queries/update/buildUpdate.js +1 -1
  70. package/lib/queries/update/buildUpdate.js.map +1 -1
  71. package/lib/queries/update/updateResultSchema.d.ts.map +1 -1
  72. package/lib/queries/update/updateResultSchema.js +3 -1
  73. package/lib/queries/update/updateResultSchema.js.map +1 -1
  74. package/lib/queries/update/updateToSql.js +1 -1
  75. package/lib/queries/update/updateToSql.js.map +1 -1
  76. package/lib/queries/updateMany.d.ts.map +1 -1
  77. package/lib/queries/updateMany.js +3 -1
  78. package/lib/queries/updateMany.js.map +1 -1
  79. package/lib/queries/util/rowToObject.d.ts.map +1 -1
  80. package/lib/queries/util/rowToObject.js +1 -1
  81. package/lib/queries/util/rowToObject.js.map +1 -1
  82. package/lib/schema/types/base/BaseRelation.d.ts +1 -0
  83. package/lib/schema/types/base/BaseRelation.d.ts.map +1 -1
  84. package/lib/schema/types/loose/LooseRelationDefinition.d.ts +1 -0
  85. package/lib/schema/types/loose/LooseRelationDefinition.d.ts.map +1 -1
  86. package/lib/schema/types/relations/OneToManyRelation.d.ts +1 -0
  87. package/lib/schema/types/relations/OneToManyRelation.d.ts.map +1 -1
  88. package/lib/test/db/index.d.ts +40 -0
  89. package/lib/test/db/index.d.ts.map +1 -1
  90. package/lib/test/db/models/post.model.d.ts +9 -0
  91. package/lib/test/db/models/post.model.d.ts.map +1 -1
  92. package/lib/test/db/models/post.model.js +6 -0
  93. package/lib/test/db/models/post.model.js.map +1 -1
  94. package/lib/test/db/models/post.relations.d.ts +6 -0
  95. package/lib/test/db/models/post.relations.d.ts.map +1 -1
  96. package/lib/test/db/models/post.relations.js +6 -0
  97. package/lib/test/db/models/post.relations.js.map +1 -1
  98. package/lib/test/db/models/user.model.d.ts +9 -0
  99. package/lib/test/db/models/user.model.d.ts.map +1 -1
  100. package/lib/test/db/models/user.model.js +6 -0
  101. package/lib/test/db/models/user.model.js.map +1 -1
  102. package/lib/test/db/models/user.relations.d.ts +16 -0
  103. package/lib/test/db/models/user.relations.d.ts.map +1 -1
  104. package/lib/test/db/models/user.relations.js +16 -0
  105. package/lib/test/db/models/user.relations.js.map +1 -1
  106. package/lib/test/db/models.d.ts +18 -0
  107. package/lib/test/db/models.d.ts.map +1 -1
  108. package/lib/test/db/relations.d.ts +22 -0
  109. package/lib/test/db/relations.d.ts.map +1 -1
  110. package/lib/test/seed/index.d.ts +40 -0
  111. package/lib/test/seed/index.d.ts.map +1 -1
  112. package/package.json +1 -1
  113. package/src/migrate/commands/implode.ts +1 -1
  114. package/src/migrate/sql/createTableSql.test.ts +1 -0
  115. package/src/orm.ts +5 -2
  116. package/src/queries/clauses/where/buildWhereClauses.test.ts +1 -1
  117. package/src/queries/clauses/where/buildWhereClauses.ts +1 -1
  118. package/src/queries/count/buildCount.ts +39 -33
  119. package/src/queries/count/countToSql.ts +27 -32
  120. package/src/queries/count/types/CountBuilder.ts +23 -6
  121. package/src/queries/count.ts +4 -1
  122. package/src/queries/create/buildCreate.ts +2 -2
  123. package/src/queries/create/createResultSchema.ts +3 -1
  124. package/src/queries/create/createToSql.ts +6 -2
  125. package/src/queries/createMany.ts +4 -1
  126. package/src/queries/delete/buildDelete.ts +2 -2
  127. package/src/queries/delete/deleteResultSchema.ts +3 -1
  128. package/src/queries/delete/deleteToSql.ts +1 -1
  129. package/src/queries/deleteMany.ts +4 -1
  130. package/src/queries/find/buildFind.ts +40 -34
  131. package/src/queries/find/findResultSchema.ts +9 -2
  132. package/src/queries/find/findToSql.ts +27 -32
  133. package/src/queries/find/tests/findMany.nullable-relations.test.ts +127 -0
  134. package/src/queries/find/types/FindBuilder.ts +23 -6
  135. package/src/queries/findMany.ts +25 -17
  136. package/src/queries/update/buildUpdate.ts +2 -2
  137. package/src/queries/update/updateResultSchema.ts +3 -1
  138. package/src/queries/update/updateToSql.ts +1 -1
  139. package/src/queries/updateMany.ts +4 -1
  140. package/src/queries/util/rowToObject.ts +5 -1
  141. package/src/schema/types/base/BaseRelation.ts +1 -0
  142. package/src/schema/types/loose/LooseRelationDefinition.ts +1 -1
  143. package/src/schema/types/relations/OneToManyRelation.ts +1 -0
  144. package/src/test/db/models/post.model.ts +6 -0
  145. package/src/test/db/models/post.relations.ts +6 -0
  146. package/src/test/db/models/user.model.ts +6 -0
  147. package/src/test/db/models/user.relations.ts +16 -0
@@ -13,23 +13,25 @@ export const buildCount = (
13
13
  _tableIndex = 0,
14
14
  ): CountBuilder => {
15
15
  const builder: CountBuilder = {
16
+ table: {
17
+ table: config.models[m]["table"],
18
+ model: m,
19
+ schema: config.models[m]["schema"],
20
+ alias: tableAlias(_tableIndex++),
21
+ joins: [],
22
+ where: config.middleware.count?.where
23
+ ? config.middleware.count.where(query.where, {
24
+ config,
25
+ model: m,
26
+ })
27
+ : query.where,
28
+ },
16
29
  tableIndex: _tableIndex,
17
- tables: [],
18
30
  };
19
31
 
20
32
  const model = config.models[m];
21
33
 
22
- const alias = tableAlias(builder.tableIndex++);
23
-
24
- builder.tables.push({
25
- name: config.models[m]["table"],
26
- model: m,
27
- schema: config.models[m]["schema"],
28
- alias: alias,
29
- where: config.middleware.count?.where
30
- ? config.middleware.count.where(query.where, { config, model: m })
31
- : query.where,
32
- });
34
+ const alias = builder.table.alias;
33
35
 
34
36
  for (const [r, subquery] of Object.entries(query.include ?? {})) {
35
37
  const relation = config.relations[m][r];
@@ -42,28 +44,32 @@ export const buildCount = (
42
44
  [...path, r],
43
45
  builder.tableIndex++,
44
46
  );
45
- const [joinedTable, ...otherTables] = joinBuilder.tables;
46
- builder.tables.push({
47
- ...joinedTable,
48
- joins: [
49
- ...(joinedTable.joins ?? []),
50
- {
51
- from: {
52
- table: alias,
53
- columns: ensureArray(relation.foreignKey).map(
54
- (c) => model.columns[c].name,
55
- ),
56
- },
57
- to: {
58
- table: joinedTable.alias,
59
- columns: joinedModel.primaryKey.map(
60
- (c) => joinedModel.columns[c].name,
61
- ),
62
- },
47
+ const joinedTable = joinBuilder.table;
48
+ builder.table.joins.push(
49
+ {
50
+ from: {
51
+ schema: config.models[m].schema,
52
+ table: config.models[m].table,
53
+ alias,
54
+ model: m,
55
+ columns: ensureArray(relation.foreignKey).map(
56
+ (c) => model.columns[c].name,
57
+ ),
58
+ },
59
+ to: {
60
+ schema: joinedModel.schema,
61
+ table: joinedTable.table,
62
+ alias: joinedTable.alias,
63
+ model: relation.model,
64
+ columns: joinedModel.primaryKey.map(
65
+ (c) => joinedModel.columns[c].name,
66
+ ),
63
67
  },
64
- ],
65
- });
66
- builder.tables.push(...otherTables);
68
+ where: joinedTable.where,
69
+ type: relation.optional ? "left" : "inner",
70
+ },
71
+ ...joinedTable.joins,
72
+ );
67
73
  }
68
74
  }
69
75
 
@@ -11,50 +11,45 @@ export const countToSql = (
11
11
  config: BaseConfiguration,
12
12
  builder: CountBuilder,
13
13
  ): SQLStatement => {
14
- const [table, ...joinedTables] = builder.tables;
14
+ const table = builder.table;
15
15
 
16
16
  const frag = sql`SELECT count(1) as "count"`;
17
17
 
18
- frag.push(pgfmt(`\nFROM %I.%I %I`, table.schema, table.name, table.alias));
18
+ frag.push(pgfmt(`\nFROM %I.%I %I`, table.schema, table.table, table.alias));
19
19
 
20
- for (const joinedTable of joinedTables) {
21
- if (!joinedTable.joins)
22
- throw new OrmError("Joined table without join clauses", {
23
- data: builder,
24
- });
20
+ for (const join of table.joins ?? []) {
21
+ if (join.from.columns.length !== join.to.columns.length) {
22
+ throw new OrmError(
23
+ "Number of foreign keys doesn't match number of primary keys in join",
24
+ { data: builder },
25
+ );
26
+ }
27
+
28
+ frag.push(join.type === "left" ? "\nLEFT JOIN" : "\nJOIN");
25
29
  frag.push(
26
30
  pgfmt(
27
- "\nJOIN %I.%I %I\n ON ",
28
- joinedTable.schema,
29
- joinedTable.name,
30
- joinedTable.alias,
31
+ "\n %I.%I %I\n ON ",
32
+ join.to.schema,
33
+ join.to.table,
34
+ join.to.alias,
31
35
  ),
32
36
  );
33
37
  frag.push(
34
- joinedTable.joins
35
- .flatMap((join) => {
36
- if (join.from.columns.length !== join.to.columns.length) {
37
- throw new OrmError(
38
- "Number of foreign keys doesn't match number of primary keys in join",
39
- { data: builder },
40
- );
41
- }
42
-
43
- return join.from.columns.map((from, i) =>
44
- pgfmt(
45
- "%I.%I = %I.%I",
46
- table.alias,
47
- from,
48
- joinedTable.alias,
49
- join.to.columns[i],
50
- ),
51
- );
52
- })
38
+ join.from.columns
39
+ .map((from, i) =>
40
+ pgfmt(
41
+ "%I.%I = %I.%I",
42
+ join.from.alias,
43
+ from,
44
+ join.to.alias,
45
+ join.to.columns[i],
46
+ ),
47
+ )
53
48
  .join(" AND "),
54
49
  );
55
- if (hasConditions(joinedTable.where)) {
50
+ if (hasConditions(join.where)) {
56
51
  frag.push(
57
- sql`\n AND ${buildWhereClauses(config, joinedTable, joinedTable.where)}`,
52
+ sql`\n AND ${buildWhereClauses(config, join.to, join.where)}`,
58
53
  );
59
54
  }
60
55
  }
@@ -5,12 +5,12 @@ import { WhereClause } from "../../clauses/WhereClause";
5
5
  export type CountBuilder = {
6
6
  tableIndex: number;
7
7
 
8
- tables: {
9
- name: string;
8
+ table: {
9
+ table: string;
10
10
  model: string;
11
11
  schema: string;
12
12
  alias: string;
13
- joins?: Join[];
13
+ joins: Join[];
14
14
  conditions?: WhereClause<
15
15
  LooseModelDefinitions,
16
16
  ModelName<LooseModelDefinitions>
@@ -19,10 +19,27 @@ export type CountBuilder = {
19
19
  LooseModelDefinitions,
20
20
  ModelName<LooseModelDefinitions>
21
21
  >;
22
- }[];
22
+ };
23
23
  };
24
24
 
25
25
  export type Join = {
26
- from: { table: string; columns: string[] };
27
- to: { table: string; columns: string[] };
26
+ from: {
27
+ schema: string;
28
+ table: string;
29
+ alias: string;
30
+ model: string;
31
+ columns: string[];
32
+ };
33
+ to: {
34
+ schema: string;
35
+ table: string;
36
+ alias: string;
37
+ model: string;
38
+ columns: string[];
39
+ };
40
+ where?: WhereClause<
41
+ LooseModelDefinitions,
42
+ ModelName<LooseModelDefinitions>
43
+ >;
44
+ type?: "inner" | "left";
28
45
  };
@@ -20,7 +20,10 @@ export const count = async (
20
20
  values: statement.values,
21
21
  });
22
22
 
23
- if (!process.env.CI) console.log(statement.text);
23
+ if (process.env.ORM_VERBOSE_LOGGING) {
24
+ console.log(statement.text);
25
+ console.log(statement.values);
26
+ }
24
27
 
25
28
  const result = await conn
26
29
  .query(statement)
@@ -6,7 +6,7 @@ import { BaseCreateManyParams } from "./types/BaseCreateManyParams";
6
6
 
7
7
  export type CreateBuilder = {
8
8
  tableIndex: number;
9
- table: { name: string; schema: string };
9
+ table: { table: string; schema: string };
10
10
  params: { name: string; path: string; values: unknown[] }[];
11
11
  onConflict?: { do: "nothing" };
12
12
  returning: { name: string; path: string; alias: string }[];
@@ -21,7 +21,7 @@ export const buildCreate = (
21
21
  const builder: CreateBuilder = {
22
22
  tableIndex: _tableIndex,
23
23
  table: {
24
- name: config.models[m].table,
24
+ table: config.models[m].table,
25
25
  schema: config.models[m].schema,
26
26
  },
27
27
  params: [],
@@ -15,7 +15,9 @@ export const createResultSchema = (
15
15
 
16
16
  params.returning?.forEach((s) => {
17
17
  const col = config.models[m].columns[s];
18
- obj[s] = col.nullable ? col.zodSchema.nullable() : col.zodSchema;
18
+ obj[s] = col.nullable
19
+ ? col.zodSchema.nullish().transform((x) => x ?? null)
20
+ : col.zodSchema;
19
21
  });
20
22
 
21
23
  return z.object(obj);
@@ -10,10 +10,14 @@ export const createToSql = (builder: CreateBuilder): SQLStatement => {
10
10
 
11
11
  if (params.length === 0) {
12
12
  frag.push(
13
- pgfmt("INSERT INTO %I.%I DEFAULT VALUES", table.schema, table.name),
13
+ pgfmt(
14
+ "INSERT INTO %I.%I DEFAULT VALUES",
15
+ table.schema,
16
+ table.table,
17
+ ),
14
18
  );
15
19
  } else {
16
- frag.push(pgfmt("INSERT INTO %I.%I (\n", table.schema, table.name));
20
+ frag.push(pgfmt("INSERT INTO %I.%I (\n", table.schema, table.table));
17
21
  frag.push(params.map((p) => pgfmt(" %I", p.name)).join(",\n"));
18
22
  frag.push(") VALUES ");
19
23
  const values = params[0].values.map((_, index) => {
@@ -26,7 +26,10 @@ export const createMany = async (
26
26
  values: statement.values,
27
27
  });
28
28
 
29
- if (!process.env.CI) console.log(statement.text);
29
+ if (process.env.ORM_VERBOSE_LOGGING) {
30
+ console.log(statement.text);
31
+ console.log(statement.values);
32
+ }
30
33
 
31
34
  const result = await conn.query(statement);
32
35
  return params.returning
@@ -9,7 +9,7 @@ import { BaseDeleteParams } from "./types/BaseDeleteParams";
9
9
 
10
10
  export type DeleteBuilder = {
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
  returning: { name: string; path: string; alias: string }[];
15
15
  };
@@ -23,7 +23,7 @@ export const buildDelete = (
23
23
  const builder: DeleteBuilder = {
24
24
  tableIndex: _tableIndex,
25
25
  table: {
26
- name: config.models[m].table,
26
+ table: config.models[m].table,
27
27
  schema: config.models[m].schema,
28
28
  model: m,
29
29
  alias: tableAlias(_tableIndex++),
@@ -14,7 +14,9 @@ export const deleteResultSchema = (
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);
@@ -16,7 +16,7 @@ export const deleteToSql = (
16
16
 
17
17
  const frag = sql`DELETE FROM %I.%I AS %I`.withIdentifiers(
18
18
  table.schema,
19
- table.name,
19
+ table.table,
20
20
  table.alias,
21
21
  );
22
22
 
@@ -21,7 +21,10 @@ export const deleteMany = 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
@@ -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
  }