neoorm 0.8.1 → 0.8.2

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 (318) hide show
  1. package/README.md +10 -5
  2. package/dist/bin/neoorm.d.ts +1 -1
  3. package/dist/bin/neoorm.d.ts.map +1 -1
  4. package/dist/bin/neoorm.js +131 -57
  5. package/dist/bin/neoorm.js.map +1 -1
  6. package/dist/codegen/diff-manifest.d.ts.map +1 -1
  7. package/dist/codegen/diff-manifest.js +106 -4
  8. package/dist/codegen/diff-manifest.js.map +1 -1
  9. package/dist/codegen/generate-summary.d.ts +1 -0
  10. package/dist/codegen/generate-summary.d.ts.map +1 -1
  11. package/dist/codegen/generate-summary.js +3 -0
  12. package/dist/codegen/generate-summary.js.map +1 -1
  13. package/dist/codegen/generate.d.ts +7 -1
  14. package/dist/codegen/generate.d.ts.map +1 -1
  15. package/dist/codegen/generate.js +53 -20
  16. package/dist/codegen/generate.js.map +1 -1
  17. package/dist/codegen/schema-to-manifest.d.ts.map +1 -1
  18. package/dist/codegen/schema-to-manifest.js +302 -22
  19. package/dist/codegen/schema-to-manifest.js.map +1 -1
  20. package/dist/codegen/validation/emit-elysia.d.ts +4 -0
  21. package/dist/codegen/validation/emit-elysia.d.ts.map +1 -0
  22. package/dist/codegen/validation/emit-elysia.js +304 -0
  23. package/dist/codegen/validation/emit-elysia.js.map +1 -0
  24. package/dist/codegen/validation/types.d.ts +1 -1
  25. package/dist/codegen/validation/types.js +1 -1
  26. package/dist/config.d.ts +2 -0
  27. package/dist/config.d.ts.map +1 -1
  28. package/dist/config.js +3 -1
  29. package/dist/config.js.map +1 -1
  30. package/dist/datasource-provider.d.ts +5 -1
  31. package/dist/datasource-provider.d.ts.map +1 -1
  32. package/dist/datasource-provider.js +21 -2
  33. package/dist/datasource-provider.js.map +1 -1
  34. package/dist/dialect/column-kind-support.d.ts +9 -0
  35. package/dist/dialect/column-kind-support.d.ts.map +1 -0
  36. package/dist/dialect/column-kind-support.js +25 -0
  37. package/dist/dialect/column-kind-support.js.map +1 -0
  38. package/dist/dialect/fk.d.ts +30 -1
  39. package/dist/dialect/fk.d.ts.map +1 -1
  40. package/dist/dialect/fk.js +113 -0
  41. package/dist/dialect/fk.js.map +1 -1
  42. package/dist/dialect/index.d.ts +5 -1
  43. package/dist/dialect/index.d.ts.map +1 -1
  44. package/dist/dialect/index.js +4 -0
  45. package/dist/dialect/index.js.map +1 -1
  46. package/dist/dialect/mariadb.d.ts +4 -0
  47. package/dist/dialect/mariadb.d.ts.map +1 -0
  48. package/dist/dialect/mariadb.js +15 -0
  49. package/dist/dialect/mariadb.js.map +1 -0
  50. package/dist/dialect/mariadb.test.d.ts +2 -0
  51. package/dist/dialect/mariadb.test.d.ts.map +1 -0
  52. package/dist/dialect/mariadb.test.js +151 -0
  53. package/dist/dialect/mariadb.test.js.map +1 -0
  54. package/dist/dialect/mysql-family.d.ts +14 -0
  55. package/dist/dialect/mysql-family.d.ts.map +1 -0
  56. package/dist/dialect/mysql-family.js +453 -0
  57. package/dist/dialect/mysql-family.js.map +1 -0
  58. package/dist/dialect/mysql.d.ts +6 -0
  59. package/dist/dialect/mysql.d.ts.map +1 -0
  60. package/dist/dialect/mysql.js +16 -0
  61. package/dist/dialect/mysql.js.map +1 -0
  62. package/dist/dialect/mysql.test.d.ts +2 -0
  63. package/dist/dialect/mysql.test.d.ts.map +1 -0
  64. package/dist/dialect/mysql.test.js +211 -0
  65. package/dist/dialect/mysql.test.js.map +1 -0
  66. package/dist/dialect/placeholders.d.ts +7 -0
  67. package/dist/dialect/placeholders.d.ts.map +1 -0
  68. package/dist/dialect/placeholders.js +18 -0
  69. package/dist/dialect/placeholders.js.map +1 -0
  70. package/dist/dialect/postgres.d.ts.map +1 -1
  71. package/dist/dialect/postgres.js +55 -27
  72. package/dist/dialect/postgres.js.map +1 -1
  73. package/dist/dialect/resolve.d.ts +13 -0
  74. package/dist/dialect/resolve.d.ts.map +1 -0
  75. package/dist/dialect/resolve.js +66 -0
  76. package/dist/dialect/resolve.js.map +1 -0
  77. package/dist/dialect/shared.d.ts +8 -1
  78. package/dist/dialect/shared.d.ts.map +1 -1
  79. package/dist/dialect/shared.js +37 -0
  80. package/dist/dialect/shared.js.map +1 -1
  81. package/dist/dialect/sqlite.d.ts.map +1 -1
  82. package/dist/dialect/sqlite.js +50 -18
  83. package/dist/dialect/sqlite.js.map +1 -1
  84. package/dist/dialect/sqlite.test.js +43 -1
  85. package/dist/dialect/sqlite.test.js.map +1 -1
  86. package/dist/dialect/types.d.ts +46 -3
  87. package/dist/dialect/types.d.ts.map +1 -1
  88. package/dist/docs/pages.d.ts.map +1 -1
  89. package/dist/docs/pages.js +3 -0
  90. package/dist/docs/pages.js.map +1 -1
  91. package/dist/docs/render.js +1 -1
  92. package/dist/index.d.ts +5 -3
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +4 -2
  95. package/dist/index.js.map +1 -1
  96. package/dist/init/scaffold.d.ts +2 -1
  97. package/dist/init/scaffold.d.ts.map +1 -1
  98. package/dist/init/scaffold.js.map +1 -1
  99. package/dist/init/templates.d.ts +3 -2
  100. package/dist/init/templates.d.ts.map +1 -1
  101. package/dist/init/templates.js +19 -10
  102. package/dist/init/templates.js.map +1 -1
  103. package/dist/introspect/group-fks.d.ts +24 -0
  104. package/dist/introspect/group-fks.d.ts.map +1 -0
  105. package/dist/introspect/group-fks.js +48 -0
  106. package/dist/introspect/group-fks.js.map +1 -0
  107. package/dist/introspect/mysql/to-manifest.d.ts +4 -0
  108. package/dist/introspect/mysql/to-manifest.d.ts.map +1 -0
  109. package/dist/introspect/mysql/to-manifest.js +317 -0
  110. package/dist/introspect/mysql/to-manifest.js.map +1 -0
  111. package/dist/introspect/pull.d.ts +1 -0
  112. package/dist/introspect/pull.d.ts.map +1 -1
  113. package/dist/introspect/pull.js +179 -6
  114. package/dist/introspect/pull.js.map +1 -1
  115. package/dist/introspect/queries.d.ts +10 -1
  116. package/dist/introspect/queries.d.ts.map +1 -1
  117. package/dist/introspect/queries.js +41 -11
  118. package/dist/introspect/queries.js.map +1 -1
  119. package/dist/introspect/sqlite/to-manifest.d.ts.map +1 -1
  120. package/dist/introspect/sqlite/to-manifest.js +99 -26
  121. package/dist/introspect/sqlite/to-manifest.js.map +1 -1
  122. package/dist/introspect/to-manifest.d.ts.map +1 -1
  123. package/dist/introspect/to-manifest.js +145 -26
  124. package/dist/introspect/to-manifest.js.map +1 -1
  125. package/dist/migrate/dev-lock.d.ts +15 -0
  126. package/dist/migrate/dev-lock.d.ts.map +1 -0
  127. package/dist/migrate/dev-lock.js +101 -0
  128. package/dist/migrate/dev-lock.js.map +1 -0
  129. package/dist/migrate/runner.d.ts.map +1 -1
  130. package/dist/migrate/runner.js +143 -51
  131. package/dist/migrate/runner.js.map +1 -1
  132. package/dist/plugins/builtin.d.ts +42 -0
  133. package/dist/plugins/builtin.d.ts.map +1 -1
  134. package/dist/plugins/builtin.js +276 -8
  135. package/dist/plugins/builtin.js.map +1 -1
  136. package/dist/plugins/json/operators.d.ts.map +1 -1
  137. package/dist/plugins/json/operators.js +69 -3
  138. package/dist/plugins/json/operators.js.map +1 -1
  139. package/dist/plugins/postgis/operators.d.ts.map +1 -1
  140. package/dist/plugins/postgis/operators.js +15 -3
  141. package/dist/plugins/postgis/operators.js.map +1 -1
  142. package/dist/runtime/client.d.ts +31 -4
  143. package/dist/runtime/client.d.ts.map +1 -1
  144. package/dist/runtime/client.js +129 -4
  145. package/dist/runtime/client.js.map +1 -1
  146. package/dist/runtime/driver.d.ts +2 -0
  147. package/dist/runtime/driver.d.ts.map +1 -1
  148. package/dist/runtime/driver.js +12 -0
  149. package/dist/runtime/driver.js.map +1 -1
  150. package/dist/runtime/executor.d.ts +1 -0
  151. package/dist/runtime/executor.d.ts.map +1 -1
  152. package/dist/runtime/executor.js +7 -1
  153. package/dist/runtime/executor.js.map +1 -1
  154. package/dist/runtime/mariadb-driver.d.ts +25 -0
  155. package/dist/runtime/mariadb-driver.d.ts.map +1 -0
  156. package/dist/runtime/mariadb-driver.js +103 -0
  157. package/dist/runtime/mariadb-driver.js.map +1 -0
  158. package/dist/runtime/mysql-driver.d.ts +25 -0
  159. package/dist/runtime/mysql-driver.d.ts.map +1 -0
  160. package/dist/runtime/mysql-driver.js +101 -0
  161. package/dist/runtime/mysql-driver.js.map +1 -0
  162. package/dist/runtime/mysql-error.d.ts +15 -0
  163. package/dist/runtime/mysql-error.d.ts.map +1 -0
  164. package/dist/runtime/mysql-error.js +119 -0
  165. package/dist/runtime/mysql-error.js.map +1 -0
  166. package/dist/runtime/mysql-family-pool.d.ts +50 -0
  167. package/dist/runtime/mysql-family-pool.d.ts.map +1 -0
  168. package/dist/runtime/mysql-family-pool.js +52 -0
  169. package/dist/runtime/mysql-family-pool.js.map +1 -0
  170. package/dist/runtime/mysql-family-pool.test.d.ts +2 -0
  171. package/dist/runtime/mysql-family-pool.test.d.ts.map +1 -0
  172. package/dist/runtime/mysql-family-pool.test.js +169 -0
  173. package/dist/runtime/mysql-family-pool.test.js.map +1 -0
  174. package/dist/runtime/mysql-placeholders.d.ts +18 -0
  175. package/dist/runtime/mysql-placeholders.d.ts.map +1 -0
  176. package/dist/runtime/mysql-placeholders.js +133 -0
  177. package/dist/runtime/mysql-placeholders.js.map +1 -0
  178. package/dist/runtime/mysql-placeholders.test.d.ts +2 -0
  179. package/dist/runtime/mysql-placeholders.test.d.ts.map +1 -0
  180. package/dist/runtime/mysql-placeholders.test.js +33 -0
  181. package/dist/runtime/mysql-placeholders.test.js.map +1 -0
  182. package/dist/runtime/query/compile-aggregate.d.ts +1 -1
  183. package/dist/runtime/query/compile-aggregate.d.ts.map +1 -1
  184. package/dist/runtime/query/compile-aggregate.js +25 -22
  185. package/dist/runtime/query/compile-aggregate.js.map +1 -1
  186. package/dist/runtime/query/compile-where.d.ts +9 -9
  187. package/dist/runtime/query/compile-where.d.ts.map +1 -1
  188. package/dist/runtime/query/compile-where.js +87 -66
  189. package/dist/runtime/query/compile-where.js.map +1 -1
  190. package/dist/runtime/query/compile-write.d.ts +9 -9
  191. package/dist/runtime/query/compile-write.d.ts.map +1 -1
  192. package/dist/runtime/query/compile-write.js +77 -63
  193. package/dist/runtime/query/compile-write.js.map +1 -1
  194. package/dist/runtime/query/count.d.ts.map +1 -1
  195. package/dist/runtime/query/count.js +4 -1
  196. package/dist/runtime/query/count.js.map +1 -1
  197. package/dist/runtime/query/create.d.ts.map +1 -1
  198. package/dist/runtime/query/create.js +38 -12
  199. package/dist/runtime/query/create.js.map +1 -1
  200. package/dist/runtime/query/cursor.d.ts +1 -1
  201. package/dist/runtime/query/cursor.d.ts.map +1 -1
  202. package/dist/runtime/query/cursor.js +6 -7
  203. package/dist/runtime/query/cursor.js.map +1 -1
  204. package/dist/runtime/query/delete.d.ts.map +1 -1
  205. package/dist/runtime/query/delete.js +41 -15
  206. package/dist/runtime/query/delete.js.map +1 -1
  207. package/dist/runtime/query/execute.d.ts +1 -0
  208. package/dist/runtime/query/execute.d.ts.map +1 -1
  209. package/dist/runtime/query/execute.js +23 -8
  210. package/dist/runtime/query/execute.js.map +1 -1
  211. package/dist/runtime/query/find-or-create.d.ts +1 -1
  212. package/dist/runtime/query/find-or-create.d.ts.map +1 -1
  213. package/dist/runtime/query/find-or-create.js +16 -8
  214. package/dist/runtime/query/find-or-create.js.map +1 -1
  215. package/dist/runtime/query/find.d.ts +2 -0
  216. package/dist/runtime/query/find.d.ts.map +1 -1
  217. package/dist/runtime/query/find.js +108 -62
  218. package/dist/runtime/query/find.js.map +1 -1
  219. package/dist/runtime/query/mutation-returning.d.ts +10 -0
  220. package/dist/runtime/query/mutation-returning.d.ts.map +1 -0
  221. package/dist/runtime/query/mutation-returning.js +85 -0
  222. package/dist/runtime/query/mutation-returning.js.map +1 -0
  223. package/dist/runtime/query/paginate.d.ts.map +1 -1
  224. package/dist/runtime/query/paginate.js +3 -3
  225. package/dist/runtime/query/paginate.js.map +1 -1
  226. package/dist/runtime/query/relation-join.d.ts +5 -0
  227. package/dist/runtime/query/relation-join.d.ts.map +1 -0
  228. package/dist/runtime/query/relation-join.js +26 -0
  229. package/dist/runtime/query/relation-join.js.map +1 -0
  230. package/dist/runtime/query/relation-planner.d.ts +1 -1
  231. package/dist/runtime/query/relation-planner.d.ts.map +1 -1
  232. package/dist/runtime/query/relation-planner.js +69 -55
  233. package/dist/runtime/query/relation-planner.js.map +1 -1
  234. package/dist/runtime/query/relation-writes.d.ts +2 -2
  235. package/dist/runtime/query/relation-writes.d.ts.map +1 -1
  236. package/dist/runtime/query/relation-writes.js +257 -98
  237. package/dist/runtime/query/relation-writes.js.map +1 -1
  238. package/dist/runtime/query/table-index.d.ts.map +1 -1
  239. package/dist/runtime/query/table-index.js +16 -9
  240. package/dist/runtime/query/table-index.js.map +1 -1
  241. package/dist/runtime/query/unique.d.ts +3 -0
  242. package/dist/runtime/query/unique.d.ts.map +1 -1
  243. package/dist/runtime/query/unique.js +26 -6
  244. package/dist/runtime/query/unique.js.map +1 -1
  245. package/dist/runtime/query/unique.test.js +110 -7
  246. package/dist/runtime/query/unique.test.js.map +1 -1
  247. package/dist/runtime/query/update.d.ts.map +1 -1
  248. package/dist/runtime/query/update.js +89 -23
  249. package/dist/runtime/query/update.js.map +1 -1
  250. package/dist/runtime/query/updated-at.js +2 -2
  251. package/dist/runtime/query/updated-at.js.map +1 -1
  252. package/dist/runtime/query/upsert.d.ts.map +1 -1
  253. package/dist/runtime/query/upsert.js +29 -5
  254. package/dist/runtime/query/upsert.js.map +1 -1
  255. package/dist/runtime/transaction.d.ts +1 -0
  256. package/dist/runtime/transaction.d.ts.map +1 -1
  257. package/dist/runtime/transaction.js +8 -0
  258. package/dist/runtime/transaction.js.map +1 -1
  259. package/dist/runtime/types.d.ts +10 -2
  260. package/dist/runtime/types.d.ts.map +1 -1
  261. package/dist/schema/column-constraints.d.ts +1 -1
  262. package/dist/schema/column-constraints.d.ts.map +1 -1
  263. package/dist/schema/column-constraints.js +6 -3
  264. package/dist/schema/column-constraints.js.map +1 -1
  265. package/dist/schema/column.d.ts +2 -2
  266. package/dist/schema/column.d.ts.map +1 -1
  267. package/dist/schema/column.js +1 -1
  268. package/dist/schema/column.js.map +1 -1
  269. package/dist/schema/index.d.ts +4 -4
  270. package/dist/schema/index.d.ts.map +1 -1
  271. package/dist/schema/index.js +2 -2
  272. package/dist/schema/index.js.map +1 -1
  273. package/dist/schema/nested-relation-types.d.ts +10 -9
  274. package/dist/schema/nested-relation-types.d.ts.map +1 -1
  275. package/dist/schema/relation-types.d.ts +73 -12
  276. package/dist/schema/relation-types.d.ts.map +1 -1
  277. package/dist/schema/relation.d.ts +11 -1
  278. package/dist/schema/relation.d.ts.map +1 -1
  279. package/dist/schema/relation.js +6 -0
  280. package/dist/schema/relation.js.map +1 -1
  281. package/dist/schema/table.d.ts +74 -11
  282. package/dist/schema/table.d.ts.map +1 -1
  283. package/dist/schema/table.js +93 -7
  284. package/dist/schema/table.js.map +1 -1
  285. package/dist/schema/types.d.ts +1 -1
  286. package/dist/schema/types.d.ts.map +1 -1
  287. package/dist/sql/builder.d.ts +13 -3
  288. package/dist/sql/builder.d.ts.map +1 -1
  289. package/dist/sql/builder.js +155 -5
  290. package/dist/sql/builder.js.map +1 -1
  291. package/dist/sql/index.d.ts +1 -0
  292. package/dist/sql/index.d.ts.map +1 -1
  293. package/dist/sql/index.js.map +1 -1
  294. package/dist/sql/qualify-tables.d.ts +15 -0
  295. package/dist/sql/qualify-tables.d.ts.map +1 -0
  296. package/dist/sql/qualify-tables.js +206 -0
  297. package/dist/sql/qualify-tables.js.map +1 -0
  298. package/dist/sql/template.d.ts +5 -0
  299. package/dist/sql/template.d.ts.map +1 -1
  300. package/dist/sql/template.js +23 -3
  301. package/dist/sql/template.js.map +1 -1
  302. package/docs/cli.md +4 -4
  303. package/docs/configuration.md +7 -6
  304. package/docs/elysia.md +131 -0
  305. package/docs/errors.md +1 -1
  306. package/docs/examples.md +4 -2
  307. package/docs/getting-started.md +6 -4
  308. package/docs/mariadb.md +149 -0
  309. package/docs/migrations.md +5 -3
  310. package/docs/mysql.md +134 -0
  311. package/docs/plugins.md +1 -1
  312. package/docs/queries.md +14 -11
  313. package/docs/relations.md +19 -4
  314. package/docs/schema.md +73 -10
  315. package/docs/sqlite.md +6 -2
  316. package/docs/typebox.md +4 -4
  317. package/docs/zod.md +2 -2
  318. package/package.json +18 -2
@@ -1,11 +1,13 @@
1
- import { postgresDialect, quoteIdentifier, tableRef, } from "../../dialect/postgres.js";
1
+ import { parseFkTarget, relationFkPairs } from "../../dialect/fk.js";
2
+ import { joinPlaceholders } from "../../dialect/placeholders.js";
3
+ import { postgresDialect } from "../../dialect/postgres.js";
2
4
  import { compileError } from "../compile-error.js";
3
5
  import { QueryErrorCode } from "../error-codes.js";
4
6
  import { buildInsertManyQuery, buildInsertManyValueRows, dataToSqlValues, } from "./compile.js";
5
7
  import { runQuery } from "./execute.js";
6
- import { findOrCreatePk } from "./find-or-create.js";
8
+ import { findOrCreatePk, findOrCreateRecord } from "./find-or-create.js";
7
9
  import { findM2M, findRelation, tableOwnsFkColumn } from "./manifest-lookup.js";
8
- import { fillMissingPrimaryKeys, primaryKeySqlName, requireScalarPrimaryKey, rowScalarPkValue, targetRelationPkSql, } from "./primary-key.js";
10
+ import { fillMissingPrimaryKeys, primaryKeySqlName, primaryKeyTsNames, resolvePkWhere, targetRelationPkSql, } from "./primary-key.js";
9
11
  import { columnBySqlName, columnByTsName, getTableIndex, requireTable, requireTsColumn, } from "./table-index.js";
10
12
  const RELATION_WRITE_KEYS = [
11
13
  "delete",
@@ -56,31 +58,148 @@ function connectPkError(table, pkTsName, detail) {
56
58
  code: QueryErrorCode.missing_primary_key,
57
59
  tableAccessor: table.accessor,
58
60
  tableSqlName: table.sqlName,
59
- columnTsName: pkTsName,
61
+ ...(pkTsName !== undefined ? { columnTsName: pkTsName } : {}),
60
62
  });
61
63
  }
62
- function readConnectPk(item, pkTsName, table) {
63
- if (!item || typeof item !== "object" || Array.isArray(item)) {
64
- connectPkError(table, pkTsName, `Relation connect requires { ${pkTsName}: ... } for table "${table.accessor}"`);
64
+ function normalizeConnectPks(runtime, targetAccessor, value) {
65
+ const table = requireTable(runtime.manifest, targetAccessor, "select");
66
+ const tableIndex = getTableIndex(runtime.tableIndex, targetAccessor);
67
+ if (value == null || value === false)
68
+ return [];
69
+ const items = Array.isArray(value) ? value : [value];
70
+ return items.map((item) => {
71
+ if (!item || typeof item !== "object" || Array.isArray(item)) {
72
+ const pkNames = primaryKeyTsNames(table, tableIndex);
73
+ connectPkError(table, pkNames[0], `Relation connect requires { ${pkNames.join(", ")} } for table "${table.accessor}"`);
74
+ }
75
+ return resolvePkWhere(table, item, tableIndex);
76
+ });
77
+ }
78
+ function pkField(table, pk, tsName) {
79
+ const value = pk[tsName];
80
+ if (value == null) {
81
+ connectPkError(table, tsName, `Relation connect requires primary key "${tsName}" for table "${table.accessor}"`);
65
82
  }
66
- const id = item[pkTsName];
67
- if (id == null) {
68
- connectPkError(table, pkTsName, `Relation connect requires primary key "${pkTsName}" for table "${table.accessor}"`);
83
+ return value;
84
+ }
85
+ function assignOutgoingFkScalars(scalarData, rel, targetTable, targetIndex, record, nulls = false) {
86
+ for (const pair of relationFkPairs(rel)) {
87
+ if (nulls) {
88
+ scalarData[pair.fkColumn] = null;
89
+ continue;
90
+ }
91
+ const targetTs = columnBySqlName(targetIndex, targetTable, pair.targetColumn)
92
+ ?.tsName ??
93
+ columnByTsName(targetIndex, targetTable, pair.targetColumn)
94
+ ?.tsName ??
95
+ pair.targetColumn;
96
+ scalarData[pair.fkColumn] = pkField(targetTable, record, targetTs);
69
97
  }
70
- return String(id);
71
98
  }
72
- function normalizeIdList(value, pkTsName, table) {
73
- if (value == null || value === false)
74
- return [];
75
- if (Array.isArray(value)) {
76
- return value.map((item) => readConnectPk(item, pkTsName, table));
99
+ function childFkCreatePatch(rel, parentTable, parentRow, parentId) {
100
+ const assignment = inverseFkAssignments(rel, parentTable, parentRow, parentId);
101
+ const pairs = relationFkPairs(rel);
102
+ const patch = {};
103
+ for (let i = 0; i < pairs.length; i++) {
104
+ const pair = pairs[i];
105
+ if (!pair)
106
+ continue;
107
+ patch[pair.fkColumn] = assignment.values[i] ?? parentId;
77
108
  }
78
- return [readConnectPk(value, pkTsName, table)];
109
+ return patch;
79
110
  }
80
- function normalizeConnectIds(runtime, targetAccessor, value) {
81
- const table = requireTable(runtime.manifest, targetAccessor, "select");
82
- const { tsName } = requireScalarPrimaryKey(table, "connect", getTableIndex(runtime.tableIndex, targetAccessor));
83
- return normalizeIdList(value, tsName, table);
111
+ function inverseFkAssignments(rel, parentTable, parentRow, parentId) {
112
+ const pairs = relationFkPairs(rel);
113
+ const refs = rel.referencedSqlColumns && rel.referencedSqlColumns.length > 0
114
+ ? rel.referencedSqlColumns
115
+ : pairs.map((pair) => pair.targetColumn);
116
+ if (pairs.length <= 1) {
117
+ return {
118
+ sqlNames: [rel.fkSqlColumn],
119
+ values: [parentId],
120
+ };
121
+ }
122
+ const values = pairs.map((pair, i) => {
123
+ const ref = refs[i] ?? pair.targetColumn;
124
+ const col = parentTable.columns.find((item) => item.sqlName === ref || item.tsName === ref);
125
+ const value = parentRow?.[col?.tsName ?? ref];
126
+ return value ?? parentId;
127
+ });
128
+ return {
129
+ sqlNames: pairs.map((pair) => pair.fkSqlColumn),
130
+ values,
131
+ };
132
+ }
133
+ function fkTargetTsName(table, tableIndex, relation, throughFk) {
134
+ if (throughFk?.fkTarget) {
135
+ const { columnSql } = parseFkTarget(throughFk.fkTarget);
136
+ const col = columnBySqlName(tableIndex, table, columnSql) ??
137
+ columnByTsName(tableIndex, table, columnSql);
138
+ if (col)
139
+ return col.tsName;
140
+ }
141
+ const sql = targetRelationPkSql(table, relation);
142
+ const col = columnBySqlName(tableIndex, table, sql) ??
143
+ columnByTsName(tableIndex, table, sql);
144
+ if (col)
145
+ return col.tsName;
146
+ const names = primaryKeyTsNames(table, tableIndex);
147
+ const first = names[0];
148
+ if (!first) {
149
+ connectPkError(table, undefined, `No primary key defined for table "${table.accessor}"`);
150
+ }
151
+ return first;
152
+ }
153
+ function m2mOtherThroughColumn(runtime, m2m, parentAccessor) {
154
+ const throughTable = runtime.manifest.tables[m2m.throughAccessor];
155
+ if (!throughTable)
156
+ return undefined;
157
+ const throughIndex = getTableIndex(runtime.tableIndex, throughTable.accessor);
158
+ const isLeft = m2m.leftAccessor === parentAccessor;
159
+ const otherFkCol = isLeft ? m2m.rightFkColumn : m2m.leftFkColumn;
160
+ return columnBySqlName(throughIndex, throughTable, otherFkCol);
161
+ }
162
+ function m2mConnectFkValues(runtime, m2m, parentAccessor, targetAccessor, value) {
163
+ const pks = normalizeConnectPks(runtime, targetAccessor, value);
164
+ const targetTable = requireTable(runtime.manifest, targetAccessor, "select");
165
+ const targetIndex = getTableIndex(runtime.tableIndex, targetAccessor);
166
+ const throughFk = m2mOtherThroughColumn(runtime, m2m, parentAccessor);
167
+ const fkTs = fkTargetTsName(targetTable, targetIndex, undefined, throughFk);
168
+ return { pks, ids: extractFkValues(targetTable, pks, fkTs) };
169
+ }
170
+ function extractFkValues(table, pks, fkTsName) {
171
+ return pks.map((pk) => pkField(table, pk, fkTsName));
172
+ }
173
+ function sqlPkPredicate(dialect, table, tableIndex, pks, startParam) {
174
+ const tsNames = primaryKeyTsNames(table, tableIndex);
175
+ if (tsNames.length === 0 || pks.length === 0) {
176
+ connectPkError(table, undefined, `No primary key defined for table "${table.accessor}"`);
177
+ }
178
+ const quoted = tsNames.map((tsName) => {
179
+ const col = columnByTsName(tableIndex, table, tsName);
180
+ return dialect.quoteIdentifier(col?.sqlName ?? tsName);
181
+ });
182
+ if (tsNames.length === 1) {
183
+ const tsName = tsNames[0];
184
+ if (!tsName || !quoted[0]) {
185
+ connectPkError(table, tsName, `No primary key defined for table "${table.accessor}"`);
186
+ }
187
+ const placeholders = joinPlaceholders(dialect, pks.length, startParam);
188
+ return {
189
+ sql: `${quoted[0]} IN (${placeholders})`,
190
+ params: pks.map((pk) => pkField(table, pk, tsName)),
191
+ };
192
+ }
193
+ const params = [];
194
+ let index = startParam;
195
+ const groups = pks.map((pk) => {
196
+ const parts = tsNames.map((tsName, i) => {
197
+ params.push(pkField(table, pk, tsName));
198
+ return `${quoted[i]} = ${dialect.placeholder(index++)}`;
199
+ });
200
+ return `(${parts.join(" AND ")})`;
201
+ });
202
+ return { sql: `(${groups.join(" OR ")})`, params };
84
203
  }
85
204
  function normalizeCreateList(value) {
86
205
  if (!value)
@@ -109,10 +228,10 @@ export function splitScalarsAndRelationWrites(manifest, tableAccessor, table, da
109
228
  }
110
229
  return { scalarData, relationWrites };
111
230
  }
112
- export async function resolveConnectOrCreate(executor, runtime, targetAccessor, items) {
231
+ export async function resolveConnectOrCreate(executor, runtime, targetAccessor, items, fkTsName) {
113
232
  const ids = [];
114
233
  for (const item of items) {
115
- const id = await findOrCreatePk(executor, runtime, targetAccessor, item);
234
+ const id = await findOrCreatePk(executor, runtime, targetAccessor, item, fkTsName);
116
235
  ids.push(id);
117
236
  }
118
237
  return ids;
@@ -167,7 +286,7 @@ async function insertM2MLinks(executor, runtime, m2m, parentAccessor, parentId,
167
286
  const valueByKey = new Map(keys.map((key, i) => [key, values[i]]));
168
287
  return dataKeys.map((key) => valueByKey.get(key));
169
288
  });
170
- const { valueRows, values } = buildInsertManyValueRows(throughTable, dataKeys, rowValues, runtime.tableIndex);
289
+ const { valueRows, values } = buildInsertManyValueRows(throughTable, dataKeys, rowValues, runtime.tableIndex, dialect);
171
290
  const sql = buildInsertManyQuery(throughTable, dataKeys, valueRows, runtime.tableIndex, true, dialect);
172
291
  await runQuery(executor, runtime, { operation: "insert", tableAccessor: throughTable.accessor }, sql, values);
173
292
  }
@@ -181,6 +300,7 @@ async function _insertJunctionRows(executor, runtime, throughAccessor, leftFkCol
181
300
  await insertM2MLinks(executor, runtime, m2m, parentAccessor, leftId, rightIds);
182
301
  }
183
302
  async function deleteJunctionRows(executor, runtime, m2m, parentAccessor, parentId, rightIds) {
303
+ const dialect = runtime.dialect ?? postgresDialect;
184
304
  const { manifest } = runtime;
185
305
  const throughTable = manifest.tables[m2m.throughAccessor];
186
306
  if (!throughTable)
@@ -194,10 +314,10 @@ async function deleteJunctionRows(executor, runtime, m2m, parentAccessor, parent
194
314
  if (!parentCol || !otherCol)
195
315
  return;
196
316
  const params = [parentId];
197
- let sql = `DELETE FROM ${tableRef(throughTable)} WHERE ${quoteIdentifier(parentCol.sqlName)} = $1`;
317
+ let sql = `DELETE FROM ${dialect.tableRef(throughTable)} WHERE ${dialect.quoteIdentifier(parentCol.sqlName)} = ${dialect.placeholder(1)}`;
198
318
  if (rightIds && rightIds.length > 0) {
199
- const placeholders = rightIds.map((_, i) => `$${i + 2}`).join(", ");
200
- sql += ` AND ${quoteIdentifier(otherCol.sqlName)} IN (${placeholders})`;
319
+ const placeholders = joinPlaceholders(dialect, rightIds.length, 2);
320
+ sql += ` AND ${dialect.quoteIdentifier(otherCol.sqlName)} IN (${placeholders})`;
201
321
  params.push(...rightIds);
202
322
  }
203
323
  await runQuery(executor, runtime, { operation: "delete", tableAccessor: throughTable.accessor }, sql, params);
@@ -210,56 +330,63 @@ function childFkColumnMeta(targetTable, relation, tableIndex) {
210
330
  }
211
331
  return col;
212
332
  }
213
- async function connectInverseMany(executor, runtime, relation, parentId, childIds) {
333
+ async function connectInverseMany(executor, runtime, relation, parentId, childPks, parentTable, parentRow) {
334
+ const dialect = runtime.dialect ?? postgresDialect;
214
335
  const { manifest } = runtime;
215
336
  const targetTable = manifest.tables[relation.targetAccessor];
216
- if (!targetTable || childIds.length === 0)
337
+ if (!targetTable || childPks.length === 0)
217
338
  return;
218
- const fkCol = childFkColumnMeta(targetTable, relation, getTableIndex(runtime.tableIndex, targetTable.accessor));
219
- const placeholders = childIds.map((_, i) => `$${i + 2}`).join(", ");
220
- const targetPkCol = quoteIdentifier(targetRelationPkSql(targetTable, relation));
221
- await runQuery(executor, runtime, { operation: "update", tableAccessor: relation.targetAccessor }, `UPDATE ${tableRef(targetTable)} SET ${quoteIdentifier(fkCol.sqlName)} = $1 WHERE ${targetPkCol} IN (${placeholders})`, [parentId, ...childIds]);
339
+ const targetIndex = getTableIndex(runtime.tableIndex, targetTable.accessor);
340
+ const assignment = inverseFkAssignments(relation, parentTable ?? targetTable, parentRow, parentId);
341
+ const predicate = sqlPkPredicate(dialect, targetTable, targetIndex, childPks, assignment.values.length + 1);
342
+ const setSql = assignment.sqlNames
343
+ .map((sqlName, i) => `${dialect.quoteIdentifier(sqlName)} = ${dialect.placeholder(i + 1)}`)
344
+ .join(", ");
345
+ await runQuery(executor, runtime, { operation: "update", tableAccessor: relation.targetAccessor }, `UPDATE ${dialect.tableRef(targetTable)} SET ${setSql} WHERE ${predicate.sql}`, [...assignment.values, ...predicate.params]);
222
346
  }
223
- async function disconnectInverseMany(executor, runtime, relation, parentId, childIds) {
347
+ async function disconnectInverseMany(executor, runtime, relation, parentId, childPks) {
348
+ const dialect = runtime.dialect ?? postgresDialect;
224
349
  const { manifest } = runtime;
225
350
  const targetTable = manifest.tables[relation.targetAccessor];
226
351
  if (!targetTable)
227
352
  return;
228
- const fkCol = childFkColumnMeta(targetTable, relation, getTableIndex(runtime.tableIndex, targetTable.accessor));
353
+ const targetIndex = getTableIndex(runtime.tableIndex, targetTable.accessor);
354
+ const fkCol = childFkColumnMeta(targetTable, relation, targetIndex);
229
355
  if (!fkCol.nullable) {
230
356
  compileError(`Cannot disconnect relation ${relation.name}: FK column is not nullable`);
231
357
  }
232
358
  const params = [parentId];
233
- let sql = `UPDATE ${tableRef(targetTable)} SET ${quoteIdentifier(fkCol.sqlName)} = NULL WHERE ${quoteIdentifier(fkCol.sqlName)} = $1`;
234
- if (childIds && childIds.length > 0) {
235
- const placeholders = childIds.map((_, i) => `$${i + 2}`).join(", ");
236
- const targetPkCol = quoteIdentifier(targetRelationPkSql(targetTable, relation));
237
- sql += ` AND ${targetPkCol} IN (${placeholders})`;
238
- params.push(...childIds);
359
+ let sql = `UPDATE ${dialect.tableRef(targetTable)} SET ${dialect.quoteIdentifier(fkCol.sqlName)} = NULL WHERE ${dialect.quoteIdentifier(fkCol.sqlName)} = ${dialect.placeholder(1)}`;
360
+ if (childPks && childPks.length > 0) {
361
+ const predicate = sqlPkPredicate(dialect, targetTable, targetIndex, childPks, 2);
362
+ sql += ` AND ${predicate.sql}`;
363
+ params.push(...predicate.params);
239
364
  }
240
365
  await runQuery(executor, runtime, { operation: "update", tableAccessor: relation.targetAccessor }, sql, params);
241
366
  }
242
- async function setInverseMany(executor, runtime, relation, parentId, childIds) {
367
+ async function setInverseMany(executor, runtime, relation, parentId, childPks, parentTable, parentRow) {
243
368
  await disconnectInverseMany(executor, runtime, relation, parentId, undefined);
244
- await connectInverseMany(executor, runtime, relation, parentId, childIds);
369
+ await connectInverseMany(executor, runtime, relation, parentId, childPks, parentTable, parentRow);
245
370
  }
246
- async function deleteInverseManyChildren(executor, runtime, relation, parentId, childIds) {
371
+ async function deleteInverseManyChildren(executor, runtime, relation, parentId, childPks) {
372
+ const dialect = runtime.dialect ?? postgresDialect;
247
373
  const { manifest } = runtime;
248
374
  const targetTable = manifest.tables[relation.targetAccessor];
249
375
  if (!targetTable)
250
376
  return;
251
- const fkCol = childFkColumnMeta(targetTable, relation, getTableIndex(runtime.tableIndex, targetTable.accessor));
252
- const targetPkCol = quoteIdentifier(targetRelationPkSql(targetTable, relation));
377
+ const targetIndex = getTableIndex(runtime.tableIndex, targetTable.accessor);
378
+ const fkCol = childFkColumnMeta(targetTable, relation, targetIndex);
253
379
  const params = [parentId];
254
- let sql = `DELETE FROM ${tableRef(targetTable)} WHERE ${quoteIdentifier(fkCol.sqlName)} = $1`;
255
- if (childIds && childIds.length > 0) {
256
- const placeholders = childIds.map((_, i) => `$${i + 2}`).join(", ");
257
- sql += ` AND ${targetPkCol} IN (${placeholders})`;
258
- params.push(...childIds);
380
+ let sql = `DELETE FROM ${dialect.tableRef(targetTable)} WHERE ${dialect.quoteIdentifier(fkCol.sqlName)} = ${dialect.placeholder(1)}`;
381
+ if (childPks && childPks.length > 0) {
382
+ const predicate = sqlPkPredicate(dialect, targetTable, targetIndex, childPks, 2);
383
+ sql += ` AND ${predicate.sql}`;
384
+ params.push(...predicate.params);
259
385
  }
260
386
  await runQuery(executor, runtime, { operation: "delete", tableAccessor: relation.targetAccessor }, sql, params);
261
387
  }
262
388
  async function listM2MLinkedIds(executor, runtime, m2m, parentAccessor, parentId) {
389
+ const dialect = runtime.dialect ?? postgresDialect;
263
390
  const { manifest } = runtime;
264
391
  const throughTable = manifest.tables[m2m.throughAccessor];
265
392
  if (!throughTable)
@@ -272,10 +399,11 @@ async function listM2MLinkedIds(executor, runtime, m2m, parentAccessor, parentId
272
399
  const otherCol = columnBySqlName(throughIndex, throughTable, otherFkCol);
273
400
  if (!parentCol || !otherCol)
274
401
  return [];
275
- const rows = await runQuery(executor, runtime, { operation: "select", tableAccessor: throughTable.accessor }, `SELECT ${quoteIdentifier(otherCol.sqlName)} FROM ${tableRef(throughTable)} WHERE ${quoteIdentifier(parentCol.sqlName)} = $1`, [parentId]);
402
+ const rows = await runQuery(executor, runtime, { operation: "select", tableAccessor: throughTable.accessor }, `SELECT ${dialect.quoteIdentifier(otherCol.sqlName)} FROM ${dialect.tableRef(throughTable)} WHERE ${dialect.quoteIdentifier(parentCol.sqlName)} = ${dialect.placeholder(1)}`, [parentId]);
276
403
  return rows.map((row) => String(row[otherCol.sqlName] ?? row[otherCol.tsName]));
277
404
  }
278
- async function deleteM2MRelated(executor, runtime, m2m, tableAccessor, parentId, relatedIds) {
405
+ async function deleteM2MRelated(executor, runtime, m2m, tableAccessor, parentId, relatedIds, targetPks) {
406
+ const dialect = runtime.dialect ?? postgresDialect;
279
407
  const { manifest } = runtime;
280
408
  const isLeft = m2m.leftAccessor === tableAccessor;
281
409
  const targetAccessor = isLeft ? m2m.rightAccessor : m2m.leftAccessor;
@@ -287,9 +415,22 @@ async function deleteM2MRelated(executor, runtime, m2m, tableAccessor, parentId,
287
415
  if (ids.length === 0)
288
416
  return;
289
417
  await deleteJunctionRows(executor, runtime, m2m, tableAccessor, parentId, ids);
290
- const targetPkCol = quoteIdentifier(primaryKeySqlName(targetTable));
291
- const placeholders = ids.map((_, i) => `$${i + 1}`).join(", ");
292
- await runQuery(executor, runtime, { operation: "delete", tableAccessor: targetAccessor }, `DELETE FROM ${tableRef(targetTable)} WHERE ${targetPkCol} IN (${placeholders})`, ids);
418
+ const targetIndex = getTableIndex(runtime.tableIndex, targetAccessor);
419
+ if (targetPks && targetPks.length > 0) {
420
+ const predicate = sqlPkPredicate(dialect, targetTable, targetIndex, targetPks, 1);
421
+ await runQuery(executor, runtime, { operation: "delete", tableAccessor: targetAccessor }, `DELETE FROM ${dialect.tableRef(targetTable)} WHERE ${predicate.sql}`, predicate.params);
422
+ return;
423
+ }
424
+ const targetPkCol = dialect.quoteIdentifier(primaryKeySqlName(targetTable));
425
+ const placeholders = joinPlaceholders(dialect, ids.length);
426
+ await runQuery(executor, runtime, { operation: "delete", tableAccessor: targetAccessor }, `DELETE FROM ${dialect.tableRef(targetTable)} WHERE ${targetPkCol} IN (${placeholders})`, ids);
427
+ }
428
+ function assertExclusiveConnectOrCreate(value, relationName) {
429
+ if (!("connectOrCreate" in value))
430
+ return;
431
+ if ("connect" in value || "create" in value) {
432
+ compileError(`Relation "${relationName}" cannot mix connectOrCreate with connect or create`, { code: QueryErrorCode.invalid_nested_write });
433
+ }
293
434
  }
294
435
  async function executeToOneWrite(executor, runtime, table, scalarData, relationName, value, runCreate) {
295
436
  const { manifest } = runtime;
@@ -297,19 +438,36 @@ async function executeToOneWrite(executor, runtime, table, scalarData, relationN
297
438
  const rel = findRelation(table, relationName, tableIndex);
298
439
  if (rel?.cardinality !== "one")
299
440
  return;
441
+ const targetTable = manifest.tables[rel.targetAccessor];
442
+ if (!targetTable)
443
+ compileError(`Unknown table: ${rel.targetAccessor}`);
444
+ const targetIndex = getTableIndex(runtime.tableIndex, rel.targetAccessor);
445
+ assertExclusiveConnectOrCreate(value, relationName);
446
+ if ("connectOrCreate" in value) {
447
+ const item = value.connectOrCreate;
448
+ if (!item || typeof item !== "object" || Array.isArray(item)) {
449
+ compileError(`Relation "${relationName}" connectOrCreate requires { where, create }`, { code: QueryErrorCode.invalid_nested_write });
450
+ }
451
+ const { record } = await findOrCreateRecord(executor, runtime, rel.targetAccessor, {
452
+ where: item.where,
453
+ create: item.create,
454
+ });
455
+ assignOutgoingFkScalars(scalarData, rel, targetTable, targetIndex, record);
456
+ return;
457
+ }
300
458
  if ("connect" in value) {
301
- const ids = normalizeConnectIds(runtime, rel.targetAccessor, value.connect);
302
- const id = ids[0];
303
- if (id === undefined) {
459
+ const pks = normalizeConnectPks(runtime, rel.targetAccessor, value.connect);
460
+ const pk = pks[0];
461
+ if (pk === undefined) {
304
462
  compileError(`Relation connect requires a primary key for table "${rel.targetAccessor}"`, {
305
463
  code: QueryErrorCode.missing_primary_key,
306
464
  tableAccessor: rel.targetAccessor,
307
465
  });
308
466
  }
309
- if (ids.length > 1) {
467
+ if (pks.length > 1) {
310
468
  compileError(`Cannot connect more than one record to to-one relation ${relationName}`);
311
469
  }
312
- scalarData[rel.fkColumn] = id;
470
+ assignOutgoingFkScalars(scalarData, rel, targetTable, targetIndex, pk);
313
471
  return;
314
472
  }
315
473
  if ("disconnect" in value) {
@@ -318,17 +476,14 @@ async function executeToOneWrite(executor, runtime, table, scalarData, relationN
318
476
  if (fkCol && !fkCol.nullable) {
319
477
  compileError(`Cannot disconnect relation ${relationName}: FK column is not nullable`);
320
478
  }
321
- scalarData[rel.fkColumn] = null;
479
+ assignOutgoingFkScalars(scalarData, rel, targetTable, targetIndex, {}, true);
322
480
  return;
323
481
  }
324
482
  if ("create" in value) {
325
483
  const created = await runCreate(executor, runtime, rel.targetAccessor, {
326
484
  data: value.create,
327
485
  });
328
- const targetTable = manifest.tables[rel.targetAccessor];
329
- if (!targetTable)
330
- compileError(`Unknown table: ${rel.targetAccessor}`);
331
- scalarData[rel.fkColumn] = rowScalarPkValue(created, targetTable);
486
+ assignOutgoingFkScalars(scalarData, rel, targetTable, targetIndex, created);
332
487
  }
333
488
  }
334
489
  export async function applyToOnePreWrites(executor, runtime, table, scalarData, relationWrites, runCreate) {
@@ -354,8 +509,8 @@ async function executeM2MWrite(executor, runtime, tableAccessor, parentId, relat
354
509
  await deleteM2MRelated(executor, runtime, m2m, tableAccessor, parentId, undefined);
355
510
  }
356
511
  else {
357
- const ids = normalizeConnectIds(runtime, targetAccessor, del);
358
- await deleteM2MRelated(executor, runtime, m2m, tableAccessor, parentId, ids);
512
+ const { pks, ids } = m2mConnectFkValues(runtime, m2m, tableAccessor, targetAccessor, del);
513
+ await deleteM2MRelated(executor, runtime, m2m, tableAccessor, parentId, ids, pks);
359
514
  }
360
515
  }
361
516
  if ("disconnect" in value) {
@@ -364,12 +519,12 @@ async function executeM2MWrite(executor, runtime, tableAccessor, parentId, relat
364
519
  await deleteJunctionRows(executor, runtime, m2m, tableAccessor, parentId);
365
520
  }
366
521
  else {
367
- const ids = normalizeConnectIds(runtime, targetAccessor, disconnect);
522
+ const { ids } = m2mConnectFkValues(runtime, m2m, tableAccessor, targetAccessor, disconnect);
368
523
  await deleteJunctionRows(executor, runtime, m2m, tableAccessor, parentId, ids);
369
524
  }
370
525
  }
371
526
  if ("set" in value) {
372
- const ids = normalizeConnectIds(runtime, targetAccessor, value.set);
527
+ const { ids } = m2mConnectFkValues(runtime, m2m, tableAccessor, targetAccessor, value.set);
373
528
  await deleteJunctionRows(executor, runtime, m2m, tableAccessor, parentId);
374
529
  if (ids.length > 0) {
375
530
  await insertM2MLinks(executor, runtime, m2m, tableAccessor, parentId, ids);
@@ -377,20 +532,24 @@ async function executeM2MWrite(executor, runtime, tableAccessor, parentId, relat
377
532
  return;
378
533
  }
379
534
  if ("connect" in value) {
380
- const ids = normalizeConnectIds(runtime, targetAccessor, value.connect);
535
+ const { ids } = m2mConnectFkValues(runtime, m2m, tableAccessor, targetAccessor, value.connect);
381
536
  if (ids.length > 0) {
382
537
  await insertM2MLinks(executor, runtime, m2m, tableAccessor, parentId, ids);
383
538
  }
384
539
  }
385
540
  if ("connectOrCreate" in value) {
386
541
  const items = value.connectOrCreate;
387
- const ids = await resolveConnectOrCreate(executor, runtime, targetAccessor, items);
542
+ const targetTable = requireTable(runtime.manifest, targetAccessor, "select");
543
+ const targetIndex = getTableIndex(runtime.tableIndex, targetAccessor);
544
+ const throughFk = m2mOtherThroughColumn(runtime, m2m, tableAccessor);
545
+ const fkTs = fkTargetTsName(targetTable, targetIndex, undefined, throughFk);
546
+ const ids = await resolveConnectOrCreate(executor, runtime, targetAccessor, items, fkTs);
388
547
  if (ids.length > 0) {
389
548
  await insertM2MLinks(executor, runtime, m2m, tableAccessor, parentId, ids);
390
549
  }
391
550
  }
392
551
  }
393
- async function executeInverseManyWrite(executor, runtime, table, parentId, relationName, value, runCreate) {
552
+ async function executeInverseManyWrite(executor, runtime, table, parentId, relationName, value, runCreate, parentRow) {
394
553
  const { manifest } = runtime;
395
554
  const rel = findRelation(table, relationName);
396
555
  if (rel?.cardinality !== "many" ||
@@ -403,8 +562,8 @@ async function executeInverseManyWrite(executor, runtime, table, parentId, relat
403
562
  await deleteInverseManyChildren(executor, runtime, rel, parentId, undefined);
404
563
  }
405
564
  else {
406
- const ids = normalizeConnectIds(runtime, rel.targetAccessor, del);
407
- await deleteInverseManyChildren(executor, runtime, rel, parentId, ids);
565
+ const pks = normalizeConnectPks(runtime, rel.targetAccessor, del);
566
+ await deleteInverseManyChildren(executor, runtime, rel, parentId, pks);
408
567
  }
409
568
  }
410
569
  if ("disconnect" in value) {
@@ -413,18 +572,18 @@ async function executeInverseManyWrite(executor, runtime, table, parentId, relat
413
572
  await disconnectInverseMany(executor, runtime, rel, parentId, undefined);
414
573
  }
415
574
  else {
416
- const ids = normalizeConnectIds(runtime, rel.targetAccessor, disconnect);
417
- await disconnectInverseMany(executor, runtime, rel, parentId, ids);
575
+ const pks = normalizeConnectPks(runtime, rel.targetAccessor, disconnect);
576
+ await disconnectInverseMany(executor, runtime, rel, parentId, pks);
418
577
  }
419
578
  }
420
579
  if ("set" in value) {
421
- const ids = normalizeConnectIds(runtime, rel.targetAccessor, value.set);
422
- await setInverseMany(executor, runtime, rel, parentId, ids);
580
+ const pks = normalizeConnectPks(runtime, rel.targetAccessor, value.set);
581
+ await setInverseMany(executor, runtime, rel, parentId, pks, table, parentRow);
423
582
  return;
424
583
  }
425
584
  if ("connect" in value) {
426
- const ids = normalizeConnectIds(runtime, rel.targetAccessor, value.connect);
427
- await connectInverseMany(executor, runtime, rel, parentId, ids);
585
+ const pks = normalizeConnectPks(runtime, rel.targetAccessor, value.connect);
586
+ await connectInverseMany(executor, runtime, rel, parentId, pks, table, parentRow);
428
587
  }
429
588
  if ("create" in value) {
430
589
  const items = normalizeCreateList(value.create);
@@ -432,13 +591,13 @@ async function executeInverseManyWrite(executor, runtime, table, parentId, relat
432
591
  await runCreate(executor, runtime, rel.targetAccessor, {
433
592
  data: {
434
593
  ...item,
435
- [rel.fkColumn]: parentId,
594
+ ...childFkCreatePatch(rel, table, parentRow, parentId),
436
595
  },
437
596
  });
438
597
  }
439
598
  }
440
599
  }
441
- async function executeInverseOneWrite(executor, runtime, table, parentId, relationName, value, runCreate) {
600
+ async function executeInverseOneWrite(executor, runtime, table, parentId, relationName, value, runCreate, parentRow) {
442
601
  const { manifest } = runtime;
443
602
  const rel = findRelation(table, relationName);
444
603
  if (rel?.cardinality !== "one" || tableOwnsFkColumn(table, rel))
@@ -453,8 +612,8 @@ async function executeInverseOneWrite(executor, runtime, table, parentId, relati
453
612
  await deleteInverseManyChildren(executor, runtime, rel, parentId, undefined);
454
613
  }
455
614
  else {
456
- const ids = normalizeConnectIds(runtime, rel.targetAccessor, del);
457
- await deleteInverseManyChildren(executor, runtime, rel, parentId, ids);
615
+ const pks = normalizeConnectPks(runtime, rel.targetAccessor, del);
616
+ await deleteInverseManyChildren(executor, runtime, rel, parentId, pks);
458
617
  }
459
618
  }
460
619
  if ("disconnect" in value) {
@@ -464,23 +623,23 @@ async function executeInverseOneWrite(executor, runtime, table, parentId, relati
464
623
  await disconnectInverseMany(executor, runtime, rel, parentId, undefined);
465
624
  }
466
625
  if ("set" in value) {
467
- const ids = normalizeConnectIds(runtime, rel.targetAccessor, value.set);
468
- const id = ids[0];
469
- if (id) {
626
+ const pks = normalizeConnectPks(runtime, rel.targetAccessor, value.set);
627
+ const pk = pks[0];
628
+ if (pk) {
470
629
  await disconnectInverseMany(executor, runtime, rel, parentId, undefined);
471
- await connectInverseMany(executor, runtime, rel, parentId, [id]);
630
+ await connectInverseMany(executor, runtime, rel, parentId, [pk], table, parentRow);
472
631
  }
473
632
  return;
474
633
  }
475
634
  if ("connect" in value) {
476
- const ids = normalizeConnectIds(runtime, rel.targetAccessor, value.connect);
477
- const id = ids[0];
478
- if (!id)
635
+ const pks = normalizeConnectPks(runtime, rel.targetAccessor, value.connect);
636
+ const pk = pks[0];
637
+ if (!pk)
479
638
  return;
480
- if (ids.length > 1) {
639
+ if (pks.length > 1) {
481
640
  compileError(`Cannot connect more than one record to one-to-one relation ${relationName}`);
482
641
  }
483
- await connectInverseMany(executor, runtime, rel, parentId, [id]);
642
+ await connectInverseMany(executor, runtime, rel, parentId, [pk], table, parentRow);
484
643
  }
485
644
  if ("create" in value) {
486
645
  const items = normalizeCreateList(value.create);
@@ -492,13 +651,13 @@ async function executeInverseOneWrite(executor, runtime, table, parentId, relati
492
651
  await runCreate(executor, runtime, rel.targetAccessor, {
493
652
  data: {
494
653
  ...item,
495
- [rel.fkColumn]: parentId,
654
+ ...childFkCreatePatch(rel, table, parentRow, parentId),
496
655
  },
497
656
  });
498
657
  }
499
658
  }
500
659
  }
501
- export async function executeRelationWrites(executor, runtime, tableAccessor, parentId, relationWrites, runCreate) {
660
+ export async function executeRelationWrites(executor, runtime, tableAccessor, parentId, relationWrites, runCreate, parentRow) {
502
661
  const { manifest } = runtime;
503
662
  const table = requireTable(manifest, tableAccessor, "select");
504
663
  for (const write of relationWrites) {
@@ -511,11 +670,11 @@ export async function executeRelationWrites(executor, runtime, tableAccessor, pa
511
670
  continue;
512
671
  if (rel.cardinality === "one") {
513
672
  if (!tableOwnsFkColumn(table, rel)) {
514
- await executeInverseOneWrite(executor, runtime, table, parentId, write.relationName, write.value, runCreate);
673
+ await executeInverseOneWrite(executor, runtime, table, parentId, write.relationName, write.value, runCreate, parentRow);
515
674
  }
516
675
  continue;
517
676
  }
518
- await executeInverseManyWrite(executor, runtime, table, parentId, write.relationName, write.value, runCreate);
677
+ await executeInverseManyWrite(executor, runtime, table, parentId, write.relationName, write.value, runCreate, parentRow);
519
678
  }
520
679
  }
521
680
  export function hasPostRelationWrites(table, manifest, tableAccessor, relationWrites) {