bigal 16.0.0-beta.2 → 16.0.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/.devcontainer/devcontainer.json +1 -1
- package/.vite-hooks/pre-commit +1 -0
- package/CHANGELOG.md +28 -8
- package/CLAUDE.md +4 -4
- package/README.md +29 -43
- package/dist/index.cjs +3275 -4259
- package/dist/index.d.cts +1511 -1424
- package/dist/index.d.mts +1511 -1424
- package/dist/index.mjs +3265 -4225
- package/docs/.vitepress/config.ts +0 -1
- package/docs/advanced/bigal-vs-raw-sql.md +23 -23
- package/docs/advanced/known-issues.md +26 -21
- package/docs/getting-started.md +35 -29
- package/docs/guide/crud-operations.md +42 -61
- package/docs/guide/models.md +97 -396
- package/docs/guide/querying.md +82 -83
- package/docs/guide/relationships.md +125 -90
- package/docs/guide/subqueries-and-joins.md +39 -32
- package/docs/guide/views.md +51 -79
- package/docs/index.md +31 -27
- package/docs/package.json +3 -2
- package/docs/pnpm-lock.yaml +2338 -0
- package/docs/pnpm-workspace.yaml +3 -0
- package/docs/reference/api.md +86 -384
- package/docs/reference/configuration.md +26 -113
- package/package.json +59 -73
- package/pnpm-workspace.yaml +14 -0
- package/release.config.mjs +1 -1
- package/skills/using-bigal/SKILL.md +213 -276
- package/vite.config.ts +83 -0
- package/.husky/pre-commit +0 -4
- package/.oxfmtrc.json +0 -38
- package/.oxlintrc.json +0 -219
- package/dist/index.d.ts +0 -1526
- package/docs/guide/migration-v16.md +0 -594
- package/docs/package-lock.json +0 -3753
- package/scripts/migrate-v16.ts +0 -497
- package/skills/upgrade-v16/SKILL.md +0 -244
|
@@ -1,244 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: upgrading-bigal-v16
|
|
3
|
-
description: Migrates BigAl projects from v15 decorator-based models to v16 function-based table() API. Use when upgrading BigAl, converting decorator models, or migrating from class-based Entity models to the new schema API.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Upgrading to BigAl v16
|
|
7
|
-
|
|
8
|
-
## Quick Start
|
|
9
|
-
|
|
10
|
-
v16 replaces decorators with function-based schema definitions. No classes,
|
|
11
|
-
no `experimentalDecorators`, no `extends Entity`.
|
|
12
|
-
|
|
13
|
-
**Before (v15):**
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
import { column, primaryColumn, table, Entity, initialize } from 'bigal';
|
|
17
|
-
|
|
18
|
-
@table({ name: 'products' })
|
|
19
|
-
class Product extends Entity {
|
|
20
|
-
@primaryColumn({ type: 'integer' })
|
|
21
|
-
public id!: number;
|
|
22
|
-
|
|
23
|
-
@column({ type: 'string', required: true })
|
|
24
|
-
public name!: string;
|
|
25
|
-
|
|
26
|
-
@column({ model: 'Store', name: 'store_id' })
|
|
27
|
-
public store!: Store | number;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const repos = initialize({ models: [Product, Store], pool });
|
|
31
|
-
const Product = repos.Product as Repository<Product>;
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
**After (v16):**
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
import { defineTable as table, serial, text, belongsTo, initialize } from 'bigal';
|
|
38
|
-
import type { Repository } from 'bigal';
|
|
39
|
-
|
|
40
|
-
const Product = table('products', {
|
|
41
|
-
id: serial().primaryKey(),
|
|
42
|
-
name: text().notNull(),
|
|
43
|
-
store: belongsTo('Store'),
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
const { Product } = initialize({ pool, models: { Product, Store } });
|
|
47
|
-
// Product is Repository<typeof Product> -- fully typed, no assertion needed
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Migration Steps
|
|
51
|
-
|
|
52
|
-
### Step 1: Convert model files
|
|
53
|
-
|
|
54
|
-
For each model class, create a `table()` call:
|
|
55
|
-
|
|
56
|
-
| v15 Decorator | v16 Builder |
|
|
57
|
-
| --------------------------------------------------------- | --------------------------------------- |
|
|
58
|
-
| `@primaryColumn({ type: 'integer' })` | `serial().primaryKey()` |
|
|
59
|
-
| `@column({ type: 'string', required: true })` | `text().notNull()` |
|
|
60
|
-
| `@column({ type: 'string' })` | `text()` |
|
|
61
|
-
| `@column({ type: 'integer' })` | `integer()` |
|
|
62
|
-
| `@column({ type: 'float' })` | `float()` |
|
|
63
|
-
| `@column({ type: 'boolean' })` | `boolean()` |
|
|
64
|
-
| `@column({ type: 'json' })` | `jsonb()` |
|
|
65
|
-
| `@column({ type: 'datetime' })` | `timestamptz()` |
|
|
66
|
-
| `@column({ type: 'date' })` | `date()` |
|
|
67
|
-
| `@column({ type: 'uuid' })` | `uuid()` |
|
|
68
|
-
| `@column({ type: 'binary' })` | `bytea()` |
|
|
69
|
-
| `@column({ type: 'string[]' })` | `textArray()` |
|
|
70
|
-
| `@column({ type: 'integer[]' })` | `integerArray()` |
|
|
71
|
-
| `@column({ type: 'boolean[]' })` | `booleanArray()` |
|
|
72
|
-
| `@createDateColumn()` | `createdAt()` |
|
|
73
|
-
| `@updateDateColumn()` | `updatedAt()` |
|
|
74
|
-
| `@versionColumn()` | `integer().version()` |
|
|
75
|
-
| `@column({ model: 'Store', name: 'store_id' })` | `belongsTo('Store')` |
|
|
76
|
-
| `@column({ collection: 'Product', via: 'store' })` | `hasMany('Product').via('store')` |
|
|
77
|
-
| `@column({ collection: 'Cat', through: 'PC', via: 'p' })` | `hasMany('Cat').through('PC').via('p')` |
|
|
78
|
-
|
|
79
|
-
Column names auto-derive from property keys via snakeCase. Only specify
|
|
80
|
-
a name when the convention doesn't match:
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
aliases: textArray({ name: 'alias_names' }).default([]),
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Step 2: Replace class inheritance with spread
|
|
87
|
-
|
|
88
|
-
Only extract a shared base for columns that genuinely appear in every model (typically
|
|
89
|
-
`id` + timestamps). Domain-specific columns like `organization: belongsTo(...)` should
|
|
90
|
-
stay inline in each model, even if repeated. A bit of repetition is better than a hierarchy
|
|
91
|
-
of base objects that becomes hard to maintain.
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
// Before
|
|
95
|
-
abstract class ModelBase extends Entity {
|
|
96
|
-
@primaryColumn({ type: 'integer' }) public id!: number;
|
|
97
|
-
@createDateColumn() public createdAt!: Date;
|
|
98
|
-
@updateDateColumn() public updatedAt!: Date;
|
|
99
|
-
}
|
|
100
|
-
class Product extends ModelBase { ... }
|
|
101
|
-
|
|
102
|
-
// After - one shared base for universal columns
|
|
103
|
-
const modelBase = {
|
|
104
|
-
id: serial().primaryKey(),
|
|
105
|
-
createdAt: createdAt(),
|
|
106
|
-
updatedAt: updatedAt(),
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
const Product = table('products', {
|
|
110
|
-
...modelBase,
|
|
111
|
-
name: text().notNull(),
|
|
112
|
-
organization: belongsTo<string>('Organization'),
|
|
113
|
-
});
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
**Avoid** creating a hierarchy of base objects like `orgBase`, `accountingBase`, etc.
|
|
117
|
-
Each model should declare its own relationships and domain columns inline. Use
|
|
118
|
-
`QueryResult<typeof Product>` for the row type instead of creating separate base row types.
|
|
119
|
-
|
|
120
|
-
### Step 3: Convert hooks
|
|
121
|
-
|
|
122
|
-
Move static `beforeCreate`/`beforeUpdate` methods to table options.
|
|
123
|
-
v16 supports all 7 lifecycle hooks:
|
|
124
|
-
|
|
125
|
-
```typescript
|
|
126
|
-
// Before
|
|
127
|
-
class Product extends Entity {
|
|
128
|
-
static override beforeCreate(values) {
|
|
129
|
-
return { ...values, slug: slugify(values.name) };
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// After
|
|
134
|
-
const Product = table(
|
|
135
|
-
'products',
|
|
136
|
-
{ ...columns },
|
|
137
|
-
{
|
|
138
|
-
hooks: {
|
|
139
|
-
beforeCreate(values) {
|
|
140
|
-
return { ...values, slug: slugify(values.name) };
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
);
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
Available hooks: `beforeCreate`, `afterCreate`, `beforeUpdate`,
|
|
148
|
-
`afterUpdate`, `beforeDestroy`, `afterDestroy`, `afterFind`.
|
|
149
|
-
|
|
150
|
-
### Step 4: Convert initialization
|
|
151
|
-
|
|
152
|
-
```typescript
|
|
153
|
-
// Before
|
|
154
|
-
const repos = initialize({ models: [Product, Store], pool });
|
|
155
|
-
const Product = repos.Product as Repository<Product>;
|
|
156
|
-
|
|
157
|
-
// After -- object style (typed destructuring, recommended)
|
|
158
|
-
const { Product, Store } = initialize({
|
|
159
|
-
pool,
|
|
160
|
-
models: { Product, Store },
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
// After -- array style (use getRepository)
|
|
164
|
-
const bigal = initialize({ pool, models: [Product, Store] });
|
|
165
|
-
const Product = bigal.getRepository(Product);
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### Step 5: Remove old imports and config
|
|
169
|
-
|
|
170
|
-
- Remove `extends Entity` from all classes
|
|
171
|
-
- Remove `import { Entity, column, primaryColumn, ... } from 'bigal'`
|
|
172
|
-
- Remove `experimentalDecorators: true` from tsconfig.json
|
|
173
|
-
- Remove `useDefineForClassFields: false` from tsconfig.json
|
|
174
|
-
- Remove `NotEntity<T>` wrappers - no longer needed
|
|
175
|
-
- Remove redundant `{ name: '...' }` options where the column name matches the auto-derived
|
|
176
|
-
snakeCase (e.g., `priceCents: integer({ name: 'price_cents' })` should be just
|
|
177
|
-
`priceCents: integer()`)
|
|
178
|
-
|
|
179
|
-
### Step 6: Update type references
|
|
180
|
-
|
|
181
|
-
```typescript
|
|
182
|
-
// Before (v15)
|
|
183
|
-
let product: Product;
|
|
184
|
-
let params: CreateUpdateParams<Product>;
|
|
185
|
-
let result: QueryResult<Product>;
|
|
186
|
-
|
|
187
|
-
// After (v16) - use typeof Model everywhere
|
|
188
|
-
import type { QueryResult, CreateUpdateParams, InferInsert, Repository } from 'bigal';
|
|
189
|
-
|
|
190
|
-
let product: QueryResult<typeof Product>;
|
|
191
|
-
let params: CreateUpdateParams<QueryResult<typeof Product>>;
|
|
192
|
-
let insert: InferInsert<(typeof Product)['schema']>;
|
|
193
|
-
|
|
194
|
-
// For repository type annotations:
|
|
195
|
-
function getProducts(repo: Repository<typeof Product>) {
|
|
196
|
-
/* ... */
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
Use `typeof Product` as the single source of truth for all type references:
|
|
201
|
-
|
|
202
|
-
- `QueryResult<typeof Product>` - row type for query results (narrows FKs, excludes hasMany)
|
|
203
|
-
- `CreateUpdateParams<QueryResult<typeof Product>>` - partial type for create/update
|
|
204
|
-
- `Repository<typeof Product>` - typed repository
|
|
205
|
-
- `InferInsert<(typeof Product)['schema']>` - insert params with required/optional awareness
|
|
206
|
-
|
|
207
|
-
## Removed Exports
|
|
208
|
-
|
|
209
|
-
These v15 exports no longer exist:
|
|
210
|
-
|
|
211
|
-
- `Entity`, `EntityStatic`, `NotEntity`, `NotEntityBrand`
|
|
212
|
-
- `column`, `primaryColumn`, `createDateColumn`, `updateDateColumn`,
|
|
213
|
-
`versionColumn` (decorators)
|
|
214
|
-
- `table` decorator (replaced by `table` function, exported as
|
|
215
|
-
`defineTable`)
|
|
216
|
-
- `getMetadataStorage`, `MetadataStorage`
|
|
217
|
-
|
|
218
|
-
## New Features in v16
|
|
219
|
-
|
|
220
|
-
- `view()` - define readonly models backed by PostgreSQL views
|
|
221
|
-
- `toSQL()` - inspect generated SQL without executing on any operation
|
|
222
|
-
- `onQuery` - observability callback on `initialize()`
|
|
223
|
-
- Global filters - auto-applied where clauses (soft delete,
|
|
224
|
-
multi-tenancy)
|
|
225
|
-
- All 7 lifecycle hooks - `beforeCreate`, `afterCreate`,
|
|
226
|
-
`beforeUpdate`, `afterUpdate`, `beforeDestroy`, `afterDestroy`,
|
|
227
|
-
`afterFind`
|
|
228
|
-
- String references - `belongsTo('Store')` with model name strings only
|
|
229
|
-
- Auto-derived names - column names from property keys, model names
|
|
230
|
-
from table names
|
|
231
|
-
- pgvector - `vector({ dimensions })` with nearest-neighbor sort and
|
|
232
|
-
distance filtering
|
|
233
|
-
- `Repository<typeof Product>` - type alias for typed repository
|
|
234
|
-
annotations
|
|
235
|
-
|
|
236
|
-
## Guidelines
|
|
237
|
-
|
|
238
|
-
- Run the codemod first for mechanical conversions:
|
|
239
|
-
`npx tsx scripts/migrate-v16.ts 'src/models/**/*.ts'`
|
|
240
|
-
- Convert one model at a time and verify tests pass
|
|
241
|
-
- Instance methods on Entity classes should become `afterFind` hooks or
|
|
242
|
-
standalone functions
|
|
243
|
-
- The query API (`find`, `findOne`, `create`, `update`, `destroy`,
|
|
244
|
-
`populate`, `where`, `sort`) is unchanged
|