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
package/docs/relations.md CHANGED
@@ -6,13 +6,13 @@
6
6
 
7
7
  | Relation kind | Operations |
8
8
  |---------------|------------|
9
- | **To-one** (outgoing FK) | `connect`, `create`, `disconnect` (nullable FK only) |
9
+ | **To-one** (outgoing FK) | `connect`, `connectOrCreate`, `create`, `disconnect` (nullable FK only) |
10
10
  | **One-to-many** (inverse) | `create`, `connect`, `disconnect`, `set`, `delete` |
11
11
  | **Many-to-many** | `connect`, `connectOrCreate`, `disconnect`, `set`, `delete` |
12
12
 
13
- `connect`, `set`, `disconnect`, and `delete` identify related rows by the **target table's scalar primary key** (`{ id: ... }` when the PK is `id`, `{ userId: ... }` when it is `userId`). Composite-PK connect is not supported.
13
+ `connect`, `set`, `disconnect`, and `delete` identify related rows by the **target table's primary key**: `{ id: ... }` or `{ userId: ... }` for a scalar PK, or an object with **every** PK column for a composite key. A single-column `fk()` still stores one referenced value; a composite `foreignKey()` extra assigns **each** local column from the matching target field (never a concatenated PK string).
14
14
 
15
- A relation field must be a **pure write bag**: every key is one of those operations. Mixing a write op with extra fields (`{ create: { name: "A" }, foo: 1 }`), passing a scalar, or passing `{}` throws `invalid_nested_write` — the parent row is not written.
15
+ A relation field must be a **pure write bag**: every key is one of those operations. Mixing a write op with extra fields (`{ create: { name: "A" }, foo: 1 }`), passing a scalar, or passing `{}` throws `invalid_nested_write` — the parent row is not written. To-one `connectOrCreate` cannot be mixed with `connect` or `create`.
16
16
 
17
17
  ## Examples
18
18
 
@@ -21,7 +21,22 @@ A relation field must be a **pure write bag**: every key is one of those operati
21
21
  ```ts
22
22
  await db.posts.update({
23
23
  where: { id: postId },
24
- data: { author: { connect: { id: userId } } },
24
+ data: {
25
+ author: { connect: { id: userId } },
26
+ // or create the author if missing:
27
+ // author: { connectOrCreate: { where: { email }, create: { email, password } } },
28
+ },
29
+ });
30
+ ```
31
+
32
+ Composite primary key:
33
+
34
+ ```ts
35
+ await db.orders.update({
36
+ where: { id: orderId },
37
+ data: {
38
+ lines: { connect: [{ tenantId: "acme", lineNo: 1 }] },
39
+ },
25
40
  });
26
41
  ```
27
42
 
package/docs/schema.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Schema DSL
2
2
 
3
- NeoOrm **0.8.0** uses accessor-based identity: schema keys, `fk("users")`, `many("tags")`, and `through: "postTags"` all refer to **accessors**, not raw SQL names. `schemaToManifest` resolves accessors to SQL before migrations and the typed client are generated.
3
+ NeoOrm **0.8.0** and later uses accessor-based identity: schema keys, `fk("users")`, `many("tags")`, and `through: "postTags"` all refer to **accessors**, not raw SQL names. `schemaToManifest` resolves accessors to SQL before migrations and the typed client are generated.
4
4
 
5
5
  ## Tables and accessors
6
6
 
@@ -48,10 +48,21 @@ Column field names use camelCase in TypeScript. By default SQL column names are
48
48
  | `decimal()` / `numeric()` | `NUMERIC` | `string \| null` | Use strings to avoid float loss |
49
49
  | `enumType(["a", "b"])` | mode-dependent | union literals | See [Enum columns](#enum-columns) |
50
50
  | `bytea()` | `BYTEA` | `Buffer \| null` | |
51
- | `textArray()` / `intArray()` | arrays | arrays \| null | |
51
+ | `textArray()` / `intArray()` | arrays | arrays \| null | JSON on SQLite/MySQL |
52
+ | `uuidArray()` | `UUID[]` | `string[] \| null` | JSON on SQLite/MySQL |
53
+ | `enumArray(["a", "b"])` | `TEXT[]` or `name[]` | union arrays \| null | Same enum storage mode as `enumType`; JSON on SQLite/MySQL |
54
+ | `real()` / `float()` | `REAL` | `number \| null` | 32-bit. Prisma `Float` is `double()`. MySQL `FLOAT`, SQLite `REAL` |
55
+ | `double()` | `DOUBLE PRECISION` | `number \| null` | MySQL `DOUBLE`, SQLite `REAL` |
56
+ | `date()` | `DATE` | `string \| null` | `YYYY-MM-DD`, not `Date`. SQLite `TEXT`, MySQL `DATE` |
57
+ | `time()` | `TIME` | `string \| null` | SQLite `TEXT`, MySQL `TIME` |
58
+ | `interval()` | `INTERVAL` | `string \| null` | SQLite `TEXT`; rejected on MySQL/MariaDB |
59
+ | `inet()` / `cidr()` | `INET` / `CIDR` | `string \| null` | SQLite `TEXT`; rejected on MySQL/MariaDB |
60
+ | `xml()` | `XML` | `string \| null` | MySQL `LONGTEXT`, SQLite `TEXT` |
61
+ | `money()` | `MONEY` | `string \| null` | MySQL `DECIMAL(19,4)`, SQLite `TEXT` |
62
+ | `int4Range()` / `int8Range()` / `numRange()` / `tsRange()` / `tstzRange()` / `dateRange()` | matching PG ranges | `string \| null` | PostgreSQL only (rejected on SQLite and MySQL/MariaDB) |
52
63
  | `citext()` | `CITEXT` | `string \| null` | Requires `citext` extension |
53
64
 
54
- All column builders support `.notNull()`, `.unique()`, `.default(value)`, `.primary()`, `.map(name)`, `.hidden()`, `.index()`, and `.check("sql expression")`. Text columns add `.maxLength()`, `.minLength()`, `.notEmpty()`, `.email()`, and `.url()`. Numeric columns (`int`, `bigint`, `serial`, `decimal`) add `.min()`, `.max()`, and `.positive()`.
65
+ All column builders support `.notNull()`, `.unique()`, `.default(value)`, `.primary()`, `.map(name)`, `.hidden()`, `.index()`, and `.check("sql expression")`. Text columns add `.maxLength()`, `.minLength()`, `.notEmpty()`, `.email()`, and `.url()`. Numeric columns (`int`, `bigint`, `serial`, `decimal`, `real`, `double`) add `.min()`, `.max()`, and `.positive()`.
55
66
 
56
67
  `.hidden()` marks a column as sensitive. It is omitted from default query output on the root table and on nested `with` includes. Pass `includeHidden: true` when the app needs the value (for example password verification on login). Use `.strip()` to remove any remaining sensitive fields before JSON responses.
57
68
 
@@ -100,7 +111,9 @@ Fluent modifiers (no options bag):
100
111
  |--------|--------|
101
112
  | `.as("author")` | override relation name on this table (default: strip `Id` from column name) |
102
113
  | `.inverse("articles")` | override relation name on the target table (rare — see defaults below) |
103
- | `.onDelete("cascade" \| "restrict" \| "set null" \| "no action")` | FK action |
114
+ | `.onDelete("cascade" \| "restrict" \| "set null" \| "no action")` | FK `ON DELETE` |
115
+ | `.onUpdate("cascade" \| "restrict" \| "set null" \| "no action")` | FK `ON UPDATE` |
116
+ | `.deferrable("immediate" \| "deferred")` | `DEFERRABLE` (Postgres and SQLite; rejected on MySQL/MariaDB) |
104
117
  | `.notNull()` | `NOT NULL` |
105
118
  | `.unique()` | `UNIQUE` — unique FKs infer a **singular** inverse (`profiles.userId` → `users.profile`) |
106
119
  | `.primary()` | part of composite PK |
@@ -123,6 +136,39 @@ postTags: table("post_tags", {
123
136
 
124
137
  Multiple `.primary()` columns infer a composite key. `primaryKey(t.colA, t.colB)` in extras is optional when you want to name the key without marking every column.
125
138
 
139
+ ### Composite foreign keys
140
+
141
+ Use table extras `foreignKey()` when several local columns form one constraint (and one relation). Do not also mark those columns `fk()`.
142
+
143
+ ```ts
144
+ orders: table(
145
+ {
146
+ id: id(),
147
+ tenantId: text().notNull(),
148
+ userId: text().notNull(),
149
+ },
150
+ (t) => [
151
+ foreignKey(t.tenantId, t.userId)
152
+ .references("users", "tenantId", "id")
153
+ .as("user")
154
+ .inverse("orders")
155
+ .onDelete("cascade")
156
+ .onUpdate("cascade"),
157
+ ],
158
+ ),
159
+ ```
160
+
161
+ The target column list must match a primary key or unique index. `.as()` and `.inverse()` are required. Connect still uses the target table's full primary key:
162
+
163
+ ```ts
164
+ await db.orders.create({
165
+ data: {
166
+ tenantId: "acme",
167
+ user: { connect: { tenantId: "acme", id: userId } },
168
+ },
169
+ });
170
+ ```
171
+
126
172
  ### Self-relations
127
173
 
128
174
  ```ts
@@ -148,7 +194,7 @@ export const schema = defineSchema({
148
194
 
149
195
  ## Column checks
150
196
 
151
- Use `.check("sql expression")` for custom CHECK constraints, or the typed helpers below. Helpers compile to database CHECK constraints (and `VARCHAR(n)` for text length on Postgres). They are not runtime validators by themselves. With [`generate.zod`](zod.md) or [`generate.typebox`](typebox.md), the same helpers are copied into generated validation schemas at your API boundary.
197
+ Use `.check("sql expression")` for custom CHECK constraints, or the typed helpers below. Helpers compile to database CHECK constraints (and `VARCHAR(n)` for text length on Postgres). They are not runtime validators by themselves. With [`generate.zod`](zod.md), [`generate.typebox`](typebox.md), or [`generate.elysia`](elysia.md), the same helpers are copied into generated validation schemas at your API boundary.
152
198
 
153
199
  ### Typed constraint helpers
154
200
 
@@ -172,7 +218,7 @@ views: int().notNull().min(0)
172
218
  price: decimal({ precision: 10, scale: 2 }).notNull().positive()
173
219
  ```
174
220
 
175
- `.email()` and `.url()` are validation-only: they do not emit a SQL CHECK. With [`generate.zod`](zod.md) or [`generate.typebox`](typebox.md), columns named `email` or ending in `Email` (`contactEmail`) become email-format strings, and columns named `url` or ending in `Url` (`avatarUrl`) become URL-format strings. You can also mark any `text` / `citext` column with `.email()` or `.url()`. Foreign keys follow the **referenced** column (`authorEmail` pointing at a uuid PK stays a uuid).
221
+ `.email()` and `.url()` are validation-only: they do not emit a SQL CHECK. With [`generate.zod`](zod.md), [`generate.typebox`](typebox.md), or [`generate.elysia`](elysia.md), columns named `email` or ending in `Email` (`contactEmail`) become email-format strings, and columns named `url` or ending in `Url` (`avatarUrl`) become URL-format strings. You can also mark any `text` / `citext` column with `.email()` or `.url()`. Foreign keys follow the **referenced** column (`authorEmail` pointing at a uuid PK stays a uuid).
176
222
 
177
223
  `citext` length helpers use CHECK only (no `VARCHAR`). NULL still bypasses CHECK — pair `.notEmpty()` with `.notNull()` to reject empty strings.
178
224
 
@@ -200,7 +246,24 @@ posts: table(
200
246
  ),
201
247
  ```
202
248
 
203
- Helpers: `unique(...cols)`, `index(...cols)`, `primaryKey(...cols)`. `unique()` and `index()` both support `.where()` for partial indexes.
249
+ Helpers: `unique(...cols)`, `index(...cols)`, `primaryKey(...cols)`, `expr("sql")`. `unique()` and `index()` support `.using()`, `.ops()`, and `.where()` for partial indexes.
250
+
251
+ ### Index methods and expressions
252
+
253
+ ```ts
254
+ (t) => [
255
+ index(t.tags).using("gin"),
256
+ index(t.metadata).using("gin").ops("jsonb_path_ops"),
257
+ index(t.location).using("gist"),
258
+ index(t.createdAt).using("brin"),
259
+ unique(expr("lower(email)")),
260
+ index(t.authorId, expr("date_trunc('day', created_at)")),
261
+ ],
262
+ ```
263
+
264
+ Default method is btree (`USING btree` is omitted in SQL). Postgres also emits `gin`, `gist`, `brin`, and `hash`. SQLite allows expression keys and partial `WHERE`, but not those access methods. MySQL/MariaDB allow `USING HASH` and functional `(expr)` keys; they reject GIN/GiST/BRIN and partial `WHERE`.
265
+
266
+ `unique()` cannot use `gin` / `gist` / `brin`. Expression unique indexes are not `findUnique` / `upsert` targets.
204
267
 
205
268
  ### Partial indexes
206
269
 
@@ -211,7 +274,7 @@ Helpers: `unique(...cols)`, `index(...cols)`, `primaryKey(...cols)`. `unique()`
211
274
  ],
212
275
  ```
213
276
 
214
- Equality map of column refs → values; compiled to `WHERE "published" = true` (or `= 1` on SQLite). Partial uniques emit as `CREATE UNIQUE INDEX ... WHERE ...`, not table-level `UNIQUE (...)`. They are not usable as `findUnique` / `upsert` targets.
277
+ Equality map of column refs → values; compiled to `WHERE "published" = true` (or `= 1` on SQLite). Partial uniques emit as `CREATE UNIQUE INDEX ... WHERE ...`, not table-level `UNIQUE (...)`. They are valid `findUnique` / `upsert` / `findOrCreate` targets: `where` uses the indexed columns, and the index predicate is applied automatically (`AND` on lookups, `ON CONFLICT (…) WHERE …` on Postgres and SQLite).
215
278
 
216
279
  ## Many-to-many
217
280
 
@@ -282,7 +345,7 @@ status: enumType(["draft", "published", "archived"])
282
345
  .default("draft"),
283
346
  ```
284
347
 
285
- `datasource.enum` in config: `check` (default), `union`, or `native` (PostgreSQL only).
348
+ `datasource.enum` in config: `check` (default), `union`, or `native` (PostgreSQL `CREATE TYPE` / MySQL and MariaDB column `ENUM`).
286
349
 
287
350
  ## PostgreSQL extensions
288
351
 
@@ -297,4 +360,4 @@ Column type plugins still register required extensions automatically.
297
360
 
298
361
  ## SQLite type mapping
299
362
 
300
- Same DSL; see [SQLite](sqlite.md) for storage types and limitations.
363
+ Same DSL; see [SQLite](sqlite.md), [MySQL](mysql.md), and [MariaDB](mariadb.md) for storage types and limitations.
package/docs/sqlite.md CHANGED
@@ -103,9 +103,11 @@ bunx neoorm migrate reset --force
103
103
 
104
104
  | Schema builder | SQLite storage |
105
105
  |----------------|----------------|
106
- | `id`, `text`, `uuid`, `json`, `jsonb`, `decimal`, `textArray`, `intArray`, `citext`, `enumType` | `TEXT` |
106
+ | `id`, `text`, `uuid`, `json`, `jsonb`, `decimal`, `textArray`, `intArray`, `uuidArray`, `enumArray`, `citext`, `enumType`, `date`, `time`, `interval`, `inet`, `cidr`, `xml`, `money` | `TEXT` |
107
107
  | `int`, `serial` | `INTEGER` |
108
+ | `real`, `double` | `REAL` |
108
109
  | `bigint` | `TEXT` |
110
+ | `int4Range` … `dateRange` | rejected at schema compile |
109
111
  | `serial().primary()` | `INTEGER PRIMARY KEY AUTOINCREMENT` |
110
112
  | `bool` | `BOOLEAN` (stored as 0/1) |
111
113
  | `timestamp` | `TEXT` (ISO-8601) |
@@ -118,9 +120,11 @@ bunx neoorm migrate reset --force
118
120
 
119
121
  | Feature | PostgreSQL | SQLite |
120
122
  |---------|-----------|--------|
121
- | `distinct` (`DISTINCT ON`) | supported | throws `distinct is not supported on SQLite` |
123
+ | `distinct` (`DISTINCT ON`) | supported | `ROW_NUMBER()` per distinct columns (same `orderBy` prefix rule) |
124
+ | `search` | POSIX `~` / `~*` | JavaScript `RegExp` via `REGEXP` / `regexp_i` |
122
125
  | `datasource.schema` | multi-schema | not applicable |
123
126
  | `enum: "native"` | `CREATE TYPE ... AS ENUM` | not applicable (TEXT + CHECK) |
127
+ | range types | supported | rejected at schema compile |
124
128
  | transaction options (`readOnly`, `isolationLevel`) | `BEGIN READ ONLY` / `ISOLATION LEVEL` | `readOnly` → `PRAGMA query_only`; `RepeatableRead`/`Serializable` → `BEGIN IMMEDIATE`; other isolation → `BEGIN` |
125
129
  | JSON operators | `@>`, `?`, `#>` | `json_patch` / `json_each` / `json_extract` |
126
130
 
package/docs/typebox.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # TypeBox schemas
2
2
 
3
- `neoorm generate` can print Select, Create, and Update **scalar** TypeBox schemas next to the typed client. Codegen maps your schema to a validator-neutral IR first; TypeBox is the second printer (alongside [Zod](zod.md)).
3
+ `neoorm generate` can print Select, Create, and Update **scalar** TypeBox schemas next to the typed client. Codegen maps your schema to a validator-neutral IR first; TypeBox 1.x is one printer (alongside [Zod](zod.md) and [Elysia `t`](elysia.md)).
4
4
 
5
5
  Generated schemas match the TypeScript shapes of row / insert / update scalars — not nested relation writes (`connect`, `create`, `set`). Those stay TypeScript-only.
6
6
 
7
- Schemas target **TypeBox 1.x** (`typebox` on npm), not `@sinclair/typebox` 0.x.
7
+ Schemas target **TypeBox 1.x** (`typebox` on npm), not `@sinclair/typebox` 0.x. For Elysia 1.x route `body:`, use [`generate.elysia`](elysia.md) instead.
8
8
 
9
9
  ## Enable
10
10
 
@@ -40,7 +40,7 @@ Disable `generate.typebox` and generate again to remove `typebox.ts`.
40
40
 
41
41
  `typebox` is an optional peer of NeoOrm. The generated file imports `typebox` directly; NeoOrm does not bundle it. If `generate.typebox` is on and `typebox` is not installed, `neoorm generate` still writes `typebox.ts` and prints a warning (`bun add typebox`).
42
42
 
43
- You can enable Zod and TypeBox together. When both are on, `client.ts` keeps Zod as a flat `export *` and re-exports TypeBox as `export * as typebox from "./typebox.js"` so names do not collide. Import TypeBox from `./typebox.js` (or `typebox.UserCreateSchema` from the client) in that case.
43
+ You can enable Zod, TypeBox, and Elysia together. When Zod is on, `client.ts` keeps Zod as a flat `export *` and namespaces TypeBox and Elysia (`export * as typebox` / `export * as elysia`). TypeBox + Elysia without Zod keeps TypeBox flat and namespaces Elysia. Import TypeBox from `./typebox.js` (or `typebox.UserCreateSchema` from the client) when it is namespaced. For Elysia 1.x `body:`, use [`generate.elysia`](elysia.md).
44
44
 
45
45
  ## Usage
46
46
 
@@ -115,7 +115,7 @@ Typed schema helpers map into TypeBox:
115
115
  | `timestamp()` | `Date` or ISO datetime string → `Date` (`Type.Codec` + `Value.Decode`) |
116
116
  | `bytea()` | `Type.Refine` + `Buffer.isBuffer` |
117
117
 
118
- Raw `.check("sql")` is not mapped. With `generate.typebox: true` (or `generate.zod: true`), codegen reads inline `json()` / `jsonb()` type arguments from `schema.ts` and maps object literals to `Type.Object`, `Record<K,V>` to `Type.Record`, and primitives to the matching TypeBox types. Type aliases and imported types are not resolved yet — use an inline type or `.schema()` for those.
118
+ Raw `.check("sql")` is not mapped. With `generate.typebox: true` (or `generate.zod` / `generate.elysia`), codegen reads inline `json()` / `jsonb()` type arguments from `schema.ts` and maps object literals to `Type.Object`, `Record<K,V>` to `Type.Record`, and primitives to the matching TypeBox types. Type aliases and imported types are not resolved yet — use an inline type or `.schema()` for those.
119
119
 
120
120
  ```ts
121
121
  metadata: jsonb<{ featured: boolean; category?: string }>(),
package/docs/zod.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Zod schemas
2
2
 
3
- `neoorm generate` can print Select, Create, and Update **scalar** Zod schemas next to the typed client. Codegen maps your schema to a validator-neutral IR first; Zod and [TypeBox](typebox.md) are the printers shipped today.
3
+ `neoorm generate` can print Select, Create, and Update **scalar** Zod schemas next to the typed client. Codegen maps your schema to a validator-neutral IR first; Zod, [TypeBox](typebox.md), and [Elysia `t`](elysia.md) are the printers shipped today.
4
4
 
5
5
  Generated schemas match the TypeScript shapes of row / insert / update scalars — not nested relation writes (`connect`, `create`, `set`). Those stay TypeScript-only.
6
6
 
@@ -104,7 +104,7 @@ Typed schema helpers map into Zod:
104
104
  | `json()` / `jsonb()` with `.schema()` validation IR | same as IR (`z.object`, nested `z.record`, …); wins over generics |
105
105
  | `timestamp()` | `Date` or ISO datetime string → `Date` |
106
106
 
107
- Raw `.check("sql")` is not mapped. With `generate.zod: true` or `generate.typebox: true`, codegen reads inline `json()` / `jsonb()` type arguments from `schema.ts` and maps object literals to `z.object`, `Record<K,V>` to `z.record`, and primitives to the matching Zod types. Type aliases and imported types are not resolved yet — use an inline type or `.schema()` for those.
107
+ Raw `.check("sql")` is not mapped. With `generate.zod: true`, `generate.typebox: true`, or `generate.elysia: true`, codegen reads inline `json()` / `jsonb()` type arguments from `schema.ts` and maps object literals to `z.object`, `Record<K,V>` to `z.record`, and primitives to the matching Zod types. Type aliases and imported types are not resolved yet — use an inline type or `.schema()` for those.
108
108
 
109
109
  ```ts
110
110
  metadata: jsonb<{ featured: boolean; category?: string }>(),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "neoorm",
3
- "version": "0.8.1",
4
- "description": "TypeScript-first PostgreSQL and SQLite ORM with schema DSL, codegen, and typed relations",
3
+ "version": "0.8.2",
4
+ "description": "TypeScript-first PostgreSQL, SQLite, MySQL, and MariaDB ORM with schema DSL, codegen, and typed relations",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -67,6 +67,8 @@
67
67
  "postgresql",
68
68
  "postgres",
69
69
  "sqlite",
70
+ "mysql",
71
+ "mariadb",
70
72
  "typescript",
71
73
  "schema",
72
74
  "codegen",
@@ -88,16 +90,30 @@
88
90
  "@biomejs/biome": "2.5.2",
89
91
  "@types/node": "^26.1.0",
90
92
  "@types/pg": "^8.20.0",
93
+ "mysql2": "^3.15.3",
94
+ "mariadb": "^3.4.5",
91
95
  "typebox": "^1.3.31",
92
96
  "typescript": "^7.0.2",
93
97
  "vitest": "^4.1.9",
94
98
  "zod": "^4.1.5"
95
99
  },
96
100
  "peerDependencies": {
101
+ "elysia": ">=1.2.0",
102
+ "mysql2": ">=3.0.0",
103
+ "mariadb": ">=3.0.0",
97
104
  "typebox": "^1.0.0",
98
105
  "zod": "^4.0.0"
99
106
  },
100
107
  "peerDependenciesMeta": {
108
+ "elysia": {
109
+ "optional": true
110
+ },
111
+ "mysql2": {
112
+ "optional": true
113
+ },
114
+ "mariadb": {
115
+ "optional": true
116
+ },
101
117
  "typebox": {
102
118
  "optional": true
103
119
  },