@xubylele/schema-forge 1.2.0 → 1.5.0
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 +128 -13
- package/dist/cli.js +255 -911
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -8,7 +8,9 @@ A modern CLI tool for database schema management with a clean DSL and automatic
|
|
|
8
8
|
- **Migration Generation** - Automatically generate SQL migrations from schema changes
|
|
9
9
|
- **State Tracking** - Built-in state management to track your schema evolution
|
|
10
10
|
- **Type Safety** - Validates your schema before generating SQL
|
|
11
|
+
- **Default Change Detection** - Detects added/removed/modified column defaults and generates ALTER COLUMN SET/DROP DEFAULT
|
|
11
12
|
- **Postgres/Supabase** - Currently supports PostgreSQL and Supabase
|
|
13
|
+
- **Constraint Diffing** - Detects UNIQUE and PRIMARY KEY changes with deterministic constraint names
|
|
12
14
|
|
|
13
15
|
## Installation
|
|
14
16
|
|
|
@@ -78,15 +80,15 @@ Edit `schemaforge/schema.sf`:
|
|
|
78
80
|
|
|
79
81
|
table users {
|
|
80
82
|
id uuid pk
|
|
81
|
-
email varchar unique
|
|
82
|
-
name text
|
|
83
|
+
email varchar unique not null
|
|
84
|
+
name text not null
|
|
83
85
|
created_at timestamptz default now()
|
|
84
86
|
}
|
|
85
87
|
|
|
86
88
|
table posts {
|
|
87
89
|
id uuid pk
|
|
88
|
-
user_id uuid fk users.id
|
|
89
|
-
title varchar
|
|
90
|
+
user_id uuid fk users.id not null
|
|
91
|
+
title varchar not null
|
|
90
92
|
content text
|
|
91
93
|
published boolean default false
|
|
92
94
|
created_at timestamptz default now()
|
|
@@ -108,8 +110,8 @@ Edit `schemaforge/schema.sf` to add a new column:
|
|
|
108
110
|
```sql
|
|
109
111
|
table users {
|
|
110
112
|
id uuid pk
|
|
111
|
-
email varchar unique
|
|
112
|
-
name text
|
|
113
|
+
email varchar unique not null
|
|
114
|
+
name text not null
|
|
113
115
|
avatar_url text # New column!
|
|
114
116
|
created_at timestamptz default now()
|
|
115
117
|
}
|
|
@@ -131,6 +133,25 @@ schema-forge diff
|
|
|
131
133
|
|
|
132
134
|
If your schema matches the state file, you'll see "No changes detected". If there are changes, it will display the SQL that would be generated.
|
|
133
135
|
|
|
136
|
+
### Default value changes
|
|
137
|
+
|
|
138
|
+
Schema Forge also tracks default changes on existing columns when diffing `schema.sf` against `state.json`.
|
|
139
|
+
|
|
140
|
+
Supported migration output:
|
|
141
|
+
|
|
142
|
+
```sql
|
|
143
|
+
ALTER TABLE <table_name> ALTER COLUMN <column_name> SET DEFAULT <expr>;
|
|
144
|
+
ALTER TABLE <table_name> ALTER COLUMN <column_name> DROP DEFAULT;
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Examples:
|
|
148
|
+
|
|
149
|
+
- Add default: `created_at timestamptz` -> `created_at timestamptz default now()`
|
|
150
|
+
- Remove default: `created_at timestamptz default now()` -> `created_at timestamptz`
|
|
151
|
+
- Modify default: `default now()` -> `default timezone('utc', now())`
|
|
152
|
+
|
|
153
|
+
For common function-style defaults, comparisons are normalized to avoid obvious false positives (for example `NOW()` and `now()`).
|
|
154
|
+
|
|
134
155
|
## Commands
|
|
135
156
|
|
|
136
157
|
### `schema-forge init`
|
|
@@ -167,6 +188,99 @@ schema-forge diff
|
|
|
167
188
|
|
|
168
189
|
Shows what SQL would be generated if you ran `generate`. Useful for previewing changes.
|
|
169
190
|
|
|
191
|
+
### `schema-forge import`
|
|
192
|
+
|
|
193
|
+
Reconstruct `schemaforge/schema.sf` from existing PostgreSQL/Supabase SQL migrations.
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
schema-forge import <path-to-sql-file-or-migrations-dir>
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**Options:**
|
|
200
|
+
|
|
201
|
+
- `--out <path>` - Optional output schema file path (default: `schemaforge/schema.sf`)
|
|
202
|
+
|
|
203
|
+
Behavior:
|
|
204
|
+
|
|
205
|
+
- Parses supported DDL statements in order from a file or from sorted migration filenames in a directory
|
|
206
|
+
- Ignores unsupported SQL safely and prints warnings
|
|
207
|
+
- Writes a normalized SchemaForge DSL schema file
|
|
208
|
+
|
|
209
|
+
### `schema-forge validate`
|
|
210
|
+
|
|
211
|
+
Detect destructive or risky schema changes before generating/applying migrations.
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
schema-forge validate
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Validation checks include:
|
|
218
|
+
|
|
219
|
+
- Dropped tables (`DROP_TABLE`, error)
|
|
220
|
+
- Dropped columns (`DROP_COLUMN`, error)
|
|
221
|
+
- Column type changes (`ALTER_COLUMN_TYPE`, warning/error based on compatibility heuristics)
|
|
222
|
+
- Nullable to NOT NULL changes (`SET_NOT_NULL`, warning)
|
|
223
|
+
|
|
224
|
+
Use JSON mode for CI and automation:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
schema-forge validate --json
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Exit codes:
|
|
231
|
+
|
|
232
|
+
- `1` when one or more `error` findings are detected
|
|
233
|
+
- `0` when no `error` findings are detected (warnings alone do not fail)
|
|
234
|
+
|
|
235
|
+
## Constraint Change Detection
|
|
236
|
+
|
|
237
|
+
SchemaForge detects and generates migrations for:
|
|
238
|
+
|
|
239
|
+
- Column-level `unique` added/removed
|
|
240
|
+
- Table primary key added/removed/changed (single-column PK)
|
|
241
|
+
|
|
242
|
+
### Deterministic Constraint Names
|
|
243
|
+
|
|
244
|
+
To keep migrations stable and safe to drop later, generated constraint names are deterministic:
|
|
245
|
+
|
|
246
|
+
- Primary key: `pk_<table>` (example: `pk_users`)
|
|
247
|
+
- Unique (column): `uq_<table>_<column>` (example: `uq_users_email`)
|
|
248
|
+
|
|
249
|
+
Identifiers are normalized to lowercase, non-alphanumeric characters are replaced with `_`, and repeated `_` are collapsed.
|
|
250
|
+
|
|
251
|
+
### Generated SQL Examples
|
|
252
|
+
|
|
253
|
+
Add unique:
|
|
254
|
+
|
|
255
|
+
```sql
|
|
256
|
+
ALTER TABLE users ADD CONSTRAINT uq_users_email UNIQUE (email);
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Remove unique:
|
|
260
|
+
|
|
261
|
+
```sql
|
|
262
|
+
ALTER TABLE users DROP CONSTRAINT IF EXISTS uq_users_email;
|
|
263
|
+
ALTER TABLE users DROP CONSTRAINT IF EXISTS users_email_key;
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Change primary key column (`id` -> `user_id`):
|
|
267
|
+
|
|
268
|
+
```sql
|
|
269
|
+
ALTER TABLE users DROP CONSTRAINT IF EXISTS pk_users;
|
|
270
|
+
ALTER TABLE users DROP CONSTRAINT IF EXISTS users_pkey;
|
|
271
|
+
|
|
272
|
+
ALTER TABLE users ADD CONSTRAINT pk_users PRIMARY KEY (user_id);
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
When dropping constraints, SchemaForge attempts deterministic names first, then PostgreSQL legacy defaults (`<table>_pkey`, `<table>_<column>_key`) for compatibility.
|
|
276
|
+
|
|
277
|
+
Also includes nullability migrations when `not null` is added or removed:
|
|
278
|
+
|
|
279
|
+
```sql
|
|
280
|
+
ALTER TABLE users ALTER COLUMN email SET NOT NULL;
|
|
281
|
+
ALTER TABLE users ALTER COLUMN email DROP NOT NULL;
|
|
282
|
+
```
|
|
283
|
+
|
|
170
284
|
## Schema DSL Format
|
|
171
285
|
|
|
172
286
|
Schemas are defined using the `.sf` format with a clean, readable syntax.
|
|
@@ -195,7 +309,8 @@ table table_name {
|
|
|
195
309
|
|
|
196
310
|
- `pk` - Primary key
|
|
197
311
|
- `unique` - Unique constraint
|
|
198
|
-
- `
|
|
312
|
+
- `not null` - Disallow NULL values
|
|
313
|
+
- `nullable` - Allow NULL values (default when `not null` is not provided)
|
|
199
314
|
- `default <value>` - Default value (e.g., `default now()`, `default false`, `default 0`)
|
|
200
315
|
- `fk <table>.<column>` - Foreign key reference (e.g., `fk users.id`)
|
|
201
316
|
|
|
@@ -206,8 +321,8 @@ table table_name {
|
|
|
206
321
|
```sql
|
|
207
322
|
table users {
|
|
208
323
|
id uuid pk
|
|
209
|
-
email varchar unique
|
|
210
|
-
name text
|
|
324
|
+
email varchar unique not null
|
|
325
|
+
name text not null
|
|
211
326
|
created_at timestamptz default now()
|
|
212
327
|
}
|
|
213
328
|
```
|
|
@@ -217,20 +332,20 @@ table users {
|
|
|
217
332
|
```sql
|
|
218
333
|
table posts {
|
|
219
334
|
id uuid pk
|
|
220
|
-
author_id uuid fk users.id
|
|
221
|
-
title varchar
|
|
335
|
+
author_id uuid fk users.id not null
|
|
336
|
+
title varchar not null
|
|
222
337
|
content text
|
|
223
338
|
published boolean default false
|
|
224
339
|
created_at timestamptz default now()
|
|
225
340
|
}
|
|
226
341
|
```
|
|
227
342
|
|
|
228
|
-
#### Table with
|
|
343
|
+
#### Table with mixed nullability
|
|
229
344
|
|
|
230
345
|
```sql
|
|
231
346
|
table profiles {
|
|
232
347
|
id uuid pk
|
|
233
|
-
user_id uuid fk users.id
|
|
348
|
+
user_id uuid fk users.id not null
|
|
234
349
|
bio text nullable
|
|
235
350
|
avatar_url text nullable
|
|
236
351
|
website varchar nullable
|