neoorm 0.9.5 → 0.9.7
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/AGENTS.md +46 -0
- package/dist/bin/neoorm.d.ts.map +1 -1
- package/dist/bin/neoorm.js +213 -135
- package/dist/bin/neoorm.js.map +1 -1
- package/dist/codegen/column-ts.d.ts.map +1 -1
- package/dist/codegen/column-ts.js +5 -2
- package/dist/codegen/column-ts.js.map +1 -1
- package/dist/codegen/emit-query-types.d.ts.map +1 -1
- package/dist/codegen/emit-query-types.js +35 -0
- package/dist/codegen/emit-query-types.js.map +1 -1
- package/dist/codegen/generate.d.ts +25 -1
- package/dist/codegen/generate.d.ts.map +1 -1
- package/dist/codegen/generate.js +80 -17
- package/dist/codegen/generate.js.map +1 -1
- package/dist/codegen/schema-to-manifest.d.ts.map +1 -1
- package/dist/codegen/schema-to-manifest.js +65 -0
- package/dist/codegen/schema-to-manifest.js.map +1 -1
- package/dist/codegen/validation/from-manifest.d.ts.map +1 -1
- package/dist/codegen/validation/from-manifest.js +12 -2
- package/dist/codegen/validation/from-manifest.js.map +1 -1
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +28 -0
- package/dist/config.js.map +1 -1
- package/dist/dialect/sqlite.test.js +9 -0
- package/dist/dialect/sqlite.test.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/introspect/mysql/to-manifest.d.ts.map +1 -1
- package/dist/introspect/mysql/to-manifest.js +2 -1
- package/dist/introspect/mysql/to-manifest.js.map +1 -1
- package/dist/introspect/pull.d.ts +5 -0
- package/dist/introspect/pull.d.ts.map +1 -1
- package/dist/introspect/pull.js +160 -22
- package/dist/introspect/pull.js.map +1 -1
- package/dist/introspect/sqlite/to-manifest.d.ts.map +1 -1
- package/dist/introspect/sqlite/to-manifest.js +2 -1
- package/dist/introspect/sqlite/to-manifest.js.map +1 -1
- package/dist/introspect/table-map.d.ts +9 -0
- package/dist/introspect/table-map.d.ts.map +1 -0
- package/dist/introspect/table-map.js +21 -0
- package/dist/introspect/table-map.js.map +1 -0
- package/dist/introspect/to-manifest.d.ts.map +1 -1
- package/dist/introspect/to-manifest.js +2 -1
- package/dist/introspect/to-manifest.js.map +1 -1
- package/dist/migrate/dev-workflow.d.ts +36 -0
- package/dist/migrate/dev-workflow.d.ts.map +1 -0
- package/dist/migrate/dev-workflow.js +96 -0
- package/dist/migrate/dev-workflow.js.map +1 -0
- package/dist/migrate/runner.d.ts.map +1 -1
- package/dist/migrate/runner.js +23 -5
- package/dist/migrate/runner.js.map +1 -1
- package/dist/runtime/driver-sqlite.test.js +115 -0
- package/dist/runtime/driver-sqlite.test.js.map +1 -1
- package/dist/runtime/driver.d.ts +8 -0
- package/dist/runtime/driver.d.ts.map +1 -1
- package/dist/runtime/driver.js +51 -97
- package/dist/runtime/driver.js.map +1 -1
- package/dist/runtime/error-codes.d.ts +4 -0
- package/dist/runtime/error-codes.d.ts.map +1 -1
- package/dist/runtime/error-codes.js +4 -0
- package/dist/runtime/error-codes.js.map +1 -1
- package/dist/runtime/mysql-driver.d.ts.map +1 -1
- package/dist/runtime/mysql-driver.js +5 -1
- package/dist/runtime/mysql-driver.js.map +1 -1
- package/dist/runtime/mysql-family-pool.test.js +14 -1
- package/dist/runtime/mysql-family-pool.test.js.map +1 -1
- package/dist/runtime/mysql-placeholders.d.ts.map +1 -1
- package/dist/runtime/mysql-placeholders.js +12 -0
- package/dist/runtime/mysql-placeholders.js.map +1 -1
- package/dist/runtime/mysql-placeholders.test.js +15 -0
- package/dist/runtime/mysql-placeholders.test.js.map +1 -1
- package/dist/runtime/query/compile-where.d.ts.map +1 -1
- package/dist/runtime/query/compile-where.js +26 -1
- package/dist/runtime/query/compile-where.js.map +1 -1
- package/dist/runtime/query/find-or-create.test.js +19 -0
- package/dist/runtime/query/find-or-create.test.js.map +1 -1
- package/dist/runtime/query/update.d.ts.map +1 -1
- package/dist/runtime/query/update.js +9 -1
- package/dist/runtime/query/update.js.map +1 -1
- package/dist/runtime/query/upsert.d.ts.map +1 -1
- package/dist/runtime/query/upsert.js +12 -3
- package/dist/runtime/query/upsert.js.map +1 -1
- package/dist/runtime/regex-guard.d.ts +28 -0
- package/dist/runtime/regex-guard.d.ts.map +1 -0
- package/dist/runtime/regex-guard.js +124 -0
- package/dist/runtime/regex-guard.js.map +1 -0
- package/dist/runtime/regex-guard.test.d.ts +2 -0
- package/dist/runtime/regex-guard.test.d.ts.map +1 -0
- package/dist/runtime/regex-guard.test.js +63 -0
- package/dist/runtime/regex-guard.test.js.map +1 -0
- package/dist/runtime/sqlite-open.d.ts.map +1 -1
- package/dist/runtime/sqlite-open.js +22 -7
- package/dist/runtime/sqlite-open.js.map +1 -1
- package/dist/runtime/sqlite-open.test.d.ts +2 -0
- package/dist/runtime/sqlite-open.test.d.ts.map +1 -0
- package/dist/runtime/sqlite-open.test.js +66 -0
- package/dist/runtime/sqlite-open.test.js.map +1 -0
- package/dist/seed/runner.d.ts +46 -0
- package/dist/seed/runner.d.ts.map +1 -0
- package/dist/seed/runner.js +99 -0
- package/dist/seed/runner.js.map +1 -0
- package/dist/sql/split-statements.d.ts +15 -0
- package/dist/sql/split-statements.d.ts.map +1 -0
- package/dist/sql/split-statements.js +132 -0
- package/dist/sql/split-statements.js.map +1 -0
- package/docs/cli.md +30 -2
- package/docs/configuration.md +2 -0
- package/docs/migrate-dev-workflow.md +84 -0
- package/docs/migrations.md +14 -3
- package/docs/seeding.md +67 -0
- package/docs/sqlite.md +2 -0
- package/llms-full.txt +3547 -0
- package/llms.txt +40 -0
- package/package.json +5 -2
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { stat } from "node:fs/promises";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { schemaError } from "../runtime/error-builders.js";
|
|
4
|
+
import { SchemaErrorCode } from "../runtime/error-codes.js";
|
|
5
|
+
import { importTsModule } from "../utils/load-ts.js";
|
|
6
|
+
const SEED_EXTENSIONS = [".ts", ".mts", ".cts"];
|
|
7
|
+
function isRecord(value) {
|
|
8
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
async function isFile(path) {
|
|
11
|
+
try {
|
|
12
|
+
return (await stat(path)).isFile();
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function firstExisting(paths) {
|
|
19
|
+
for (const path of paths) {
|
|
20
|
+
if (await isFile(path)) {
|
|
21
|
+
return path;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
function seedFileSuggestions(lookedFor) {
|
|
27
|
+
return [
|
|
28
|
+
`Create ${lookedFor[0]} exporting \`export async function seed(db) { ... }\``,
|
|
29
|
+
"Or pass an explicit path with --file <path>",
|
|
30
|
+
];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve which seed file to run. Precedence: `--file` → config
|
|
34
|
+
* `seed.file` → `seeds/<env>.ts` → `seed.ts` next to the schema.
|
|
35
|
+
* Throws `invalid_seed` when nothing resolves.
|
|
36
|
+
*/
|
|
37
|
+
export async function resolveSeedFile(options) {
|
|
38
|
+
if (options.file) {
|
|
39
|
+
return resolve(options.cwd, options.file);
|
|
40
|
+
}
|
|
41
|
+
if (options.configFile) {
|
|
42
|
+
return resolve(options.cwd, options.configFile);
|
|
43
|
+
}
|
|
44
|
+
const schemaDir = dirname(options.schemaPath);
|
|
45
|
+
if (options.env) {
|
|
46
|
+
const candidates = SEED_EXTENSIONS.map((ext) => join(schemaDir, "seeds", `${options.env}${ext}`));
|
|
47
|
+
const found = await firstExisting(candidates);
|
|
48
|
+
if (!found) {
|
|
49
|
+
throw schemaError(SchemaErrorCode.invalid_seed, `No seed file found for --env "${options.env}". Looked for: ${candidates.join(", ")}.`, undefined, seedFileSuggestions(candidates));
|
|
50
|
+
}
|
|
51
|
+
return found;
|
|
52
|
+
}
|
|
53
|
+
const candidates = SEED_EXTENSIONS.map((ext) => join(schemaDir, `seed${ext}`));
|
|
54
|
+
const found = await firstExisting(candidates);
|
|
55
|
+
if (!found) {
|
|
56
|
+
throw schemaError(SchemaErrorCode.invalid_seed, `No seed file found. Looked for: ${candidates.join(", ")}.`, undefined, seedFileSuggestions(candidates));
|
|
57
|
+
}
|
|
58
|
+
return found;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Load the `seed(db)` export from a seed file. Accepts a named `seed`
|
|
62
|
+
* export or a default-exported function.
|
|
63
|
+
*/
|
|
64
|
+
export async function loadSeedFunction(seedPath) {
|
|
65
|
+
let mod;
|
|
66
|
+
try {
|
|
67
|
+
mod = await importTsModule(seedPath);
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
throw schemaError(SchemaErrorCode.invalid_seed, `Could not load seed file "${seedPath}": ${err instanceof Error ? err.message : String(err)}`, undefined, ["Check the path and that the file compiles"]);
|
|
71
|
+
}
|
|
72
|
+
const exported = mod.seed;
|
|
73
|
+
const defaultExport = mod.default;
|
|
74
|
+
const fromDefault = typeof defaultExport === "function"
|
|
75
|
+
? defaultExport
|
|
76
|
+
: isRecord(defaultExport)
|
|
77
|
+
? defaultExport.seed
|
|
78
|
+
: undefined;
|
|
79
|
+
const fn = exported ?? fromDefault;
|
|
80
|
+
if (typeof fn !== "function") {
|
|
81
|
+
throw schemaError(SchemaErrorCode.invalid_seed, `Seed file "${seedPath}" must export a seed function: \`export async function seed(db) { ... }\`.`, undefined, ["Export a named `seed` function or a default function"]);
|
|
82
|
+
}
|
|
83
|
+
return fn;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Run a seed file inside a single transaction. Any failure rolls the whole
|
|
87
|
+
* seed back, so failed runs are safe to retry. Execution errors propagate
|
|
88
|
+
* unwrapped so their original code and context are preserved.
|
|
89
|
+
*/
|
|
90
|
+
export async function runSeed(db, seedPath) {
|
|
91
|
+
const seed = await loadSeedFunction(seedPath);
|
|
92
|
+
await db.$transaction(async (tx) => {
|
|
93
|
+
// The runtime shape is identical for every manifest (repositories by
|
|
94
|
+
// accessor); only the static table types differ, so seed files may
|
|
95
|
+
// annotate with their own `TransactionClient<typeof schema._tables>`.
|
|
96
|
+
await seed(tx);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/seed/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type SplitStatementsOptions = {
|
|
2
|
+
/**
|
|
3
|
+
* Treat `\` as an escape character inside quoted strings and quoted
|
|
4
|
+
* identifiers (MySQL/MariaDB string syntax). Off by default: SQLite and
|
|
5
|
+
* PostgreSQL treat a backslash as a literal character in strings.
|
|
6
|
+
*/
|
|
7
|
+
backslashEscapes?: boolean;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Split a SQL script into individual statements on `;` boundaries, honoring
|
|
11
|
+
* quoted strings, quoted identifiers (backticks/double quotes), and
|
|
12
|
+
* line/block comments — so `;` inside any of them never splits.
|
|
13
|
+
*/
|
|
14
|
+
export declare function splitStatements(sql: string, options?: SplitStatementsOptions): string[];
|
|
15
|
+
//# sourceMappingURL=split-statements.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split-statements.d.ts","sourceRoot":"","sources":["../../src/sql/split-statements.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,sBAAsB,GAAG;IACpC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,eAAe,CAC9B,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,sBAAsB,GAC9B,MAAM,EAAE,CA6HV"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Split a SQL script into individual statements on `;` boundaries, honoring
|
|
3
|
+
* quoted strings, quoted identifiers (backticks/double quotes), and
|
|
4
|
+
* line/block comments — so `;` inside any of them never splits.
|
|
5
|
+
*/
|
|
6
|
+
export function splitStatements(sql, options) {
|
|
7
|
+
const backslash = options?.backslashEscapes === true;
|
|
8
|
+
const statements = [];
|
|
9
|
+
let current = "";
|
|
10
|
+
let inSingle = false;
|
|
11
|
+
let inDouble = false;
|
|
12
|
+
let inBacktick = false;
|
|
13
|
+
let inLineComment = false;
|
|
14
|
+
let inBlockComment = false;
|
|
15
|
+
for (let i = 0; i < sql.length; i++) {
|
|
16
|
+
const ch = sql[i];
|
|
17
|
+
const next = sql[i + 1];
|
|
18
|
+
if (inLineComment) {
|
|
19
|
+
current += ch;
|
|
20
|
+
if (ch === "\n")
|
|
21
|
+
inLineComment = false;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (inBlockComment) {
|
|
25
|
+
current += ch;
|
|
26
|
+
if (ch === "*" && next === "/") {
|
|
27
|
+
current += next;
|
|
28
|
+
i++;
|
|
29
|
+
inBlockComment = false;
|
|
30
|
+
}
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (inSingle) {
|
|
34
|
+
current += ch;
|
|
35
|
+
if (backslash && ch === "\\") {
|
|
36
|
+
if (next !== undefined) {
|
|
37
|
+
current += next;
|
|
38
|
+
i++;
|
|
39
|
+
}
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
if (ch === "'") {
|
|
43
|
+
if (next === "'") {
|
|
44
|
+
current += next;
|
|
45
|
+
i++;
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
inSingle = false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (inDouble) {
|
|
54
|
+
current += ch;
|
|
55
|
+
if (backslash && ch === "\\") {
|
|
56
|
+
if (next !== undefined) {
|
|
57
|
+
current += next;
|
|
58
|
+
i++;
|
|
59
|
+
}
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (ch === '"') {
|
|
63
|
+
if (next === '"') {
|
|
64
|
+
current += next;
|
|
65
|
+
i++;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
inDouble = false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (inBacktick) {
|
|
74
|
+
current += ch;
|
|
75
|
+
if (backslash && ch === "\\") {
|
|
76
|
+
if (next !== undefined) {
|
|
77
|
+
current += next;
|
|
78
|
+
i++;
|
|
79
|
+
}
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (ch === "`") {
|
|
83
|
+
if (next === "`") {
|
|
84
|
+
current += next;
|
|
85
|
+
i++;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
inBacktick = false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (ch === "-" && next === "-") {
|
|
94
|
+
inLineComment = true;
|
|
95
|
+
current += ch;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (ch === "/" && next === "*") {
|
|
99
|
+
inBlockComment = true;
|
|
100
|
+
current += ch;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (ch === "'") {
|
|
104
|
+
inSingle = true;
|
|
105
|
+
current += ch;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (ch === '"') {
|
|
109
|
+
inDouble = true;
|
|
110
|
+
current += ch;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (ch === "`") {
|
|
114
|
+
inBacktick = true;
|
|
115
|
+
current += ch;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (ch === ";") {
|
|
119
|
+
if (current.trim().length > 0) {
|
|
120
|
+
statements.push(current.trim());
|
|
121
|
+
}
|
|
122
|
+
current = "";
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
current += ch;
|
|
126
|
+
}
|
|
127
|
+
if (current.trim().length > 0) {
|
|
128
|
+
statements.push(current.trim());
|
|
129
|
+
}
|
|
130
|
+
return statements.length > 0 ? statements : [sql];
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=split-statements.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split-statements.js","sourceRoot":"","sources":["../../src/sql/split-statements.ts"],"names":[],"mappings":"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"}
|
package/docs/cli.md
CHANGED
|
@@ -30,7 +30,7 @@ neoorm generate [options]
|
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
Options:
|
|
33
|
-
- `-n, --name <name>` — migration name (e.g. `--name add_users`).
|
|
33
|
+
- `-n, --name <name>` — migration name (e.g. `--name add_users`). Only needed when a migration is created: prompts on a TTY at that point, errors in CI. Folders are `<timestamp>_<slug>` with the slug capped at 50 chars. No-change runs (client regeneration only) and pending-apply-only `dev` runs never prompt and succeed without `--name`.
|
|
34
34
|
- `--accept-data-loss` — include destructive DDL changes (column drops, type changes)
|
|
35
35
|
|
|
36
36
|
## `neoorm migrate dev`
|
|
@@ -41,7 +41,22 @@ Apply pending migrations, then generate a new migration if the schema changed. I
|
|
|
41
41
|
neoorm migrate dev --name <name>
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
- `-n, --name <name>` — same as `generate`:
|
|
44
|
+
- `-n, --name <name>` — same as `generate`: only needed when `dev` creates a migration, prompts on a TTY at that point, errors in CI. Applying pending migrations never requires `--name`. Not used by `deploy`, `status`, `reset`, or `down`.
|
|
45
|
+
|
|
46
|
+
## `neoorm migrate diff`
|
|
47
|
+
|
|
48
|
+
Preview the migration SQL `generate` / `migrate dev` would write, without writing anything.
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
neoorm migrate diff [--accept-data-loss] [--json]
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Read-only: diffs `schema.ts` against `snapshot.json` only. No database connection, no files written, and `--name` is never needed (ignored if passed). Shows the exact statements that would go into `migration.sql`, so you can inspect a change before naming it.
|
|
55
|
+
|
|
56
|
+
- `--accept-data-loss` — include destructive DDL in the preview (by default destructive changes are reported as blocked, same as `generate`)
|
|
57
|
+
- `--json` — print `{ schemaChanged, sql, blocked, destructiveBlocked, warnings }` instead of human-readable text
|
|
58
|
+
|
|
59
|
+
Exit code is `1` when destructive changes would block the migration (mirrors `generate`), `0` otherwise. For already-written but unapplied migrations, use `migrate status`.
|
|
45
60
|
|
|
46
61
|
## `neoorm migrate deploy`
|
|
47
62
|
|
|
@@ -86,6 +101,19 @@ neoorm migrate reset --force [--skip-apply]
|
|
|
86
101
|
|
|
87
102
|
PostgreSQL: the connecting role owns the recreated schema. `PUBLIC` is not granted.
|
|
88
103
|
|
|
104
|
+
## `neoorm seed`
|
|
105
|
+
|
|
106
|
+
Run a seed script against the database inside a single transaction. Any failure rolls the whole seed back.
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
neoorm seed [--env <name>] [--file <path>]
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
- `--env <name>` — run `seeds/<name>.ts` (next to `schema.ts`) instead of `seed.ts`
|
|
113
|
+
- `--file <path>` — run a specific seed file (wins over `--env` and config)
|
|
114
|
+
|
|
115
|
+
Resolution order: `--file` → config `seed.file` → `seeds/<env>.ts` → `seed.ts`. The client is compiled from `schema.ts`, so seeding works on a fresh checkout with no codegen. Write idempotent seeds (`upsert`, `findOrCreate`, `createMany` with `skipDuplicates`) — re-runs are by convention, there is no seed ledger. See [Seeding](seeding.md).
|
|
116
|
+
|
|
89
117
|
## `neoorm docs`
|
|
90
118
|
|
|
91
119
|
Serve the NeoOrm documentation locally in your browser.
|
package/docs/configuration.md
CHANGED
|
@@ -33,6 +33,8 @@ CLI commands load `.env` from the project directory before evaluating this file,
|
|
|
33
33
|
| `generate.zod` | `boolean` | `false` | Emit Select/Create/Update Zod schemas to `out/zod.ts`. See [Zod schemas](zod.md). |
|
|
34
34
|
| `generate.typebox` | `boolean` | `false` | Emit Select/Create/Update TypeBox schemas to `out/typebox.ts`. See [TypeBox schemas](typebox.md). |
|
|
35
35
|
| `generate.elysia` | `boolean` | `false` | Emit Select/Create/Update Elysia `t` schemas to `out/elysia.ts`. See [Elysia schemas](elysia.md). |
|
|
36
|
+
| `seed.file` | `string` | unset | Default seed file, project-root relative. CLI `--file` overrides it. See [Seeding](seeding.md). |
|
|
37
|
+
| `seed.env` | `string` | unset | Default environment: runs `seeds/<env>.ts` next to the schema. CLI `--env` overrides it. |
|
|
36
38
|
|
|
37
39
|
### Validation emit
|
|
38
40
|
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# `migrate dev` Workflow
|
|
2
|
+
|
|
3
|
+
This guide records the workflow contract and the implementation changes behind `neoorm migrate dev`. The refactor preserves the command's migration order and user-visible output timing.
|
|
4
|
+
|
|
5
|
+
## Runtime contract
|
|
6
|
+
|
|
7
|
+
`runMigrateDev` derives `migrationsDir` from `outDir` and runs the complete sequence inside `withMigrateDevLock`:
|
|
8
|
+
|
|
9
|
+
1. Read the snapshot, compile the target schema, reconcile pending `CREATE TABLE` migrations against the live database, then apply remaining pending migrations.
|
|
10
|
+
2. Generate from the current schema. If generation fails with the existing missing-migration-name error, no explicit name was supplied, and the CLI provided an interactive prompt callback, ask once and retry once. Other errors propagate unchanged. If generation needs no migration, it does not prompt.
|
|
11
|
+
3. Emit the generation summary and warnings, then reconcile a newly written migration against existing tables or apply it when reconciliation did not record it.
|
|
12
|
+
4. Return whether destructive changes were blocked; the CLI sets `process.exitCode` after the workflow completes.
|
|
13
|
+
|
|
14
|
+
The lock covers snapshot reading, both reconciliation/deployment phases, generation, and the optional prompt. Progress events keep the CLI output at the same stage as before: pending-migration output precedes a possible prompt, while generation output precedes post-generation reconciliation/application.
|
|
15
|
+
|
|
16
|
+
## File-by-file changes
|
|
17
|
+
|
|
18
|
+
### `src/migrate/dev-workflow.ts`
|
|
19
|
+
|
|
20
|
+
- **Before:** The ordered `migrate dev` sequence had no dedicated workflow module; the CLI path coordinated it.
|
|
21
|
+
- **After:** `runMigrateDev` owns snapshot reading, initial reconciliation/deployment, generation, the optional one-shot prompt/retry, and post-generation reconciliation/deployment. A typed progress-event union reports completed stages, while existing migration and code-generation helpers remain responsible for their work. The migration directory is derived from `outDir`.
|
|
22
|
+
- **Why it is useful:** The lock scope and ordering have one owner, and the workflow can be tested through a small interface without a CLI/TTY harness.
|
|
23
|
+
|
|
24
|
+
### `src/bin/neoorm.ts`
|
|
25
|
+
|
|
26
|
+
- **Before:** The CLI command path contained the `migrate dev` orchestration alongside the separate `migrate deploy` path.
|
|
27
|
+
- **After:** `migrate dev` calls `runMigrateDev`, adapts its progress events to the existing console output, supplies the prompt callback only for interactive runs, and handles the returned destructive-blocked status. `migrate deploy` remains on its separate path.
|
|
28
|
+
- **Why it is useful:** Terminal interaction and presentation stay in the CLI, while moving orchestration does not delay or reorder output around the prompt.
|
|
29
|
+
|
|
30
|
+
### `src/codegen/generate.ts`
|
|
31
|
+
|
|
32
|
+
- **Before:** The missing-migration-name predicate lived in the CLI even though both regular `generate` and `migrate dev` use it.
|
|
33
|
+
- **After:** The same predicate lives beside `missingMigrationNameError` in the code-generation module and is shared by both callers.
|
|
34
|
+
- **Why it is useful:** There is one definition of the narrow prompt-eligibility check; its error conditions are unchanged, not broadened into general error handling.
|
|
35
|
+
|
|
36
|
+
### `test/migrate-dev-workflow.test.ts`
|
|
37
|
+
|
|
38
|
+
- **Before:** Existing tests covered migration, generation, and lock helpers separately, but not their ordering at the workflow boundary.
|
|
39
|
+
- **After:** Real in-memory SQLite tests verify that a pending migration is applied and the lock remains held when the controlled name prompt runs, and that an unchanged schema completes without prompting or creating another migration.
|
|
40
|
+
- **Why it is useful:** The regression coverage checks observable database state and timing rather than mocked helper forwarding or CLI wiring.
|
|
41
|
+
|
|
42
|
+
### `docs/migrations.md`
|
|
43
|
+
|
|
44
|
+
- **Before:** The migration guide described command behavior but did not state the full `migrate dev` lock interval.
|
|
45
|
+
- **After:** It documents that the lock starts before pending reconciliation and remains held through the optional name prompt, generation, and post-generation reconciliation/application; it links to this implementation guide.
|
|
46
|
+
- **Why it is useful:** Readers can reason about concurrency and prompt timing from the documented contract.
|
|
47
|
+
|
|
48
|
+
### `llms-full.txt`
|
|
49
|
+
|
|
50
|
+
- **Before:** The generated documentation aggregate did not include the updated lock-lifetime note or this guide.
|
|
51
|
+
- **After:** Regeneration mirrors the migration-guide update and includes the new workflow page.
|
|
52
|
+
- **Why it is useful:** The aggregate stays aligned with the source documentation instead of presenting stale workflow details.
|
|
53
|
+
|
|
54
|
+
### `examples/blog/seed.ts`
|
|
55
|
+
|
|
56
|
+
- **Before:** The schema was imported as a runtime value even though it was used only for a type.
|
|
57
|
+
- **After:** The import is type-only.
|
|
58
|
+
- **Why it is useful:** TypeScript erases the import from emitted JavaScript, and lint no longer reports the type-only usage.
|
|
59
|
+
|
|
60
|
+
### `docs/migrate-dev-workflow.md`
|
|
61
|
+
|
|
62
|
+
- **Before:** There was no durable, file-by-file record of the workflow ownership, preserved behavior, and verification.
|
|
63
|
+
- **After:** This page records the execution contract, concrete before/after changes, and their rationale.
|
|
64
|
+
- **Why it is useful:** Future maintenance can distinguish an ownership refactor from an intended behavior change.
|
|
65
|
+
|
|
66
|
+
## Preserved behavior and scope
|
|
67
|
+
|
|
68
|
+
- Pending migrations are reconciled and applied before a missing name can be requested.
|
|
69
|
+
- The prompt is limited to the existing missing-name condition and is attempted at most once; unchanged schemas do not prompt.
|
|
70
|
+
- The migrate-dev lock remains held during the prompt and until post-generation reconciliation/application finishes.
|
|
71
|
+
- The existing second schema compilation remains; this change does not optimize it.
|
|
72
|
+
- `migrate deploy` keeps its separate execution path.
|
|
73
|
+
|
|
74
|
+
## Verification
|
|
75
|
+
|
|
76
|
+
The implementation verification below was recorded before this documentation continuation; it was not rerun as part of the documentation-only changes:
|
|
77
|
+
|
|
78
|
+
- `bun run build` — passed.
|
|
79
|
+
- `bun run test` — 128 files passed, 4 skipped; 1,215 tests passed, 42 skipped.
|
|
80
|
+
- `bun run typecheck` and `bun run lint` — passed; lint was clean.
|
|
81
|
+
- Focused migration suites — 4 files and 34 tests passed.
|
|
82
|
+
- CLI fixture smoke — `migrate dev --name initial`, a no-name no-op `migrate dev`, and a no-op `migrate deploy` each exited 0; the SQLite database had the expected table and one applied ledger entry.
|
|
83
|
+
|
|
84
|
+
The generated documentation is refreshed with `bun run docs:llms` after editing this page.
|
package/docs/migrations.md
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
| Command | Description |
|
|
6
6
|
|---------|-------------|
|
|
7
7
|
| `neoorm init` | Scaffold `neoorm.config.ts`, `schema.ts`, `.env.example` only (no codegen or migrations; run `neoorm migrate dev` after) |
|
|
8
|
-
| `neoorm generate --name <name
|
|
9
|
-
| `neoorm migrate dev --name <name
|
|
8
|
+
| `neoorm generate [--name <name>]` | Emit manifest, typed client, models, includes, and migrations (`--name` only when a migration is created) |
|
|
9
|
+
| `neoorm migrate dev [--name <name>]` | Apply pending migrations (or record colliding CREATE TABLE files against the live schema), then generate a new one if `schema.ts` changed (`--name` only when a new migration is created) |
|
|
10
|
+
| `neoorm migrate diff [--accept-data-loss] [--json]` | Preview the SQL a new migration would contain — no files written, no `--name` needed |
|
|
10
11
|
| `neoorm migrate deploy` | Apply pending migrations (throws `migration_drift` if a pending `CREATE TABLE` targets a relation that already exists) |
|
|
11
12
|
| `neoorm migrate status` | List applied vs pending migrations |
|
|
12
13
|
| `neoorm migrate down [--steps N]` | Roll back the last N applied migrations (default 1) |
|
|
@@ -25,7 +26,10 @@
|
|
|
25
26
|
| Migration created | New `migrations/<timestamp>_<name>/migration.sql` written |
|
|
26
27
|
| Migration blocked | Destructive or manual changes prevented writing SQL |
|
|
27
28
|
|
|
28
|
-
Migration names are slugified (`Add Users` → `add_users`, capped at 50 chars) and prefixed with a timestamp so folders sort in apply order. `--name` is
|
|
29
|
+
Migration names are slugified (`Add Users` → `add_users`, capped at 50 chars) and prefixed with a timestamp so folders sort in apply order. `--name` is only needed when a migration is created: the CLI prompts on a TTY at that point (after pending migrations are applied in `dev`) and errors in non-interactive runs. Runs with no schema changes (client regeneration only) and pending-apply-only `dev` runs succeed without `--name` and never prompt. Older `*_migration` folders still apply in order.
|
|
30
|
+
|
|
31
|
+
`migrate dev` holds its lock from before pending reconciliation through the optional name prompt, generation, and post-generation reconciliation/application.
|
|
32
|
+
For the implementation ordering and regression coverage, see [the workflow guide](migrate-dev-workflow.md).
|
|
29
33
|
|
|
30
34
|
When migration is blocked, the CLI explains why — for example unsupported type casts (`alter_column_type_manual`), enum value changes, or destructive drops. Re-run with `--accept-data-loss` to include destructive DDL:
|
|
31
35
|
|
|
@@ -33,6 +37,13 @@ When migration is blocked, the CLI explains why — for example unsupported type
|
|
|
33
37
|
neoorm generate --name add_users --accept-data-loss
|
|
34
38
|
```
|
|
35
39
|
|
|
40
|
+
To inspect the SQL before naming the migration, preview it first (read-only, needs no `--name`):
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
neoorm migrate diff
|
|
44
|
+
neoorm migrate diff --json
|
|
45
|
+
```
|
|
46
|
+
|
|
36
47
|
## Existing tables vs pending CREATE TABLE
|
|
37
48
|
|
|
38
49
|
`generate` diffs `snapshot.json`. If that file is missing, the first migration is a full `CREATE TABLE` script. `migrate deploy` will not run that SQL when those relations already exist (for example after `db push`). It throws `migration_drift` before any user statement.
|
package/docs/seeding.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Seeding
|
|
2
|
+
|
|
3
|
+
`neoorm seed` runs a seed script against the database inside a single transaction. Any failure rolls the whole seed back, so failed runs are safe to retry.
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
neoorm seed [--env <name>] [--file <path>]
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Seed files
|
|
10
|
+
|
|
11
|
+
By convention the seed lives next to the schema as `seed.ts` and exports a `seed(db)` function. `db` is a transaction-scoped client, so every write in the file is atomic:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// seed.ts
|
|
15
|
+
import type { TransactionClient } from "neoorm";
|
|
16
|
+
import { schema } from "./schema.js";
|
|
17
|
+
|
|
18
|
+
export async function seed(db: TransactionClient<typeof schema._tables>) {
|
|
19
|
+
await db.users.upsert({
|
|
20
|
+
where: { email: "admin@example.com" },
|
|
21
|
+
create: { email: "admin@example.com", name: "Admin" },
|
|
22
|
+
update: {},
|
|
23
|
+
});
|
|
24
|
+
await db.tags.createMany({
|
|
25
|
+
data: [
|
|
26
|
+
{ slug: "news", name: "News" },
|
|
27
|
+
{ slug: "guides", name: "Guides" },
|
|
28
|
+
],
|
|
29
|
+
skipDuplicates: true,
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Annotating with `TransactionClient<typeof schema._tables>` gives fully typed repositories — the same types as the generated client. A default-exported function works too, and `SeedContext` from `neoorm` is available for manifest-agnostic helpers.
|
|
35
|
+
|
|
36
|
+
## Environments
|
|
37
|
+
|
|
38
|
+
`--env <name>` runs `seeds/<name>.ts` instead of `seed.ts`:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
neoorm seed --env dev
|
|
42
|
+
neoorm seed --file ./seeds/manual.ts
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
`--file` wins over `--env`, and both win over config (see below).
|
|
46
|
+
|
|
47
|
+
## Idempotency
|
|
48
|
+
|
|
49
|
+
Seeds are re-run by convention — there is no seed ledger. Write seeds so running them twice is safe: `upsert`, `findOrCreate`, and `createMany({ skipDuplicates: true })` are the building blocks. The transaction guarantees all-or-nothing per run, not across runs.
|
|
50
|
+
|
|
51
|
+
## Configuration
|
|
52
|
+
|
|
53
|
+
Pin defaults in `neoorm.config.ts` (CLI flags override them):
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
export default defineConfig({
|
|
57
|
+
// ...
|
|
58
|
+
seed: { env: "dev", file: "./seeds/base.ts" },
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
| Key | Type | Description |
|
|
63
|
+
|-----|------|-------------|
|
|
64
|
+
| `seed.file` | `string` | Default seed file, project-root relative |
|
|
65
|
+
| `seed.env` | `string` | Default environment, runs `seeds/<env>.ts` next to the schema |
|
|
66
|
+
|
|
67
|
+
See [Configuration](configuration.md) for the full config reference.
|
package/docs/sqlite.md
CHANGED
|
@@ -60,6 +60,8 @@ const db = createNeoOrmClient(manifest, {
|
|
|
60
60
|
|
|
61
61
|
`busyTimeout` can also be a millisecond wait (`sqlite: { busyTimeout: 10_000 }`).
|
|
62
62
|
|
|
63
|
+
SQLite runs `search`/`REGEXP` patterns in-process as JavaScript `RegExp`, so a catastrophic-backtracking pattern (e.g. `(a+)+$`) could freeze the whole process. neoorm rejects patterns that nest unbounded quantifiers; pass `sqlite: { unsafeAllowRegex: true }` to allow them anyway.
|
|
64
|
+
|
|
63
65
|
### Custom driver
|
|
64
66
|
|
|
65
67
|
Pass any object implementing `prepare(sql)`, `exec(sql)`, and `close()` — the `node:sqlite` and `bun:sqlite` APIs both match. Useful for sandboxed runtimes or existing database handles:
|