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
|
@@ -68,7 +68,6 @@ export default defineConfig({
|
|
|
68
68
|
{ text: 'Relationships', link: '/guide/relationships' },
|
|
69
69
|
{ text: 'Subqueries & Joins', link: '/guide/subqueries-and-joins' },
|
|
70
70
|
{ text: 'Views', link: '/guide/views' },
|
|
71
|
-
{ text: 'Migrating to v16', link: '/guide/migration-v16' },
|
|
72
71
|
],
|
|
73
72
|
},
|
|
74
73
|
{
|
|
@@ -29,35 +29,35 @@ Drop to raw SQL (via your pool directly) when:
|
|
|
29
29
|
|
|
30
30
|
### Basic queries
|
|
31
31
|
|
|
32
|
-
| SQL | BigAl
|
|
33
|
-
| ----------------------------------------------------- |
|
|
34
|
-
| `SELECT * FROM products WHERE id = 1` | `
|
|
35
|
-
| `SELECT name FROM products WHERE id = 1` | `
|
|
36
|
-
| `SELECT * FROM products WHERE name ILIKE '%widget%'` | `
|
|
37
|
-
| `SELECT * FROM products WHERE price >= 100` | `
|
|
38
|
-
| `SELECT * FROM products WHERE status IN ('a','b')` | `
|
|
39
|
-
| `SELECT * FROM products WHERE status <> 'x'` | `
|
|
40
|
-
| `SELECT * FROM products WHERE deleted_at IS NOT NULL` | `
|
|
41
|
-
| `SELECT * FROM products ORDER BY name LIMIT 10` | `
|
|
42
|
-
| `SELECT COUNT(*) FROM products WHERE active = true` | `
|
|
32
|
+
| SQL | BigAl |
|
|
33
|
+
| ----------------------------------------------------- | ------------------------------------------------------------ |
|
|
34
|
+
| `SELECT * FROM products WHERE id = 1` | `productRepo.findOne().where({ id: 1 })` |
|
|
35
|
+
| `SELECT name FROM products WHERE id = 1` | `productRepo.findOne({ select: ['name'] }).where({ id: 1 })` |
|
|
36
|
+
| `SELECT * FROM products WHERE name ILIKE '%widget%'` | `productRepo.find().where({ name: { contains: 'widget' } })` |
|
|
37
|
+
| `SELECT * FROM products WHERE price >= 100` | `productRepo.find().where({ price: { '>=': 100 } })` |
|
|
38
|
+
| `SELECT * FROM products WHERE status IN ('a','b')` | `productRepo.find().where({ status: ['a', 'b'] })` |
|
|
39
|
+
| `SELECT * FROM products WHERE status <> 'x'` | `productRepo.find().where({ status: { '!': 'x' } })` |
|
|
40
|
+
| `SELECT * FROM products WHERE deleted_at IS NOT NULL` | `productRepo.find().where({ deletedAt: { '!': null } })` |
|
|
41
|
+
| `SELECT * FROM products ORDER BY name LIMIT 10` | `productRepo.find().where({}).sort('name asc').limit(10)` |
|
|
42
|
+
| `SELECT COUNT(*) FROM products WHERE active = true` | `productRepo.count().where({ active: true })` |
|
|
43
43
|
|
|
44
44
|
### CRUD
|
|
45
45
|
|
|
46
|
-
| SQL | BigAl
|
|
47
|
-
| ----------------------------------------------------------- |
|
|
48
|
-
| `INSERT INTO products (name) VALUES ('Widget') RETURNING *` | `
|
|
49
|
-
| `UPDATE products SET name = 'X' WHERE id = 1 RETURNING *` | `
|
|
50
|
-
| `DELETE FROM products WHERE id = 1 RETURNING *` | `
|
|
46
|
+
| SQL | BigAl |
|
|
47
|
+
| ----------------------------------------------------------- | ---------------------------------------------- |
|
|
48
|
+
| `INSERT INTO products (name) VALUES ('Widget') RETURNING *` | `productRepo.create({ name: 'Widget' })` |
|
|
49
|
+
| `UPDATE products SET name = 'X' WHERE id = 1 RETURNING *` | `productRepo.update({ id: 1 }, { name: 'X' })` |
|
|
50
|
+
| `DELETE FROM products WHERE id = 1 RETURNING *` | `productRepo.destroy({ id: 1 })` |
|
|
51
51
|
|
|
52
52
|
### Subqueries, joins, and advanced
|
|
53
53
|
|
|
54
|
-
| SQL | BigAl
|
|
55
|
-
| ------------------------------------------------------------------------ |
|
|
56
|
-
| `WHERE store_id IN (SELECT id FROM stores WHERE active)` | `.where({ store: { in: subquery(
|
|
57
|
-
| `INNER JOIN stores s ON p.store_id = s.id WHERE s.name = 'Acme'` | `.join('store').where({ store: { name: 'Acme' } })`
|
|
58
|
-
| `SELECT DISTINCT ON (store_id) * ... ORDER BY store_id, created_at DESC` | `.distinctOn(['store']).sort('store').sort('createdAt desc')`
|
|
59
|
-
| `ON CONFLICT (sku) DO NOTHING` | `{ onConflict: { action: 'ignore', targets: ['sku'] } }`
|
|
60
|
-
| `ON CONFLICT (sku) DO UPDATE SET name = EXCLUDED.name` | `{ onConflict: { action: 'merge', targets: ['sku'], merge: ['name'] } }`
|
|
54
|
+
| SQL | BigAl |
|
|
55
|
+
| ------------------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
|
|
56
|
+
| `WHERE store_id IN (SELECT id FROM stores WHERE active)` | `.where({ store: { in: subquery(storeRepo).select(['id']).where({ active: true }) } })` |
|
|
57
|
+
| `INNER JOIN stores s ON p.store_id = s.id WHERE s.name = 'Acme'` | `.join('store').where({ store: { name: 'Acme' } })` |
|
|
58
|
+
| `SELECT DISTINCT ON (store_id) * ... ORDER BY store_id, created_at DESC` | `.distinctOn(['store']).sort('store').sort('createdAt desc')` |
|
|
59
|
+
| `ON CONFLICT (sku) DO NOTHING` | `{ onConflict: { action: 'ignore', targets: ['sku'] } }` |
|
|
60
|
+
| `ON CONFLICT (sku) DO UPDATE SET name = EXCLUDED.name` | `{ onConflict: { action: 'merge', targets: ['sku'], merge: ['name'] } }` |
|
|
61
61
|
|
|
62
62
|
## Mixing BigAl and raw SQL
|
|
63
63
|
|
|
@@ -1,42 +1,47 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Known issues and workarounds
|
|
2
|
+
description: Known issues and workarounds — optional collections, NotEntity for JSON objects with id fields, and DEBUG_BIGAL logging.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# Known Issues
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## Entity collections must be optional
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
on query results after calling `.populate()`:
|
|
9
|
+
Collection properties (one-to-many, many-to-many) must be declared as optional. They are only present after `.populate()` and will cause `QueryResult` type errors if required:
|
|
11
10
|
|
|
12
11
|
```ts
|
|
13
|
-
//
|
|
14
|
-
|
|
12
|
+
// Correct
|
|
13
|
+
@column({ collection: () => 'Product', via: 'store' })
|
|
14
|
+
public products?: Product[];
|
|
15
15
|
|
|
16
|
-
//
|
|
17
|
-
|
|
16
|
+
// Incorrect — causes type issues
|
|
17
|
+
@column({ collection: () => 'Product', via: 'store' })
|
|
18
|
+
public products!: Product[];
|
|
18
19
|
```
|
|
19
20
|
|
|
20
|
-
##
|
|
21
|
+
## Non-entity objects with id fields
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
If a JSON column contains objects with an `id` property, TypeScript may mistake them for BigAl entities. Wrap the type with `NotEntity<T>`:
|
|
23
24
|
|
|
24
25
|
```ts
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
import type { NotEntity } from 'bigal';
|
|
27
|
+
|
|
28
|
+
interface IMyJsonType {
|
|
29
|
+
id: string;
|
|
30
|
+
foo: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@column({ type: 'json' })
|
|
34
|
+
public metadata?: NotEntity<IMyJsonType>;
|
|
32
35
|
```
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
Without `NotEntity`, BigAl's type system treats the type as an entity relationship, which leads to incorrect type narrowing in `QueryResult`.
|
|
38
|
+
|
|
39
|
+
## Debugging queries
|
|
40
|
+
|
|
41
|
+
Set the `DEBUG_BIGAL` environment variable to see generated SQL:
|
|
36
42
|
|
|
37
43
|
```sh
|
|
38
44
|
DEBUG_BIGAL=true node app.js
|
|
39
45
|
```
|
|
40
46
|
|
|
41
|
-
This logs all SQL statements and parameter values to the console.
|
|
42
|
-
sensitive data.
|
|
47
|
+
This logs all SQL statements and parameter values to the console.
|
package/docs/getting-started.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Install BigAl, define your first model,
|
|
2
|
+
description: Install BigAl, define your first model with decorators, initialize a repository, and run type-safe PostgreSQL queries.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# Getting Started
|
|
@@ -25,56 +25,63 @@ npm install @neondatabase/serverless
|
|
|
25
25
|
|
|
26
26
|
## Define a model
|
|
27
27
|
|
|
28
|
-
Models
|
|
29
|
-
inferred from the schema definition. Column names are auto-derived from property keys using snakeCase.
|
|
28
|
+
Models extend `Entity` and use decorators to map to database tables.
|
|
30
29
|
|
|
31
30
|
```ts
|
|
32
|
-
import {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
31
|
+
import { column, primaryColumn, table, Entity } from 'bigal';
|
|
32
|
+
|
|
33
|
+
@table({ name: 'products' })
|
|
34
|
+
export class Product extends Entity {
|
|
35
|
+
@primaryColumn({ type: 'integer' })
|
|
36
|
+
public id!: number;
|
|
37
|
+
|
|
38
|
+
@column({ type: 'string', required: true })
|
|
39
|
+
public name!: string;
|
|
40
|
+
|
|
41
|
+
@column({ type: 'string' })
|
|
42
|
+
public sku?: string;
|
|
43
|
+
|
|
44
|
+
@column({ type: 'integer', required: true, name: 'price_cents' })
|
|
45
|
+
public priceCents!: number;
|
|
46
|
+
}
|
|
42
47
|
```
|
|
43
48
|
|
|
44
49
|
## Initialize repositories
|
|
45
50
|
|
|
46
|
-
Pass your models and a connection pool to `initialize()`.
|
|
47
|
-
typed repositories directly via destructuring:
|
|
51
|
+
Pass your models and a connection pool to `initialize()`. It returns a map of repositories keyed by model name.
|
|
48
52
|
|
|
49
53
|
```ts
|
|
50
|
-
import { initialize } from 'bigal';
|
|
54
|
+
import { initialize, Repository } from 'bigal';
|
|
51
55
|
import { Pool } from 'postgres-pool';
|
|
52
56
|
import { Product } from './Product';
|
|
53
57
|
|
|
54
58
|
const pool = new Pool('postgres://localhost/mydb');
|
|
55
59
|
|
|
56
|
-
const
|
|
57
|
-
models:
|
|
60
|
+
const repos = initialize({
|
|
61
|
+
models: [Product],
|
|
58
62
|
pool,
|
|
59
63
|
});
|
|
64
|
+
|
|
65
|
+
const productRepository = repos.Product as Repository<Product>;
|
|
60
66
|
```
|
|
61
67
|
|
|
62
68
|
## Run your first query
|
|
63
69
|
|
|
64
|
-
Queries use a fluent builder and are `PromiseLike`
|
|
70
|
+
Queries use a fluent builder and are `PromiseLike` — just `await` the chain.
|
|
65
71
|
|
|
66
72
|
```ts
|
|
67
73
|
// Find all products with price >= 1000 cents, sorted by name
|
|
68
|
-
const products = await
|
|
74
|
+
const products = await productRepository
|
|
75
|
+
.find()
|
|
69
76
|
.where({ priceCents: { '>=': 1000 } })
|
|
70
77
|
.sort('name asc')
|
|
71
78
|
.limit(10);
|
|
72
79
|
|
|
73
80
|
// Find one product by ID
|
|
74
|
-
const product = await
|
|
81
|
+
const product = await productRepository.findOne().where({ id: 42 });
|
|
75
82
|
|
|
76
83
|
// Count matching records
|
|
77
|
-
const count = await
|
|
84
|
+
const count = await productRepository.count().where({ sku: { '!': null } });
|
|
78
85
|
```
|
|
79
86
|
|
|
80
87
|
## Using with AI assistants
|
|
@@ -88,13 +95,12 @@ npx skills add bigalorm/bigal
|
|
|
88
95
|
|
|
89
96
|
Machine-readable documentation is also available:
|
|
90
97
|
|
|
91
|
-
- [llms.txt](/llms.txt)
|
|
92
|
-
- [llms-full.txt](/llms-full.txt)
|
|
98
|
+
- [llms.txt](/llms.txt) — structured overview
|
|
99
|
+
- [llms-full.txt](/llms-full.txt) — complete documentation in a single file
|
|
93
100
|
|
|
94
101
|
## Next steps
|
|
95
102
|
|
|
96
|
-
- [Models](/guide/models)
|
|
97
|
-
- [Querying](/guide/querying)
|
|
98
|
-
- [CRUD Operations](/guide/crud-operations)
|
|
99
|
-
- [API Reference](/reference/api)
|
|
100
|
-
- [Migrating from v15](/guide/migration-v16) - upgrade from decorators to the new API
|
|
103
|
+
- [Models](/guide/models) — decorators, relationships, and Entity types
|
|
104
|
+
- [Querying](/guide/querying) — operators, pagination, JSONB, and more
|
|
105
|
+
- [CRUD Operations](/guide/crud-operations) — create, update, and destroy
|
|
106
|
+
- [API Reference](/reference/api) — all exports and method signatures
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Create, update, and destroy records with RETURNING support, query projection,
|
|
2
|
+
description: Create, update, and destroy records with RETURNING support, query projection, and ON CONFLICT upserts.
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# CRUD Operations
|
|
6
6
|
|
|
7
|
-
BigAl repositories provide `create()`, `update()`, and `destroy()` methods. All three return affected
|
|
8
|
-
|
|
9
|
-
Results are always plain objects.
|
|
7
|
+
BigAl repositories provide `create()`, `update()`, and `destroy()` methods. All three return affected records
|
|
8
|
+
by default (using `RETURNING *`), and all support `returnRecords` and `returnSelect` options.
|
|
10
9
|
|
|
11
10
|
## Create
|
|
12
11
|
|
|
13
12
|
### Single record
|
|
14
13
|
|
|
15
14
|
```ts
|
|
16
|
-
const product = await
|
|
15
|
+
const product = await productRepository.create({
|
|
17
16
|
name: 'Widget',
|
|
18
17
|
priceCents: 999,
|
|
19
18
|
});
|
|
@@ -23,17 +22,31 @@ const product = await Product.create({
|
|
|
23
22
|
### Multiple records
|
|
24
23
|
|
|
25
24
|
```ts
|
|
26
|
-
const products = await
|
|
25
|
+
const products = await productRepository.create([
|
|
27
26
|
{ name: 'Widget', priceCents: 999 },
|
|
28
27
|
{ name: 'Gadget', priceCents: 1499 },
|
|
29
28
|
]);
|
|
30
29
|
// products = [{ id: 42, ... }, { id: 43, ... }]
|
|
31
30
|
```
|
|
32
31
|
|
|
32
|
+
Passing an array builds a single multi-row `INSERT` statement, one round trip for the whole batch. Prefer this over calling
|
|
33
|
+
`create()` in a loop, which issues a separate `INSERT` (and round trip) per record:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
// Correct — one INSERT statement for all rows
|
|
37
|
+
const products = await productRepository.create(items);
|
|
38
|
+
|
|
39
|
+
// Slower — a separate INSERT statement and round trip per item
|
|
40
|
+
const products = [];
|
|
41
|
+
for (const item of items) {
|
|
42
|
+
products.push(await productRepository.create(item));
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
33
46
|
### Skip returning records
|
|
34
47
|
|
|
35
48
|
```ts
|
|
36
|
-
await
|
|
49
|
+
await productRepository.create({ name: 'Widget', priceCents: 999 }, { returnRecords: false });
|
|
37
50
|
```
|
|
38
51
|
|
|
39
52
|
### Query projection (returnSelect)
|
|
@@ -41,14 +54,14 @@ await Product.create({ name: 'Widget', priceCents: 999 }, { returnRecords: false
|
|
|
41
54
|
Return only specific columns. The primary key is always included.
|
|
42
55
|
|
|
43
56
|
```ts
|
|
44
|
-
const product = await
|
|
57
|
+
const product = await productRepository.create({ name: 'Widget', priceCents: 999 }, { returnSelect: ['name'] });
|
|
45
58
|
// product = { id: 42, name: 'Widget' }
|
|
46
59
|
```
|
|
47
60
|
|
|
48
61
|
Pass an empty array to return only the primary key:
|
|
49
62
|
|
|
50
63
|
```ts
|
|
51
|
-
const product = await
|
|
64
|
+
const product = await productRepository.create({ name: 'Widget', priceCents: 999 }, { returnSelect: [] });
|
|
52
65
|
// product = { id: 42 }
|
|
53
66
|
```
|
|
54
67
|
|
|
@@ -59,7 +72,7 @@ Handle constraint violations with PostgreSQL's `ON CONFLICT` clause.
|
|
|
59
72
|
### Ignore (DO NOTHING)
|
|
60
73
|
|
|
61
74
|
```ts
|
|
62
|
-
const product = await
|
|
75
|
+
const product = await productRepository.create(
|
|
63
76
|
{ name: 'Widget', sku: 'WDG-001' },
|
|
64
77
|
{
|
|
65
78
|
onConflict: {
|
|
@@ -73,7 +86,7 @@ const product = await Product.create(
|
|
|
73
86
|
### Merge (DO UPDATE) - all columns
|
|
74
87
|
|
|
75
88
|
```ts
|
|
76
|
-
const product = await
|
|
89
|
+
const product = await productRepository.create(
|
|
77
90
|
{ name: 'Widget', sku: 'WDG-001', priceCents: 999 },
|
|
78
91
|
{
|
|
79
92
|
onConflict: {
|
|
@@ -87,7 +100,7 @@ const product = await Product.create(
|
|
|
87
100
|
### Merge - specific columns
|
|
88
101
|
|
|
89
102
|
```ts
|
|
90
|
-
const product = await
|
|
103
|
+
const product = await productRepository.create(
|
|
91
104
|
{ name: 'Widget', sku: 'WDG-001', priceCents: 999 },
|
|
92
105
|
{
|
|
93
106
|
onConflict: {
|
|
@@ -105,11 +118,11 @@ const product = await Product.create(
|
|
|
105
118
|
|
|
106
119
|
```ts
|
|
107
120
|
// Update a single record
|
|
108
|
-
const products = await
|
|
121
|
+
const products = await productRepository.update({ id: 42 }, { name: 'Super Widget' });
|
|
109
122
|
// products = [{ id: 42, name: 'Super Widget', ... }]
|
|
110
123
|
|
|
111
124
|
// Update multiple records
|
|
112
|
-
const products = await
|
|
125
|
+
const products = await productRepository.update({ id: [42, 43] }, { priceCents: 1299 });
|
|
113
126
|
// products = [{ id: 42, ... }, { id: 43, ... }]
|
|
114
127
|
```
|
|
115
128
|
|
|
@@ -118,74 +131,42 @@ const products = await Product.update({ id: [42, 43] }, { priceCents: 1299 });
|
|
|
118
131
|
Without returning records:
|
|
119
132
|
|
|
120
133
|
```ts
|
|
121
|
-
await
|
|
134
|
+
await productRepository.update({ id: 42 }, { name: 'Super Widget' }, { returnRecords: false });
|
|
122
135
|
```
|
|
123
136
|
|
|
124
137
|
With query projection:
|
|
125
138
|
|
|
126
139
|
```ts
|
|
127
|
-
const products = await
|
|
140
|
+
const products = await productRepository.update({ id: [42, 43] }, { priceCents: 1299 }, { returnSelect: ['id'] });
|
|
128
141
|
// products = [{ id: 42 }, { id: 43 }]
|
|
129
142
|
```
|
|
130
143
|
|
|
131
144
|
## Destroy
|
|
132
145
|
|
|
133
|
-
`destroy()` takes a where clause object. Returns
|
|
134
|
-
|
|
135
|
-
```ts
|
|
136
|
-
// Delete records (returns void)
|
|
137
|
-
await Product.destroy({ id: 42 });
|
|
138
|
-
await Product.destroy({ id: [42, 43] });
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
With returning records:
|
|
146
|
+
`destroy()` takes a where clause object. Returns an array of deleted records.
|
|
142
147
|
|
|
143
148
|
```ts
|
|
144
|
-
|
|
149
|
+
// Delete a single record
|
|
150
|
+
const products = await productRepository.destroy({ id: 42 });
|
|
145
151
|
// products = [{ id: 42, name: 'Super Widget', ... }]
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
With query projection:
|
|
149
152
|
|
|
150
|
-
|
|
151
|
-
const products = await
|
|
152
|
-
// products = [{ id: 42, name: 'Widget' }, { id: 43, name: 'Gadget' }]
|
|
153
|
+
// Delete multiple records
|
|
154
|
+
const products = await productRepository.destroy({ id: [42, 43] });
|
|
153
155
|
```
|
|
154
156
|
|
|
155
|
-
>
|
|
156
|
-
> primary key.
|
|
157
|
-
|
|
158
|
-
## toSQL() on mutations
|
|
157
|
+
> `destroy()` always returns an array, regardless of how many records were affected.
|
|
159
158
|
|
|
160
|
-
|
|
159
|
+
Without returning records:
|
|
161
160
|
|
|
162
161
|
```ts
|
|
163
|
-
|
|
164
|
-
const { sql, params } = Product.create({ name: 'Widget', priceCents: 999 }).toSQL();
|
|
165
|
-
|
|
166
|
-
// Update
|
|
167
|
-
const { sql, params } = Product.update({ id: 42 }, { name: 'Super Widget' }).toSQL();
|
|
168
|
-
|
|
169
|
-
// Destroy
|
|
170
|
-
const { sql, params } = Product.destroy({ id: 42 }).toSQL();
|
|
162
|
+
await productRepository.destroy({ id: 42 }, { returnRecords: false });
|
|
171
163
|
```
|
|
172
164
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
## Initialization example
|
|
165
|
+
With query projection:
|
|
176
166
|
|
|
177
167
|
```ts
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const Product = table('products', {
|
|
182
|
-
id: serial().primaryKey(),
|
|
183
|
-
name: text().notNull(),
|
|
184
|
-
priceCents: integer().notNull(),
|
|
185
|
-
createdAt: createdAt(),
|
|
186
|
-
updatedAt: updatedAt(),
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
const pool = new Pool('postgres://localhost/mydb');
|
|
190
|
-
const { Product } = initialize({ models: { Product }, pool });
|
|
168
|
+
const products = await productRepository.destroy({ id: [42, 43] }, { returnSelect: ['name'] });
|
|
169
|
+
// products = [{ id: 42, name: 'Widget' }, { id: 43, name: 'Gadget' }]
|
|
191
170
|
```
|
|
171
|
+
|
|
172
|
+
> The primary key is always included. Pass an empty array to return only the primary key.
|