neoorm 0.1.5 → 0.2.1
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.
- package/README.md +246 -23
- package/dist/bin/neoorm.js +70 -4
- package/dist/bin/neoorm.js.map +1 -1
- package/dist/codegen/diff-manifest.d.ts +3 -0
- package/dist/codegen/diff-manifest.d.ts.map +1 -1
- package/dist/codegen/diff-manifest.js +15 -0
- package/dist/codegen/diff-manifest.js.map +1 -1
- package/dist/codegen/emit-includes.d.ts.map +1 -1
- package/dist/codegen/emit-includes.js +7 -1
- package/dist/codegen/emit-includes.js.map +1 -1
- package/dist/codegen/emit-models.d.ts.map +1 -1
- package/dist/codegen/emit-models.js +28 -6
- package/dist/codegen/emit-models.js.map +1 -1
- package/dist/codegen/generate.d.ts +10 -4
- package/dist/codegen/generate.d.ts.map +1 -1
- package/dist/codegen/generate.js +22 -10
- package/dist/codegen/generate.js.map +1 -1
- package/dist/codegen/schema-to-manifest.d.ts +2 -3
- package/dist/codegen/schema-to-manifest.d.ts.map +1 -1
- package/dist/codegen/schema-to-manifest.js +25 -13
- package/dist/codegen/schema-to-manifest.js.map +1 -1
- package/dist/dialect/types.d.ts +2 -0
- package/dist/dialect/types.d.ts.map +1 -1
- package/dist/index.d.ts +8 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/init/scaffold.d.ts +19 -0
- package/dist/init/scaffold.d.ts.map +1 -0
- package/dist/init/scaffold.js +92 -0
- package/dist/init/scaffold.js.map +1 -0
- package/dist/init/templates.d.ts +4 -0
- package/dist/init/templates.d.ts.map +1 -0
- package/dist/init/templates.js +44 -0
- package/dist/init/templates.js.map +1 -0
- package/dist/introspect/pull.d.ts.map +1 -1
- package/dist/introspect/pull.js +18 -7
- package/dist/introspect/pull.js.map +1 -1
- package/dist/migrate/runner.d.ts +5 -0
- package/dist/migrate/runner.d.ts.map +1 -1
- package/dist/migrate/runner.js +67 -1
- package/dist/migrate/runner.js.map +1 -1
- package/dist/plugins/builtin.d.ts.map +1 -1
- package/dist/plugins/builtin.js +6 -0
- package/dist/plugins/builtin.js.map +1 -1
- package/dist/plugins/json/operators.d.ts +3 -0
- package/dist/plugins/json/operators.d.ts.map +1 -0
- package/dist/plugins/json/operators.js +65 -0
- package/dist/plugins/json/operators.js.map +1 -0
- package/dist/plugins/types.d.ts +1 -0
- package/dist/plugins/types.d.ts.map +1 -1
- package/dist/runtime/client.d.ts +30 -3
- package/dist/runtime/client.d.ts.map +1 -1
- package/dist/runtime/client.js +46 -27
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/errors.d.ts +20 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/errors.js +68 -0
- package/dist/runtime/errors.js.map +1 -0
- package/dist/runtime/pg-error.d.ts +19 -0
- package/dist/runtime/pg-error.d.ts.map +1 -0
- package/dist/runtime/pg-error.js +110 -0
- package/dist/runtime/pg-error.js.map +1 -0
- package/dist/runtime/query/aggregate.d.ts +11 -0
- package/dist/runtime/query/aggregate.d.ts.map +1 -0
- package/dist/runtime/query/aggregate.js +44 -0
- package/dist/runtime/query/aggregate.js.map +1 -0
- package/dist/runtime/query/compile.d.ts +15 -5
- package/dist/runtime/query/compile.d.ts.map +1 -1
- package/dist/runtime/query/compile.js +72 -13
- package/dist/runtime/query/compile.js.map +1 -1
- package/dist/runtime/query/count.d.ts +3 -3
- package/dist/runtime/query/count.d.ts.map +1 -1
- package/dist/runtime/query/count.js +7 -4
- package/dist/runtime/query/count.js.map +1 -1
- package/dist/runtime/query/create.d.ts +7 -4
- package/dist/runtime/query/create.d.ts.map +1 -1
- package/dist/runtime/query/create.js +33 -16
- package/dist/runtime/query/create.js.map +1 -1
- package/dist/runtime/query/cursor-codec.d.ts +3 -0
- package/dist/runtime/query/cursor-codec.d.ts.map +1 -0
- package/dist/runtime/query/cursor-codec.js +27 -0
- package/dist/runtime/query/cursor-codec.js.map +1 -0
- package/dist/runtime/query/cursor.d.ts +22 -0
- package/dist/runtime/query/cursor.d.ts.map +1 -0
- package/dist/runtime/query/cursor.js +84 -0
- package/dist/runtime/query/cursor.js.map +1 -0
- package/dist/runtime/query/delete.d.ts +4 -4
- package/dist/runtime/query/delete.d.ts.map +1 -1
- package/dist/runtime/query/delete.js +11 -7
- package/dist/runtime/query/delete.js.map +1 -1
- package/dist/runtime/query/execute.d.ts +16 -0
- package/dist/runtime/query/execute.d.ts.map +1 -0
- package/dist/runtime/query/execute.js +74 -0
- package/dist/runtime/query/execute.js.map +1 -0
- package/dist/runtime/query/find.d.ts +7 -5
- package/dist/runtime/query/find.d.ts.map +1 -1
- package/dist/runtime/query/find.js +142 -25
- package/dist/runtime/query/find.js.map +1 -1
- package/dist/runtime/query/paginate.d.ts +17 -0
- package/dist/runtime/query/paginate.d.ts.map +1 -0
- package/dist/runtime/query/paginate.js +35 -0
- package/dist/runtime/query/paginate.js.map +1 -0
- package/dist/runtime/query/relation-writes.d.ts +5 -4
- package/dist/runtime/query/relation-writes.d.ts.map +1 -1
- package/dist/runtime/query/relation-writes.js +117 -38
- package/dist/runtime/query/relation-writes.js.map +1 -1
- package/dist/runtime/query/update.d.ts +4 -4
- package/dist/runtime/query/update.d.ts.map +1 -1
- package/dist/runtime/query/update.js +63 -21
- package/dist/runtime/query/update.js.map +1 -1
- package/dist/runtime/query/updated-at.d.ts +6 -0
- package/dist/runtime/query/updated-at.d.ts.map +1 -0
- package/dist/runtime/query/updated-at.js +21 -0
- package/dist/runtime/query/updated-at.js.map +1 -0
- package/dist/runtime/query/upsert.d.ts +2 -2
- package/dist/runtime/query/upsert.d.ts.map +1 -1
- package/dist/runtime/query/upsert.js +12 -8
- package/dist/runtime/query/upsert.js.map +1 -1
- package/dist/runtime/types.d.ts +19 -10
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/schema/column-where.d.ts +14 -1
- package/dist/schema/column-where.d.ts.map +1 -1
- package/dist/schema/column.d.ts +4 -0
- package/dist/schema/column.d.ts.map +1 -1
- package/dist/schema/column.js +6 -0
- package/dist/schema/column.js.map +1 -1
- package/dist/schema/define-schema.d.ts +6 -2
- package/dist/schema/define-schema.d.ts.map +1 -1
- package/dist/schema/define-schema.js +5 -2
- package/dist/schema/define-schema.js.map +1 -1
- package/dist/schema/index.d.ts +3 -3
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/nested-relation-types.d.ts +1 -0
- package/dist/schema/nested-relation-types.d.ts.map +1 -1
- package/dist/schema/relation-types.d.ts +42 -0
- package/dist/schema/relation-types.d.ts.map +1 -1
- package/dist/schema/table.d.ts +7 -1
- package/dist/schema/table.d.ts.map +1 -1
- package/dist/schema/table.js +6 -2
- package/dist/schema/table.js.map +1 -1
- package/dist/schema/types.d.ts +60 -3
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/utils/case.d.ts +2 -0
- package/dist/utils/case.d.ts.map +1 -1
- package/dist/utils/case.js +14 -0
- package/dist/utils/case.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,44 @@ Requires Node.js 20+ and PostgreSQL.
|
|
|
12
12
|
|
|
13
13
|
## Quick start
|
|
14
14
|
|
|
15
|
-
**1.
|
|
15
|
+
**1. Scaffold a new project**
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx neoorm init
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
This creates `neoorm.config.ts`, `schema.ts`, `.env.example`, generates `neoorm/client.ts` (and related files), and writes the first migration under `neoorm/migrations/`.
|
|
22
|
+
|
|
23
|
+
**2. Set your database URL**
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
cp .env.example .env
|
|
27
|
+
# edit DATABASE_URL in .env
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**3. Apply migrations**
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx neoorm migrate deploy
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**4. Query**
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { db } from "./neoorm/client.js";
|
|
40
|
+
|
|
41
|
+
const user = await db.users.findById(userId, {
|
|
42
|
+
with: {
|
|
43
|
+
posts: { orderBy: { createdAt: "desc" }, limit: 10 },
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Manual setup
|
|
49
|
+
|
|
50
|
+
If you prefer to write files yourself instead of `neoorm init`:
|
|
51
|
+
|
|
52
|
+
**Define a schema** (`schema.ts`):
|
|
16
53
|
|
|
17
54
|
```ts
|
|
18
55
|
import { defineSchema, table, uuid, text, timestamp, fk } from "neoorm/schema";
|
|
@@ -56,18 +93,6 @@ npx neoorm generate
|
|
|
56
93
|
|
|
57
94
|
This writes `client.ts`, `manifest.ts`, `models.ts`, `includes.ts`, and migration SQL when the schema changed.
|
|
58
95
|
|
|
59
|
-
**4. Query**
|
|
60
|
-
|
|
61
|
-
```ts
|
|
62
|
-
import { db } from "./neoorm/client.js";
|
|
63
|
-
|
|
64
|
-
const user = await db.users.findById(userId, {
|
|
65
|
-
with: {
|
|
66
|
-
posts: { orderBy: { createdAt: "desc" }, limit: 10 },
|
|
67
|
-
},
|
|
68
|
-
});
|
|
69
|
-
```
|
|
70
|
-
|
|
71
96
|
## Schema DSL
|
|
72
97
|
|
|
73
98
|
### Tables and accessors
|
|
@@ -78,7 +103,7 @@ const user = await db.users.findById(userId, {
|
|
|
78
103
|
users: table("user", { ... }) // db.users → SQL table "user"
|
|
79
104
|
```
|
|
80
105
|
|
|
81
|
-
Column field names use camelCase in TypeScript. By default, SQL column names are snake_case (`createdAt` → `created_at`).
|
|
106
|
+
Column field names use camelCase in TypeScript. By default, SQL column names are snake_case (`createdAt` → `created_at`). You can change that globally or per table with `columnNaming`.
|
|
82
107
|
|
|
83
108
|
### Column types
|
|
84
109
|
|
|
@@ -92,7 +117,16 @@ Column field names use camelCase in TypeScript. By default, SQL column names are
|
|
|
92
117
|
| `text()` | `TEXT` | `string \| null` | |
|
|
93
118
|
| `bool()` | `BOOLEAN` | `boolean \| null` | |
|
|
94
119
|
| `int()` | `INTEGER` | `number \| null` | |
|
|
95
|
-
| `timestamp()` | `TIMESTAMPTZ` | `Date \| null` | Use `.defaultNow()` for `DEFAULT NOW()` |
|
|
120
|
+
| `timestamp()` | `TIMESTAMPTZ` | `Date \| null` | Use `.defaultNow()` for `DEFAULT NOW()`; use `.updatedAt()` for auto-update on ORM writes |
|
|
121
|
+
|
|
122
|
+
Pair audit timestamps on mutable tables:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
createdAt: timestamp().notNull().defaultNow(),
|
|
126
|
+
updatedAt: timestamp().notNull().defaultNow().updatedAt(),
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
`.updatedAt()` is ORM metadata only (no DB trigger). `update`, `updateById`, `updateMany`, and `upsert` always set the column to `NOW()` in SQL; user-provided values in `data` are ignored.
|
|
96
130
|
| `json()` | `JSON` | `unknown \| null` | Generic: `json<MyType>()` |
|
|
97
131
|
| `jsonb()` | `JSONB` | `unknown \| null` | Generic: `jsonb<MyType>()` |
|
|
98
132
|
| `decimal()` / `numeric()` | `NUMERIC` or `NUMERIC(p,s)` | `string \| null` | Use strings to avoid float precision loss |
|
|
@@ -102,7 +136,7 @@ Column field names use camelCase in TypeScript. By default, SQL column names are
|
|
|
102
136
|
| `intArray()` | `INTEGER[]` | `number[] \| null` | |
|
|
103
137
|
| `citext()` | `CITEXT` | `string \| null` | Case-insensitive text; requires `citext` extension |
|
|
104
138
|
|
|
105
|
-
All column builders support `.notNull()`, `.unique()`, `.default(value)`, `.defaultNow()`, `.primary()`, and `.map(name)`.
|
|
139
|
+
All column builders support `.notNull()`, `.unique()`, `.default(value)`, `.defaultNow()`, `.updatedAt()` (timestamp only), `.primary()`, and `.map(name)`.
|
|
106
140
|
|
|
107
141
|
Foreign keys use `fk("target_table.target_column", { as, inverse, nullable?, onDelete? })`.
|
|
108
142
|
|
|
@@ -159,11 +193,27 @@ posts: table("posts", {
|
|
|
159
193
|
```
|
|
160
194
|
|
|
161
195
|
```ts
|
|
162
|
-
// jsonb — equality
|
|
196
|
+
// jsonb — exact equality on the full object (all keys must match)
|
|
163
197
|
await db.posts.findMany({
|
|
164
198
|
where: { metadata: { featured: true, category: "engineering" } },
|
|
165
199
|
});
|
|
166
200
|
|
|
201
|
+
// jsonb — partial / subset match (@> containment)
|
|
202
|
+
await db.posts.findMany({
|
|
203
|
+
where: { metadata: { jsonContains: { featured: true } } },
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// jsonb — key existence and path filters
|
|
207
|
+
await db.posts.findMany({
|
|
208
|
+
where: {
|
|
209
|
+
metadata: {
|
|
210
|
+
hasKey: "featured",
|
|
211
|
+
hasAnyKeys: ["category", "tags"],
|
|
212
|
+
path: { segments: ["category"], equals: "engineering" },
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
});
|
|
216
|
+
|
|
167
217
|
// decimal — compare as strings
|
|
168
218
|
await db.posts.findMany({
|
|
169
219
|
where: { price: { gte: "9.99", lte: "49.99" } },
|
|
@@ -192,6 +242,11 @@ Omit `id` on insert — the database assigns it and `RETURNING` populates the re
|
|
|
192
242
|
```ts
|
|
193
243
|
const item = await db.items.create({ data: { name: "Widget" } });
|
|
194
244
|
// item.id is the DB-generated integer
|
|
245
|
+
|
|
246
|
+
// Bulk insert with returned rows (serial IDs, UUIDs, defaults materialized)
|
|
247
|
+
const items = await db.items.createManyAndReturn({
|
|
248
|
+
data: [{ name: "A" }, { name: "B" }],
|
|
249
|
+
});
|
|
195
250
|
```
|
|
196
251
|
|
|
197
252
|
### UUID columns
|
|
@@ -216,7 +271,45 @@ emailAddress: text().notNull().map("email"),
|
|
|
216
271
|
authorId: fk("users.id", { as: "author", inverse: "posts" }).map("author_ref"),
|
|
217
272
|
```
|
|
218
273
|
|
|
219
|
-
`.map()` only produces a migration when the SQL name actually changes. Mapping to the default
|
|
274
|
+
`.map()` only produces a migration when the SQL name actually changes. Mapping to the active naming strategy's default name (e.g. `.map("email_verified")` on `emailVerified` in a snake_case table) is a no-op — `neoorm generate` warns about this.
|
|
275
|
+
|
|
276
|
+
### Column naming strategy
|
|
277
|
+
|
|
278
|
+
Use `columnNaming` when an entire schema or table follows camelCase SQL column names instead of the default snake_case:
|
|
279
|
+
|
|
280
|
+
```ts
|
|
281
|
+
export const schema = defineSchema(
|
|
282
|
+
{
|
|
283
|
+
users: table("users", {
|
|
284
|
+
emailAddress: text().notNull(), // SQL: email_address
|
|
285
|
+
}),
|
|
286
|
+
|
|
287
|
+
legacyUsers: table(
|
|
288
|
+
"legacy_users",
|
|
289
|
+
{
|
|
290
|
+
emailAddress: text().notNull(), // SQL: emailAddress
|
|
291
|
+
},
|
|
292
|
+
{ columnNaming: "camelCase" },
|
|
293
|
+
),
|
|
294
|
+
},
|
|
295
|
+
{ columnNaming: "snakeCase" },
|
|
296
|
+
);
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Per-table options can also include `extras`:
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
posts: table(
|
|
303
|
+
"posts",
|
|
304
|
+
{ authorId: fk("users.id", { as: "author", inverse: "posts" }) },
|
|
305
|
+
{
|
|
306
|
+
columnNaming: "camelCase",
|
|
307
|
+
extras: (t) => ({ authorIdx: index().on(t.authorId) }),
|
|
308
|
+
},
|
|
309
|
+
)
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
`columnNaming` affects SQL column names only. TypeScript keys stay exactly as written in the schema, and `.map("exact_name")` still overrides the strategy for individual columns.
|
|
220
313
|
|
|
221
314
|
### Indexes and composite keys
|
|
222
315
|
|
|
@@ -264,8 +357,8 @@ manyToMany(schema.posts, schema.tags, {
|
|
|
264
357
|
| Relation kind | Operations |
|
|
265
358
|
|---------------|------------|
|
|
266
359
|
| **To-one** (outgoing FK) | `connect`, `create`, `disconnect` (nullable FK only) |
|
|
267
|
-
| **One-to-many** (inverse) | `create`, `connect`, `disconnect`, `set` |
|
|
268
|
-
| **Many-to-many** | `connect`, `connectOrCreate`, `disconnect`, `set` |
|
|
360
|
+
| **One-to-many** (inverse) | `create`, `connect`, `disconnect`, `set`, `delete` |
|
|
361
|
+
| **Many-to-many** | `connect`, `connectOrCreate`, `disconnect`, `set`, `delete` |
|
|
269
362
|
|
|
270
363
|
```ts
|
|
271
364
|
// To-one on update
|
|
@@ -283,6 +376,7 @@ await db.posts.update({
|
|
|
283
376
|
connect: [{ id: commentId }],
|
|
284
377
|
disconnect: [{ id: oldCommentId }], // or `true` to unlink all
|
|
285
378
|
set: [{ id: commentId }], // replace all links
|
|
379
|
+
delete: [{ id: commentId }], // or `true` to delete all linked children
|
|
286
380
|
},
|
|
287
381
|
},
|
|
288
382
|
});
|
|
@@ -297,14 +391,100 @@ await db.posts.update({
|
|
|
297
391
|
connectOrCreate: [
|
|
298
392
|
{ where: { slug: "orm" }, create: { slug: "orm", name: "ORM" } },
|
|
299
393
|
],
|
|
394
|
+
delete: [{ id: tagId }], // removes junction links, then deletes tag rows
|
|
300
395
|
},
|
|
301
396
|
},
|
|
302
397
|
});
|
|
398
|
+
|
|
399
|
+
// updateMany applies scalar SET once, then nested writes per matched parent
|
|
400
|
+
await db.posts.updateMany({
|
|
401
|
+
where: { published: true },
|
|
402
|
+
data: {
|
|
403
|
+
status: "archived",
|
|
404
|
+
tags: { connect: [{ id: tagId }] },
|
|
405
|
+
},
|
|
406
|
+
});
|
|
303
407
|
```
|
|
304
408
|
|
|
305
|
-
Within a single relation field, operations run in order: `disconnect` → `set` → `connect` / `connectOrCreate` → `create`. Mixing `set` with `connect` or `create` is discouraged — `set` replaces the full link set.
|
|
409
|
+
Within a single relation field, operations run in order: `delete` → `disconnect` → `set` → `connect` / `connectOrCreate` → `create`. Mixing `set` with `connect` or `create` is discouraged — `set` replaces the full link set.
|
|
410
|
+
|
|
411
|
+
## Cursor pagination
|
|
412
|
+
|
|
413
|
+
For feeds, infinite scroll, and large tables, use `paginate` instead of `limit`/`offset`. It uses **keyset pagination** on your `orderBy` columns plus the table primary key as a stable tiebreaker (for example `(createdAt, id)`).
|
|
414
|
+
|
|
415
|
+
```ts
|
|
416
|
+
let cursor: { createdAt: string; id: string } | null = null;
|
|
417
|
+
|
|
418
|
+
for (;;) {
|
|
419
|
+
const page = await db.posts.paginate({
|
|
420
|
+
where: { published: true },
|
|
421
|
+
orderBy: { createdAt: "desc" },
|
|
422
|
+
take: 20,
|
|
423
|
+
...(cursor ? { after: cursor } : {}),
|
|
424
|
+
with: { author: true },
|
|
425
|
+
});
|
|
306
426
|
|
|
307
|
-
|
|
427
|
+
for (const post of page.items) {
|
|
428
|
+
// render post
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
if (!page.hasMore) break;
|
|
432
|
+
cursor = page.nextCursor;
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
- `orderBy` is required; scalar `id` is appended automatically when omitted.
|
|
437
|
+
- `take` is the page size; `hasMore` uses a `take + 1` probe row.
|
|
438
|
+
- `after` is a typed cursor object (`nextCursor` from the previous page).
|
|
439
|
+
- For HTTP APIs, encode cursors with `encodeCursor` / `decodeCursor` from `neoorm`.
|
|
440
|
+
|
|
441
|
+
On feed tables, add a composite index on the sort columns (for example `index().on(t.createdAt, t.id)`).
|
|
442
|
+
|
|
443
|
+
## Aggregates
|
|
444
|
+
|
|
445
|
+
### Relation counts in `with`
|
|
446
|
+
|
|
447
|
+
Load counts without fetching full related rows:
|
|
448
|
+
|
|
449
|
+
```ts
|
|
450
|
+
const users = await db.users.findMany({
|
|
451
|
+
with: {
|
|
452
|
+
_count: { posts: true },
|
|
453
|
+
profile: true,
|
|
454
|
+
},
|
|
455
|
+
});
|
|
456
|
+
// users[0]._count.posts === number
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
Optional per-relation filter: `_count: { posts: { where: { published: true } } }`.
|
|
460
|
+
|
|
461
|
+
### Table-level `aggregate()`
|
|
462
|
+
|
|
463
|
+
```ts
|
|
464
|
+
const stats = await db.posts.aggregate({
|
|
465
|
+
where: { published: true },
|
|
466
|
+
_count: true,
|
|
467
|
+
_avg: { views: true },
|
|
468
|
+
});
|
|
469
|
+
// { _count: number, _avg: { views: number | null } }
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
For grouped dashboards, use `db.sql` or the `sqlBuilder` helper.
|
|
473
|
+
|
|
474
|
+
## Bulk insert
|
|
475
|
+
|
|
476
|
+
`createMany` returns the number of rows inserted. Use `createManyAndReturn` when you need serial IDs, generated UUIDs, or default values in the result:
|
|
477
|
+
|
|
478
|
+
```ts
|
|
479
|
+
const users = await db.users.createManyAndReturn({
|
|
480
|
+
data: [
|
|
481
|
+
{ email: "a@example.com", name: "A" },
|
|
482
|
+
{ email: "b@example.com", name: "B" },
|
|
483
|
+
],
|
|
484
|
+
});
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Scalar fields only — no nested relation writes (same as `createMany`).
|
|
308
488
|
|
|
309
489
|
## Where clauses
|
|
310
490
|
|
|
@@ -328,7 +508,29 @@ await db.posts.findFirst({
|
|
|
328
508
|
});
|
|
329
509
|
```
|
|
330
510
|
|
|
331
|
-
String columns support `equals`, `contains`, `startsWith`, `endsWith`, `in`, and `notIn`. Numeric, boolean, and date columns support `equals`, `gt`, `gte`, `lt`, `lte`, `in`, and `notIn`. All nullable columns also support `isNull` and `isNotNull`.
|
|
511
|
+
String columns support `equals`, `contains`, `startsWith`, `endsWith`, `in`, and `notIn`. Numeric, boolean, and date columns support `equals`, `gt`, `gte`, `lt`, `lte`, `in`, and `notIn`. JSON columns support `jsonContains`, `hasKey`, `hasAnyKeys`, `hasAllKeys`, and `path`. All nullable columns also support `isNull` and `isNotNull`.
|
|
512
|
+
|
|
513
|
+
### `distinct`
|
|
514
|
+
|
|
515
|
+
PostgreSQL `DISTINCT ON` — `orderBy` must lead with the same columns:
|
|
516
|
+
|
|
517
|
+
```ts
|
|
518
|
+
await db.users.findMany({
|
|
519
|
+
distinct: ["email"],
|
|
520
|
+
orderBy: { email: "asc" },
|
|
521
|
+
});
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### Selective `with` return types
|
|
525
|
+
|
|
526
|
+
Relation `select` narrows the TypeScript return type at compile time:
|
|
527
|
+
|
|
528
|
+
```ts
|
|
529
|
+
const users = await db.users.findMany({
|
|
530
|
+
with: { posts: { select: { title: true } } },
|
|
531
|
+
});
|
|
532
|
+
// users[0].posts[0].title is string; .body is excluded from the type
|
|
533
|
+
```
|
|
332
534
|
|
|
333
535
|
```ts
|
|
334
536
|
await db.users.findMany({
|
|
@@ -441,10 +643,12 @@ Nested `create` calls inside a transaction do not start a separate transaction.
|
|
|
441
643
|
|
|
442
644
|
| Command | Description |
|
|
443
645
|
|---------|-------------|
|
|
646
|
+
| `neoorm init` | Scaffold `neoorm.config.ts`, `schema.ts`, `.env.example`, generate client, and first migration |
|
|
444
647
|
| `neoorm generate` | Emit manifest, typed client, models, includes, and migrations |
|
|
445
648
|
| `neoorm migrate dev` | Apply pending migrations, then generate a new one if the schema changed |
|
|
446
649
|
| `neoorm migrate deploy` | Apply pending migrations |
|
|
447
650
|
| `neoorm migrate status` | List applied vs pending migrations |
|
|
651
|
+
| `neoorm migrate down [--steps N]` | Roll back the last N applied migrations (default 1) |
|
|
448
652
|
| `neoorm migrate reset --force` | Drop public schema and re-apply migrations (local dev) |
|
|
449
653
|
| `neoorm db push` | Push the current snapshot schema to the database |
|
|
450
654
|
| `neoorm db pull` | Introspect the database into a schema file |
|
|
@@ -480,6 +684,25 @@ neoorm migrate reset --force
|
|
|
480
684
|
|
|
481
685
|
Drops the `public` schema and re-applies all migrations from disk. Requires `--force`. Use `--skip-apply` to only drop the schema without re-applying.
|
|
482
686
|
|
|
687
|
+
### Rolling back migrations
|
|
688
|
+
|
|
689
|
+
```bash
|
|
690
|
+
neoorm migrate down
|
|
691
|
+
neoorm migrate down --steps 2
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
Rolls back the most recently applied migration(s) by running each migration folder's `down.sql`, removing the ledger entry from `_neoorm_migrations`, and restoring `snapshot.json` from `snapshot.before.json` (the manifest state before that migration was applied).
|
|
695
|
+
|
|
696
|
+
`down.sql` and `snapshot.before.json` are written automatically when `neoorm generate` or `neoorm migrate dev` creates a migration. The down SQL is the reverse schema diff (`next → prev`), with destructive changes accepted so rollbacks can drop columns or tables added in the forward migration.
|
|
697
|
+
|
|
698
|
+
Legacy migrations without `down.sql` cannot be rolled back — re-generate the migration or add `down.sql` manually.
|
|
699
|
+
|
|
700
|
+
Migration folders are not deleted on rollback (same as Prisma). Re-run `neoorm migrate deploy` to re-apply rolled-back migrations.
|
|
701
|
+
|
|
702
|
+
After rollback, `schema.ts` may still describe a newer schema than the restored snapshot; `neoorm migrate dev` may generate a new forward migration. `db push` and `migrate down` are independent — push ignores the migration ledger.
|
|
703
|
+
|
|
704
|
+
For a full wipe during local development, use `neoorm migrate reset --force` instead.
|
|
705
|
+
|
|
483
706
|
`generate` creates migration SQL only when the schema diff produces DDL changes (new tables/columns, column renames via `.map()`, etc.).
|
|
484
707
|
|
|
485
708
|
## Plugins
|
package/dist/bin/neoorm.js
CHANGED
|
@@ -4,14 +4,58 @@ import { join, resolve } from "node:path";
|
|
|
4
4
|
import { Pool } from "pg";
|
|
5
5
|
import { loadConfig } from "../config.js";
|
|
6
6
|
import { generateFromSchema, formatGenerateSummary } from "../codegen/generate.js";
|
|
7
|
-
import {
|
|
7
|
+
import { runInit, formatInitNextSteps } from "../init/scaffold.js";
|
|
8
|
+
import { migrateDeploy, migrateDown, migrateReset, migrateStatus, formatMigrateStatus, dbPush, dbPushWarnings, } from "../migrate/runner.js";
|
|
8
9
|
import { introspectPostgres } from "../introspect/pull.js";
|
|
9
10
|
import { writeFile } from "node:fs/promises";
|
|
11
|
+
import packageJson from "../../package.json" with { type: "json" };
|
|
10
12
|
const program = new Command();
|
|
11
13
|
program
|
|
12
14
|
.name("neoorm")
|
|
13
15
|
.description("NeoOrm CLI")
|
|
14
|
-
.version(
|
|
16
|
+
.version(packageJson.version);
|
|
17
|
+
program
|
|
18
|
+
.command("init")
|
|
19
|
+
.description("Scaffold neoorm.config.ts, schema.ts, .env.example, and run initial generate")
|
|
20
|
+
.option("--force", "Overwrite existing scaffold files")
|
|
21
|
+
.option("--schema <path>", "Schema file path", "./schema.ts")
|
|
22
|
+
.option("--out <dir>", "Generated output directory", "./neoorm")
|
|
23
|
+
.action(async (options) => {
|
|
24
|
+
const cwd = process.cwd();
|
|
25
|
+
try {
|
|
26
|
+
const result = await runInit({
|
|
27
|
+
cwd,
|
|
28
|
+
schemaPath: options.schema,
|
|
29
|
+
outDir: options.out,
|
|
30
|
+
...(options.force ? { force: true } : {}),
|
|
31
|
+
});
|
|
32
|
+
if (result.written.length > 0) {
|
|
33
|
+
console.log("Scaffolded:");
|
|
34
|
+
for (const file of result.written) {
|
|
35
|
+
console.log(` + ${file}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (result.skipped.length > 0) {
|
|
39
|
+
console.log("Skipped (already exists):");
|
|
40
|
+
for (const file of result.skipped) {
|
|
41
|
+
console.log(` - ${file}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
for (const line of formatGenerateSummary(result.summary, result.outDir)) {
|
|
45
|
+
console.log(line);
|
|
46
|
+
}
|
|
47
|
+
for (const warning of result.warnings) {
|
|
48
|
+
console.warn(`Warning: ${warning}`);
|
|
49
|
+
}
|
|
50
|
+
for (const line of formatInitNextSteps(cwd, options.schema, options.out)) {
|
|
51
|
+
console.log(line);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
15
59
|
program
|
|
16
60
|
.command("generate")
|
|
17
61
|
.description("Generate manifest, client, and migrations from schema")
|
|
@@ -35,10 +79,11 @@ program
|
|
|
35
79
|
program
|
|
36
80
|
.command("migrate")
|
|
37
81
|
.description("Run migrations")
|
|
38
|
-
.argument("[subcommand]", "dev | deploy | status | reset")
|
|
82
|
+
.argument("[subcommand]", "dev | deploy | status | reset | down")
|
|
39
83
|
.option("--accept-data-loss", "Include destructive schema changes in generated migrations")
|
|
40
84
|
.option("--force", "Required for reset — drops the public schema and all data")
|
|
41
85
|
.option("--skip-apply", "With reset, only drop schema without re-applying migrations")
|
|
86
|
+
.option("--steps <n>", "Number of migrations to roll back (down)", "1")
|
|
42
87
|
.action(async (subcommand, options) => {
|
|
43
88
|
const cwd = process.cwd();
|
|
44
89
|
const config = await loadConfig(cwd);
|
|
@@ -73,6 +118,27 @@ program
|
|
|
73
118
|
}
|
|
74
119
|
return;
|
|
75
120
|
}
|
|
121
|
+
if (subcommand === "down") {
|
|
122
|
+
const steps = Number.parseInt(options.steps ?? "1", 10);
|
|
123
|
+
if (!Number.isFinite(steps) || steps < 1) {
|
|
124
|
+
console.error("--steps must be a positive integer");
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
const reverted = await migrateDown(pool, migrationsDir, {
|
|
128
|
+
steps,
|
|
129
|
+
outDir,
|
|
130
|
+
});
|
|
131
|
+
if (reverted.length === 0) {
|
|
132
|
+
console.log("No migrations rolled back");
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
console.log(`Rolled back ${reverted.length} migration(s):`);
|
|
136
|
+
for (const name of reverted) {
|
|
137
|
+
console.log(` - ${name}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
76
142
|
if (subcommand === "deploy" || subcommand === "dev") {
|
|
77
143
|
const applied = await migrateDeploy(pool, migrationsDir);
|
|
78
144
|
if (applied.length === 0) {
|
|
@@ -105,7 +171,7 @@ program
|
|
|
105
171
|
}
|
|
106
172
|
return;
|
|
107
173
|
}
|
|
108
|
-
console.error("Usage: neoorm migrate dev | deploy | status | reset");
|
|
174
|
+
console.error("Usage: neoorm migrate dev | deploy | status | reset | down");
|
|
109
175
|
process.exit(1);
|
|
110
176
|
}
|
|
111
177
|
finally {
|
package/dist/bin/neoorm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"neoorm.js","sourceRoot":"","sources":["../../src/bin/neoorm.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,EACL,aAAa,EACb,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,MAAM,EACN,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"neoorm.js","sourceRoot":"","sources":["../../src/bin/neoorm.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,9 @@ export declare function buildMigrationSql(tableDiffs: TableDiff[], extensions?:
|
|
|
5
5
|
values: readonly string[];
|
|
6
6
|
}>): string[];
|
|
7
7
|
export declare function diffManifest(prev: Manifest | null, next: Manifest): ManifestDiff;
|
|
8
|
+
export declare function emptyManifest(): Manifest;
|
|
9
|
+
/** SQL to roll back a forward migration (next → prev). */
|
|
10
|
+
export declare function buildDownSql(prev: Manifest | null, next: Manifest): string[];
|
|
8
11
|
export declare function resolveMigrationSql(diff: ManifestDiff, prev: Manifest | null, next: Manifest, acceptDataLoss: boolean): {
|
|
9
12
|
sql: string[];
|
|
10
13
|
blocked: DestructiveChange[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff-manifest.d.ts","sourceRoot":"","sources":["../../src/codegen/diff-manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,iBAAiB,EAEjB,QAAQ,EACR,cAAc,EAGd,YAAY,EACZ,SAAS,EACV,MAAM,qBAAqB,CAAC;AAiB7B,wBAAgB,aAAa,CAC3B,GAAG,EAAE,cAAc,EACnB,QAAQ,CAAC,EAAE,QAAQ,GAClB,MAAM,CAER;AAuCD,wBAAgB,YAAY,CAC1B,CAAC,EAAE,cAAc,EACjB,CAAC,EAAE,cAAc,EACjB,QAAQ,CAAC,EAAE,QAAQ,GAClB,OAAO,
|
|
1
|
+
{"version":3,"file":"diff-manifest.d.ts","sourceRoot":"","sources":["../../src/codegen/diff-manifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,iBAAiB,EAEjB,QAAQ,EACR,cAAc,EAGd,YAAY,EACZ,SAAS,EACV,MAAM,qBAAqB,CAAC;AAiB7B,wBAAgB,aAAa,CAC3B,GAAG,EAAE,cAAc,EACnB,QAAQ,CAAC,EAAE,QAAQ,GAClB,MAAM,CAER;AAuCD,wBAAgB,YAAY,CAC1B,CAAC,EAAE,cAAc,EACjB,CAAC,EAAE,cAAc,EACjB,QAAQ,CAAC,EAAE,QAAQ,GAClB,OAAO,CAcT;AA0bD,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,SAAS,EAAE,EACvB,UAAU,GAAE,MAAM,EAAO,EACzB,QAAQ,CAAC,EAAE,QAAQ,EACnB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAAC,GAC3D,MAAM,EAAE,CAyCV;AAiCD,wBAAgB,YAAY,CAC1B,IAAI,EAAE,QAAQ,GAAG,IAAI,EACrB,IAAI,EAAE,QAAQ,GACb,YAAY,CAoDd;AAED,wBAAgB,aAAa,IAAI,QAAQ,CAMxC;AAED,0DAA0D;AAC1D,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI,EAAE,IAAI,EAAE,QAAQ,GAAG,MAAM,EAAE,CAK5E;AAED,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE,QAAQ,GAAG,IAAI,EACrB,IAAI,EAAE,QAAQ,EACd,cAAc,EAAE,OAAO,GACtB;IAAE,GAAG,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,iBAAiB,EAAE,CAAA;CAAE,CAkDjD;AAcD,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,QAAQ,GAAG,IAAI,EACrB,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,YAAY,GACjB,MAAM,EAAE,CAoDV;AAED,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,iBAAiB,EAAE,GAC/B,MAAM,EAAE,CAyBV"}
|
|
@@ -34,6 +34,7 @@ export function columnsEqual(a, b, manifest) {
|
|
|
34
34
|
effectiveNullable(a) === effectiveNullable(b) &&
|
|
35
35
|
a.unique === b.unique &&
|
|
36
36
|
a.primary === b.primary &&
|
|
37
|
+
!!a.updatedAt === !!b.updatedAt &&
|
|
37
38
|
defaultsEqual(a, b) &&
|
|
38
39
|
typeOptionsEqual(a.typeOptions, b.typeOptions) &&
|
|
39
40
|
a.checkExpression === b.checkExpression &&
|
|
@@ -472,6 +473,20 @@ export function diffManifest(prev, next) {
|
|
|
472
473
|
const sql = buildMigrationSql(tableDiffs, newExtensions, next, newEnumTypes);
|
|
473
474
|
return { isInitial: false, sql, destructive };
|
|
474
475
|
}
|
|
476
|
+
export function emptyManifest() {
|
|
477
|
+
return {
|
|
478
|
+
version: 1,
|
|
479
|
+
tables: {},
|
|
480
|
+
manyToMany: [],
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
/** SQL to roll back a forward migration (next → prev). */
|
|
484
|
+
export function buildDownSql(prev, next) {
|
|
485
|
+
const target = prev ?? emptyManifest();
|
|
486
|
+
const diff = diffManifest(next, target);
|
|
487
|
+
const { sql } = resolveMigrationSql(diff, next, target, true);
|
|
488
|
+
return sql;
|
|
489
|
+
}
|
|
475
490
|
export function resolveMigrationSql(diff, prev, next, acceptDataLoss) {
|
|
476
491
|
if (acceptDataLoss) {
|
|
477
492
|
const blocked = diff.destructive.filter((change) => change.kind === "alter_column_type_manual" ||
|