@aurios/mizzle 1.1.1 → 1.1.2
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 +57 -0
- package/package.json +72 -39
- package/src/builders/base.ts +2 -2
- package/src/builders/batch-write.ts +1 -1
- package/src/builders/delete.ts +1 -1
- package/src/builders/insert.ts +7 -7
- package/src/builders/relational-builder.ts +4 -4
- package/src/builders/select.ts +15 -16
- package/src/builders/transaction.ts +20 -19
- package/src/builders/update.ts +12 -10
- package/src/core/parser.ts +3 -2
- package/src/core/relations.ts +16 -13
- package/src/core/strategies.ts +15 -11
- package/src/core/table.ts +1 -1
- package/src/db.ts +6 -5
- package/src/expressions/builder.ts +4 -4
- package/src/expressions/update-builder.ts +11 -9
- package/src/index.ts +1 -0
- package/tsconfig.json +1 -2
package/README.md
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# @aurios/mizzle
|
|
2
|
+
|
|
3
|
+
A Drizzle-like ORM for DynamoDB. Mizzle provides a type-safe, fluent API for interacting with DynamoDB, supporting relational queries, batch operations, and transactions.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @aurios/mizzle
|
|
9
|
+
# or
|
|
10
|
+
bun add @aurios/mizzle
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Initialization
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
19
|
+
import { mizzle } from "@aurios/mizzle";
|
|
20
|
+
|
|
21
|
+
const client = new DynamoDBClient({});
|
|
22
|
+
const db = mizzle(client);
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Key Features
|
|
26
|
+
|
|
27
|
+
- **Type-Safe Schema Definition**: Define your tables and entities with strict TypeScript types.
|
|
28
|
+
- **Fluent Query Builder**: precise API for `insert`, `select`, `update`, and `delete` operations.
|
|
29
|
+
- **Relational Queries**: Query related entities with `db.query`.
|
|
30
|
+
- **Batch Operations**: `batchGet` and `batchWrite` support.
|
|
31
|
+
- **Transactions**: Atomic operations using `db.transaction`.
|
|
32
|
+
- **Automatic Type Inference**: `InferSelectModel` and `InferInsertModel` utilities.
|
|
33
|
+
|
|
34
|
+
### Example
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
// Define your schema (simplified)
|
|
38
|
+
import { dynamoTable, dynamoEntity, string } from "@aurios/mizzle";
|
|
39
|
+
|
|
40
|
+
const myTable = dynamoTable("my-app-table", {
|
|
41
|
+
pk: string("pk"),
|
|
42
|
+
sk: string("sk"),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const users = dynamoEntity(myTable, "users", {
|
|
46
|
+
id: string("id"),
|
|
47
|
+
name: string("name"),
|
|
48
|
+
email: string("email"),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Query
|
|
52
|
+
const result = await db.select().from(users).where(eq(users.id, "123")).execute();
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## License
|
|
56
|
+
|
|
57
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,41 +1,74 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
2
|
+
"name": "@aurios/mizzle",
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"description": "a drizzle-like orm for dynamoDB",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"homepage": "https://mizzle-docs.vercel.app",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"development": "./src/index.ts"
|
|
15
|
+
},
|
|
16
|
+
"./columns": {
|
|
17
|
+
"types": "./dist/columns.d.ts",
|
|
18
|
+
"import": "./dist/columns.js",
|
|
19
|
+
"development": "./src/columns/index.ts"
|
|
20
|
+
},
|
|
21
|
+
"./table": {
|
|
22
|
+
"types": "./dist/table.d.ts",
|
|
23
|
+
"import": "./dist/table.js",
|
|
24
|
+
"development": "./src/core/table.ts"
|
|
25
|
+
},
|
|
26
|
+
"./snapshot": {
|
|
27
|
+
"types": "./dist/snapshot.d.ts",
|
|
28
|
+
"import": "./dist/snapshot.js",
|
|
29
|
+
"development": "./src/core/snapshot.ts"
|
|
30
|
+
},
|
|
31
|
+
"./diff": {
|
|
32
|
+
"types": "./dist/diff.d.ts",
|
|
33
|
+
"import": "./dist/diff.js",
|
|
34
|
+
"development": "./src/core/diff.ts"
|
|
35
|
+
},
|
|
36
|
+
"./introspection": {
|
|
37
|
+
"types": "./dist/introspection.d.ts",
|
|
38
|
+
"import": "./dist/introspection.js",
|
|
39
|
+
"development": "./src/core/introspection.ts"
|
|
40
|
+
},
|
|
41
|
+
"./db": {
|
|
42
|
+
"types": "./dist/db.d.ts",
|
|
43
|
+
"import": "./dist/db.js",
|
|
44
|
+
"development": "./src/db.ts"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"author": {
|
|
48
|
+
"name": "Lucas",
|
|
49
|
+
"url": "https://github.com/realfakenerd"
|
|
50
|
+
},
|
|
51
|
+
"repository": {
|
|
52
|
+
"url": "git+https://github.com/realfakenerd/mizzle",
|
|
53
|
+
"type": "git",
|
|
54
|
+
"directory": "packages/mizzle"
|
|
55
|
+
},
|
|
56
|
+
"bugs": {
|
|
57
|
+
"url": "https://github.com/realfakenerd/mizzle/issues"
|
|
58
|
+
},
|
|
59
|
+
"scripts": {
|
|
60
|
+
"check": "tsc --noEmit",
|
|
61
|
+
"build": "tsup",
|
|
62
|
+
"lint": "bunx oxlint --type-aware src",
|
|
63
|
+
"prepublishOnly": "bun run build"
|
|
64
|
+
},
|
|
65
|
+
"dependencies": {
|
|
66
|
+
"@aws-sdk/client-dynamodb": "3.962.0",
|
|
67
|
+
"@aws-sdk/lib-dynamodb": "3.962.0"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@mizzle/shared": "workspace:*",
|
|
71
|
+
"@mizzle/tsconfig": "workspace:*",
|
|
72
|
+
"tsup": "^8.5.1"
|
|
73
|
+
}
|
|
41
74
|
}
|
package/src/builders/base.ts
CHANGED
|
@@ -18,7 +18,7 @@ export abstract class BaseBuilder<
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
public get tableName(): string {
|
|
21
|
-
return resolveTableName(this.entity as
|
|
21
|
+
return resolveTableName(this.entity as any);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
protected get physicalTable() {
|
|
@@ -66,6 +66,6 @@ export abstract class BaseBuilder<
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
protected mapToLogical(item: Record<string, unknown>): Record<string, unknown> {
|
|
69
|
-
return mapToLogical(this.entity, item);
|
|
69
|
+
return mapToLogical(this.entity as any, item);
|
|
70
70
|
}
|
|
71
71
|
}
|
package/src/builders/delete.ts
CHANGED
package/src/builders/insert.ts
CHANGED
|
@@ -14,7 +14,7 @@ export class InsertBuilder<TEntity extends Entity> {
|
|
|
14
14
|
constructor(
|
|
15
15
|
private entity: TEntity,
|
|
16
16
|
private client: IMizzleClient,
|
|
17
|
-
) {}
|
|
17
|
+
) { }
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Sets the values to be inserted into the database.
|
|
@@ -71,7 +71,7 @@ export class InsertBase<
|
|
|
71
71
|
buildItem(): Record<string, unknown> {
|
|
72
72
|
const itemToSave = this.processValues(this.valuesData);
|
|
73
73
|
const resolution = this.resolveKeys(undefined, itemToSave);
|
|
74
|
-
|
|
74
|
+
|
|
75
75
|
const finalItem: Record<string, unknown> = { ...itemToSave, ...resolution.keys };
|
|
76
76
|
|
|
77
77
|
// Also resolve GSI keys if they are defined in strategies but not in resolution.keys
|
|
@@ -164,11 +164,11 @@ export class InsertBase<
|
|
|
164
164
|
}
|
|
165
165
|
|
|
166
166
|
const finalValue = item[key];
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
167
|
+
|
|
168
|
+
// Check if column has mapToDynamoValue method (it's on the Column class)
|
|
169
|
+
if (col instanceof Column) {
|
|
170
|
+
item[key] = col.mapToDynamoValue(finalValue);
|
|
171
|
+
}
|
|
172
172
|
|
|
173
173
|
if (["SS", "NS", "BS"].includes(col.columnType)) {
|
|
174
174
|
if (Array.isArray(finalValue)) {
|
|
@@ -79,7 +79,7 @@ export class RelationnalQueryBuilder<T extends Entity> {
|
|
|
79
79
|
if (options.where) {
|
|
80
80
|
const columns = (this.table._?.columns || (this.table as unknown as Record<string, Column>)) as Record<string, Column>;
|
|
81
81
|
if (typeof options.where === 'function') {
|
|
82
|
-
condition = (options.where as WhereCallback<T>)(columns as
|
|
82
|
+
condition = (options.where as WhereCallback<T>)(columns as unknown as Record<string, Column>, operators);
|
|
83
83
|
} else {
|
|
84
84
|
condition = options.where as Condition;
|
|
85
85
|
}
|
|
@@ -106,10 +106,10 @@ export class RelationnalQueryBuilder<T extends Entity> {
|
|
|
106
106
|
|
|
107
107
|
// Map physical attributes back to logical names for the parser
|
|
108
108
|
// We need a helper since we are not inheriting from BaseBuilder here
|
|
109
|
-
const logicalItems = rawItems.map(item => mapToLogical(this.table, item));
|
|
109
|
+
const logicalItems = rawItems.map(item => mapToLogical(this.table as any, item));
|
|
110
110
|
|
|
111
111
|
const parser = new ItemCollectionParser(this.schema);
|
|
112
|
-
results = parser.parse(logicalItems as
|
|
112
|
+
results = parser.parse(logicalItems as Record<string, unknown>[], this.entityName, (options.with || options.include) as Record<string, boolean | object>);
|
|
113
113
|
|
|
114
114
|
if (options.limit) {
|
|
115
115
|
results = results.slice(0, options.limit);
|
|
@@ -147,7 +147,7 @@ export class RelationnalQueryBuilder<T extends Entity> {
|
|
|
147
147
|
const targetEntityName = Object.entries(this.schema!.entities).find(([_, m]) => m.entity === targetEntity)?.[0];
|
|
148
148
|
|
|
149
149
|
// Map result to logical names for target strategy resolution
|
|
150
|
-
const logicalValues = mapToLogical(this.table, result);
|
|
150
|
+
const logicalValues = mapToLogical(this.table as any, result);
|
|
151
151
|
|
|
152
152
|
let finalLogicalValues = logicalValues;
|
|
153
153
|
if (relation.config.fields && relation.config.references) {
|
package/src/builders/select.ts
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
QueryCommand,
|
|
4
4
|
ScanCommand,
|
|
5
5
|
} from "@aws-sdk/lib-dynamodb";
|
|
6
|
-
import { ENTITY_SYMBOLS
|
|
6
|
+
import { ENTITY_SYMBOLS } from "@mizzle/shared";
|
|
7
7
|
import { Column } from "../core/column";
|
|
8
8
|
import type { SelectedFields as SelectedFieldsBase } from "../core/operations";
|
|
9
9
|
import {
|
|
@@ -159,28 +159,27 @@ export class SelectBase<
|
|
|
159
159
|
* @returns An AsyncIterableIterator for the query results.
|
|
160
160
|
*/
|
|
161
161
|
iterator(): AsyncIterableIterator<TResult> {
|
|
162
|
-
|
|
163
|
-
|
|
162
|
+
return (async function* (this: SelectBase<TEntity, TSelection, TResult>) {
|
|
163
|
+
let lastEvaluatedKey: Record<string, unknown> | undefined;
|
|
164
164
|
let count = 0;
|
|
165
|
-
let lastEvaluatedKey: Record<string, any> | undefined = undefined;
|
|
166
165
|
|
|
167
166
|
do {
|
|
168
|
-
const result = await
|
|
167
|
+
const result = await this.fetchPage(lastEvaluatedKey);
|
|
169
168
|
|
|
170
169
|
for (const item of result.items) {
|
|
171
170
|
yield item;
|
|
172
171
|
count++;
|
|
173
|
-
if (
|
|
172
|
+
if (this._limitVal !== undefined && count >= this._limitVal) {
|
|
174
173
|
return;
|
|
175
174
|
}
|
|
176
175
|
}
|
|
177
176
|
|
|
178
177
|
lastEvaluatedKey = result.lastEvaluatedKey;
|
|
179
178
|
} while (lastEvaluatedKey);
|
|
180
|
-
})();
|
|
179
|
+
}).bind(this)();
|
|
181
180
|
}
|
|
182
181
|
|
|
183
|
-
private async fetchPage(exclusiveStartKey?: Record<string,
|
|
182
|
+
private async fetchPage(exclusiveStartKey?: Record<string, unknown>): Promise<{ items: TResult[], lastEvaluatedKey?: Record<string, unknown> }> {
|
|
184
183
|
const resolution = this.resolveKeys(this._whereClause, undefined, this._forcedIndexName);
|
|
185
184
|
|
|
186
185
|
if (resolution.hasPartitionKey && resolution.hasSortKey && !resolution.indexName && !exclusiveStartKey) {
|
|
@@ -211,14 +210,14 @@ export class SelectBase<
|
|
|
211
210
|
ConsistentRead: this._consistentReadVal,
|
|
212
211
|
});
|
|
213
212
|
|
|
214
|
-
const result = await this.client.send(command);
|
|
213
|
+
const result = await this.client.send(command) as any;
|
|
215
214
|
return result.Item ? ([this.mapToLogical(result.Item)] as TResult[]) : [];
|
|
216
215
|
}
|
|
217
216
|
|
|
218
217
|
private async executeQuery(
|
|
219
218
|
resolution: StrategyResolution,
|
|
220
|
-
exclusiveStartKey?: Record<string,
|
|
221
|
-
): Promise<{ items: TResult[], lastEvaluatedKey?: Record<string,
|
|
219
|
+
exclusiveStartKey?: Record<string, unknown>,
|
|
220
|
+
): Promise<{ items: TResult[], lastEvaluatedKey?: Record<string, unknown> }> {
|
|
222
221
|
const { expressionAttributeNames, expressionAttributeValues, addName, addValue } = this.createExpressionContext();
|
|
223
222
|
|
|
224
223
|
const keyParts: string[] = [];
|
|
@@ -247,14 +246,14 @@ export class SelectBase<
|
|
|
247
246
|
ExclusiveStartKey: exclusiveStartKey,
|
|
248
247
|
});
|
|
249
248
|
|
|
250
|
-
const response = await this.client.send(command);
|
|
249
|
+
const response = await this.client.send(command) as any;
|
|
251
250
|
return {
|
|
252
|
-
items: (response.Items || []).map((item:
|
|
251
|
+
items: (response.Items || []).map((item: Record<string, unknown>) => this.mapToLogical(item)) as TResult[],
|
|
253
252
|
lastEvaluatedKey: response.LastEvaluatedKey,
|
|
254
253
|
};
|
|
255
254
|
}
|
|
256
255
|
|
|
257
|
-
private async executeScan(exclusiveStartKey?: Record<string,
|
|
256
|
+
private async executeScan(exclusiveStartKey?: Record<string, unknown>): Promise<{ items: TResult[], lastEvaluatedKey?: Record<string, unknown> }> {
|
|
258
257
|
const { expressionAttributeNames, expressionAttributeValues, addName, addValue } = this.createExpressionContext();
|
|
259
258
|
|
|
260
259
|
const filterExpression = this._whereClause
|
|
@@ -271,9 +270,9 @@ export class SelectBase<
|
|
|
271
270
|
ExclusiveStartKey: exclusiveStartKey,
|
|
272
271
|
});
|
|
273
272
|
|
|
274
|
-
const response = await this.client.send(command);
|
|
273
|
+
const response = await this.client.send(command) as any;
|
|
275
274
|
return {
|
|
276
|
-
items: (response.Items || []).map((item:
|
|
275
|
+
items: (response.Items || []).map((item: Record<string, unknown>) => this.mapToLogical(item)) as TResult[],
|
|
277
276
|
lastEvaluatedKey: response.LastEvaluatedKey,
|
|
278
277
|
};
|
|
279
278
|
}
|
|
@@ -6,7 +6,7 @@ import { DeleteBuilder } from "./delete";
|
|
|
6
6
|
import { Expression } from "../expressions/operators";
|
|
7
7
|
import { BaseBuilder } from "./base";
|
|
8
8
|
import type { IMizzleClient } from "../core/client";
|
|
9
|
-
import { ENTITY_SYMBOLS
|
|
9
|
+
import { ENTITY_SYMBOLS } from "@mizzle/shared";
|
|
10
10
|
import { buildExpression } from "../expressions/builder";
|
|
11
11
|
import { buildUpdateExpressionString } from "../expressions/update-builder";
|
|
12
12
|
import { TransactionFailedError } from "../core/errors";
|
|
@@ -71,7 +71,7 @@ export class TransactionProxy {
|
|
|
71
71
|
export class TransactionExecutor {
|
|
72
72
|
constructor(private client: IMizzleClient) {}
|
|
73
73
|
|
|
74
|
-
async execute(token: string, operations:
|
|
74
|
+
async execute(token: string, operations: BaseBuilder<Entity, unknown>[]): Promise<void> {
|
|
75
75
|
const transactItems = operations.map(op => this.mapToTransactItem(op));
|
|
76
76
|
|
|
77
77
|
const command = new TransactWriteCommand({
|
|
@@ -81,14 +81,15 @@ export class TransactionExecutor {
|
|
|
81
81
|
|
|
82
82
|
try {
|
|
83
83
|
await this.client.send(command);
|
|
84
|
-
} catch (error:
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
} catch (error: unknown) {
|
|
85
|
+
const err = error as Error & { __type?: string; CancellationReasons?: Record<string, unknown>[] };
|
|
86
|
+
if (err.name === "TransactionCanceledException" || err.__type?.includes("TransactionCanceledException")) {
|
|
87
|
+
const reasons = (err.CancellationReasons || []).map((reason: Record<string, unknown>, index: number) => ({
|
|
87
88
|
index,
|
|
88
|
-
code: reason.Code,
|
|
89
|
-
message: reason.Message,
|
|
90
|
-
item: reason.Item
|
|
91
|
-
})).filter((reason
|
|
89
|
+
code: reason.Code as string,
|
|
90
|
+
message: reason.Message as string,
|
|
91
|
+
item: reason.Item as Record<string, unknown> | undefined
|
|
92
|
+
})).filter((reason) => reason.code !== "None");
|
|
92
93
|
|
|
93
94
|
throw new TransactionFailedError("Transaction canceled by server.", reasons);
|
|
94
95
|
}
|
|
@@ -96,24 +97,24 @@ export class TransactionExecutor {
|
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
private mapToTransactItem(builder:
|
|
100
|
-
const kind = builder.constructor[ENTITY_SYMBOLS.ENTITY_KIND];
|
|
100
|
+
private mapToTransactItem(builder: BaseBuilder<Entity, unknown>): Record<string, unknown> {
|
|
101
|
+
const kind = (builder.constructor as unknown as { [ENTITY_SYMBOLS.ENTITY_KIND]: string })[ENTITY_SYMBOLS.ENTITY_KIND];
|
|
101
102
|
|
|
102
103
|
switch (kind) {
|
|
103
104
|
case "InsertBase":
|
|
104
|
-
return { Put: this.mapPut(builder) };
|
|
105
|
+
return { Put: this.mapPut(builder as InsertBase<Entity, unknown>) };
|
|
105
106
|
case "UpdateBuilder":
|
|
106
|
-
return { Update: this.mapUpdate(builder) };
|
|
107
|
+
return { Update: this.mapUpdate(builder as UpdateBuilder<Entity, unknown>) };
|
|
107
108
|
case "DeleteBuilder":
|
|
108
|
-
return { Delete: this.mapDelete(builder) };
|
|
109
|
+
return { Delete: this.mapDelete(builder as DeleteBuilder<Entity, unknown>) };
|
|
109
110
|
case "ConditionCheckBuilder":
|
|
110
|
-
return { ConditionCheck: this.mapConditionCheck(builder) };
|
|
111
|
+
return { ConditionCheck: this.mapConditionCheck(builder as ConditionCheckBuilder<Entity>) };
|
|
111
112
|
default:
|
|
112
113
|
throw new Error(`Unsupported transaction operation: ${kind}`);
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
private mapPut(builder: InsertBase<
|
|
117
|
+
private mapPut(builder: InsertBase<Entity, unknown>): Record<string, unknown> {
|
|
117
118
|
const finalItem = builder.buildItem();
|
|
118
119
|
|
|
119
120
|
return {
|
|
@@ -122,7 +123,7 @@ export class TransactionExecutor {
|
|
|
122
123
|
};
|
|
123
124
|
}
|
|
124
125
|
|
|
125
|
-
private mapUpdate(builder: UpdateBuilder<
|
|
126
|
+
private mapUpdate(builder: UpdateBuilder<Entity, unknown>): Record<string, unknown> {
|
|
126
127
|
const { expressionAttributeNames, expressionAttributeValues, addName, addValue } = builder.createExpressionContext("up_");
|
|
127
128
|
const updateExpression = buildUpdateExpressionString(builder.state, addName, addValue);
|
|
128
129
|
|
|
@@ -141,7 +142,7 @@ export class TransactionExecutor {
|
|
|
141
142
|
};
|
|
142
143
|
}
|
|
143
144
|
|
|
144
|
-
private mapDelete(builder: DeleteBuilder<
|
|
145
|
+
private mapDelete(builder: DeleteBuilder<Entity, unknown>): Record<string, unknown> {
|
|
145
146
|
const resolution = builder.resolveKeys(undefined, builder.keys);
|
|
146
147
|
return {
|
|
147
148
|
TableName: builder.tableName,
|
|
@@ -149,7 +150,7 @@ export class TransactionExecutor {
|
|
|
149
150
|
};
|
|
150
151
|
}
|
|
151
152
|
|
|
152
|
-
private mapConditionCheck(builder: ConditionCheckBuilder<
|
|
153
|
+
private mapConditionCheck(builder: ConditionCheckBuilder<Entity>): Record<string, unknown> {
|
|
153
154
|
const { expressionAttributeNames, expressionAttributeValues, addName, addValue } = builder.createExpressionContext("cc_");
|
|
154
155
|
|
|
155
156
|
const resolution = builder.resolveKeys(builder.whereClause);
|
package/src/builders/update.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { UpdateCommand } from "@aws-sdk/lib-dynamodb";
|
|
2
2
|
import { ENTITY_SYMBOLS } from "@mizzle/shared";
|
|
3
3
|
import { Entity, type InferInsertModel } from "../core/table";
|
|
4
|
+
import { Column } from "../core/column";
|
|
4
5
|
import { type Expression } from "../expressions/operators";
|
|
5
6
|
import { BaseBuilder } from "./base";
|
|
6
7
|
import { type IMizzleClient } from "../core/client";
|
|
@@ -59,7 +60,7 @@ export class UpdateBuilder<
|
|
|
59
60
|
* @returns The current builder instance for chaining.
|
|
60
61
|
*/
|
|
61
62
|
set(values: Partial<{ [K in keyof InferInsertModel<TEntity>]: InferInsertModel<TEntity>[K] | UpdateAction }>): this {
|
|
62
|
-
partitionUpdateValues(values as Record<string,
|
|
63
|
+
partitionUpdateValues(values as Record<string, unknown | UpdateAction>, this._state, this.entity[ENTITY_SYMBOLS.COLUMNS] as unknown as Record<string, Column>);
|
|
63
64
|
return this;
|
|
64
65
|
}
|
|
65
66
|
|
|
@@ -71,9 +72,9 @@ export class UpdateBuilder<
|
|
|
71
72
|
* @returns The current builder instance for chaining.
|
|
72
73
|
*/
|
|
73
74
|
add(values: Partial<InferInsertModel<TEntity>>): this {
|
|
74
|
-
const columns = this.entity[ENTITY_SYMBOLS.COLUMNS] as Record<string,
|
|
75
|
+
const columns = this.entity[ENTITY_SYMBOLS.COLUMNS] as unknown as Record<string, Column>;
|
|
75
76
|
for (const [key, val] of Object.entries(values)) {
|
|
76
|
-
const col = columns[key];
|
|
77
|
+
const col = columns[key] as unknown as { mapToDynamoValue?: (v: unknown) => unknown };
|
|
77
78
|
this._state.add[key] = (col && typeof col.mapToDynamoValue === "function")
|
|
78
79
|
? col.mapToDynamoValue(val)
|
|
79
80
|
: val;
|
|
@@ -101,9 +102,9 @@ export class UpdateBuilder<
|
|
|
101
102
|
* @returns The current builder instance for chaining.
|
|
102
103
|
*/
|
|
103
104
|
delete(values: Partial<InferInsertModel<TEntity>>): this {
|
|
104
|
-
const columns = this.entity[ENTITY_SYMBOLS.COLUMNS] as Record<string,
|
|
105
|
+
const columns = this.entity[ENTITY_SYMBOLS.COLUMNS] as unknown as Record<string, Column>;
|
|
105
106
|
for (const [key, val] of Object.entries(values)) {
|
|
106
|
-
const col = columns[key];
|
|
107
|
+
const col = columns[key] as unknown as { mapToDynamoValue?: (v: unknown) => unknown };
|
|
107
108
|
this._state.delete[key] = (col && typeof col.mapToDynamoValue === "function")
|
|
108
109
|
? col.mapToDynamoValue(val)
|
|
109
110
|
: val;
|
|
@@ -155,12 +156,13 @@ export class UpdateBuilder<
|
|
|
155
156
|
* @throws {ItemSizeExceededError} if the update exceeds 400KB.
|
|
156
157
|
*/
|
|
157
158
|
public override async execute(): Promise<TResult> {
|
|
158
|
-
const columns = this.entity[ENTITY_SYMBOLS.COLUMNS] as Record<string,
|
|
159
|
+
const columns = this.entity[ENTITY_SYMBOLS.COLUMNS] as unknown as Record<string, Column>;
|
|
159
160
|
for (const [key, col] of Object.entries(columns)) {
|
|
160
|
-
|
|
161
|
-
|
|
161
|
+
const column = col as unknown as { onUpdateFn?: () => unknown, mapToDynamoValue?: (v: unknown) => unknown };
|
|
162
|
+
if (column.onUpdateFn && !this._state.set[key] && !this._state.remove.includes(key)) {
|
|
163
|
+
const val = column.onUpdateFn();
|
|
162
164
|
this._state.set[key] = {
|
|
163
|
-
value: typeof
|
|
165
|
+
value: typeof column.mapToDynamoValue === "function" ? column.mapToDynamoValue(val) : val
|
|
164
166
|
};
|
|
165
167
|
}
|
|
166
168
|
}
|
|
@@ -199,7 +201,7 @@ export class UpdateBuilder<
|
|
|
199
201
|
ReturnValues: this._returnValues,
|
|
200
202
|
});
|
|
201
203
|
|
|
202
|
-
const response = await this.client.send(command);
|
|
204
|
+
const response = await this.client.send(command) as any;
|
|
203
205
|
return response.Attributes as TResult;
|
|
204
206
|
}
|
|
205
207
|
|
package/src/core/parser.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Entity } from "./table";
|
|
|
5
5
|
import { Column } from "./column";
|
|
6
6
|
|
|
7
7
|
interface MinimalPhysicalTable {
|
|
8
|
-
[TABLE_SYMBOLS.PARTITION_KEY]: Column;
|
|
8
|
+
[TABLE_SYMBOLS.PARTITION_KEY]: Column | undefined;
|
|
9
9
|
[TABLE_SYMBOLS.SORT_KEY]?: Column;
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -78,8 +78,9 @@ export class ItemCollectionParser {
|
|
|
78
78
|
KeyStrategy
|
|
79
79
|
>;
|
|
80
80
|
const physicalTable = entity[ENTITY_SYMBOLS.PHYSICAL_TABLE] as unknown as MinimalPhysicalTable;
|
|
81
|
+
if (!physicalTable || !physicalTable[TABLE_SYMBOLS.PARTITION_KEY]) return false;
|
|
81
82
|
|
|
82
|
-
const pkName = physicalTable[TABLE_SYMBOLS.PARTITION_KEY]
|
|
83
|
+
const pkName = physicalTable[TABLE_SYMBOLS.PARTITION_KEY]!.name;
|
|
83
84
|
const skName = physicalTable[TABLE_SYMBOLS.SORT_KEY]?.name;
|
|
84
85
|
|
|
85
86
|
const pkMatch = this.matchStrategy(item[pkName], strategies.pk);
|
package/src/core/relations.ts
CHANGED
|
@@ -167,13 +167,14 @@ export function defineRelations<TSchema extends Record<string, Entity>>(
|
|
|
167
167
|
*/
|
|
168
168
|
export function defineRelations(
|
|
169
169
|
first: Entity | Record<string, Entity>,
|
|
170
|
-
callback:
|
|
171
|
-
):
|
|
170
|
+
callback: RelationsCallback | MultiRelationsCallback<any>
|
|
171
|
+
): RelationsDefinition | MultiRelationsDefinition {
|
|
172
172
|
if (first instanceof Entity) {
|
|
173
173
|
// Single entity mode
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
174
|
+
const cb = callback as RelationsCallback;
|
|
175
|
+
const config = cb({
|
|
176
|
+
one: (to: Entity, config?: Omit<RelationConfig, "to">) => new Relation("one", { to, ...config }),
|
|
177
|
+
many: (to: Entity, config?: Omit<RelationConfig, "to">) => new Relation("many", { to, ...config }),
|
|
177
178
|
});
|
|
178
179
|
|
|
179
180
|
return {
|
|
@@ -184,24 +185,25 @@ export function defineRelations(
|
|
|
184
185
|
} else {
|
|
185
186
|
// Multi-entity mode
|
|
186
187
|
const schema = first as Record<string, Entity>;
|
|
188
|
+
const cb = callback as MultiRelationsCallback<typeof schema>;
|
|
187
189
|
|
|
188
190
|
// Build helpers
|
|
189
|
-
const helpers:
|
|
191
|
+
const helpers: Record<string, unknown> = {
|
|
190
192
|
one: {},
|
|
191
193
|
many: {},
|
|
192
194
|
};
|
|
193
195
|
|
|
194
196
|
for (const [key, entity] of Object.entries(schema)) {
|
|
195
|
-
helpers.one[key] = (config
|
|
196
|
-
helpers.many[key] = (config
|
|
197
|
+
(helpers.one as Record<string, unknown>)[key] = (config?: Omit<RelationConfig, "to">) => new Relation("one", { to: entity, ...config });
|
|
198
|
+
(helpers.many as Record<string, unknown>)[key] = (config?: Omit<RelationConfig, "to">) => new Relation("many", { to: entity, ...config });
|
|
197
199
|
helpers[key] = entity;
|
|
198
200
|
}
|
|
199
201
|
|
|
200
|
-
const definitions =
|
|
202
|
+
const definitions = cb(helpers as unknown as RelationsHelpers<typeof schema>);
|
|
201
203
|
|
|
202
204
|
return {
|
|
203
205
|
schema,
|
|
204
|
-
definitions,
|
|
206
|
+
definitions: definitions as Record<string, Record<string, Relation>>,
|
|
205
207
|
[RELATION_SYMBOLS.RELATION_CONFIG]: true
|
|
206
208
|
};
|
|
207
209
|
}
|
|
@@ -242,8 +244,9 @@ export function extractMetadata(schema: Record<string, unknown>): InternalRelati
|
|
|
242
244
|
|
|
243
245
|
// Second pass: identify relations
|
|
244
246
|
for (const [, value] of Object.entries(schema)) {
|
|
245
|
-
if (value && (value as
|
|
246
|
-
|
|
247
|
+
if (value && typeof value === 'object' && (value as Record<string | symbol, unknown>)[RELATION_SYMBOLS.RELATION_CONFIG]) {
|
|
248
|
+
const relationConfig = value as Record<string | symbol, unknown>;
|
|
249
|
+
if (relationConfig.entity) {
|
|
247
250
|
// Single entity definition
|
|
248
251
|
const definition = value as RelationsDefinition;
|
|
249
252
|
const entityEntry = Object.entries(metadata.entities).find(
|
|
@@ -254,7 +257,7 @@ export function extractMetadata(schema: Record<string, unknown>): InternalRelati
|
|
|
254
257
|
const [, meta] = entityEntry;
|
|
255
258
|
meta.relations = { ...meta.relations, ...definition.config };
|
|
256
259
|
}
|
|
257
|
-
} else if (
|
|
260
|
+
} else if (relationConfig.definitions) {
|
|
258
261
|
// Multi-entity definition
|
|
259
262
|
const multiDef = value as MultiRelationsDefinition;
|
|
260
263
|
for (const [entityName, relations] of Object.entries(multiDef.definitions)) {
|
package/src/core/strategies.ts
CHANGED
|
@@ -115,8 +115,8 @@ export function resolveStrategies(
|
|
|
115
115
|
providedValues?: Record<string, unknown>,
|
|
116
116
|
forcedIndexName?: string
|
|
117
117
|
): StrategyResolution {
|
|
118
|
-
const strategies = entity[ENTITY_SYMBOLS.ENTITY_STRATEGY] as unknown as Record<string,
|
|
119
|
-
const physicalTable = entity[ENTITY_SYMBOLS.PHYSICAL_TABLE] as
|
|
118
|
+
const strategies = entity[ENTITY_SYMBOLS.ENTITY_STRATEGY] as unknown as Record<string, KeyStrategy | { pk: KeyStrategy; sk?: KeyStrategy }>;
|
|
119
|
+
const physicalTable = entity[ENTITY_SYMBOLS.PHYSICAL_TABLE] as unknown as Record<string | symbol, unknown>;
|
|
120
120
|
|
|
121
121
|
const pkCol = physicalTable[TABLE_SYMBOLS.PARTITION_KEY] as Column;
|
|
122
122
|
const skCol = physicalTable[TABLE_SYMBOLS.SORT_KEY] as Column | undefined;
|
|
@@ -150,9 +150,10 @@ export function resolveStrategies(
|
|
|
150
150
|
};
|
|
151
151
|
|
|
152
152
|
if (forcedIndexName) {
|
|
153
|
-
const indexes = physicalTable[TABLE_SYMBOLS.INDEXES];
|
|
153
|
+
const indexes = physicalTable[TABLE_SYMBOLS.INDEXES] as Record<string, unknown> | undefined;
|
|
154
154
|
const indexBuilder = indexes?.[forcedIndexName] as { config: { pk: string; sk?: string } } | undefined;
|
|
155
|
-
const
|
|
155
|
+
const strategy = strategies[forcedIndexName];
|
|
156
|
+
const indexStrategy = (strategy && 'pk' in strategy) ? strategy as { pk: KeyStrategy; sk?: KeyStrategy } : undefined;
|
|
156
157
|
|
|
157
158
|
if (indexBuilder && indexStrategy) {
|
|
158
159
|
// Check if availableValues already contains the PHYSICAL key
|
|
@@ -196,16 +197,18 @@ export function resolveStrategies(
|
|
|
196
197
|
if (result.hasPartitionKey) return result;
|
|
197
198
|
}
|
|
198
199
|
|
|
199
|
-
if (strategies.pk) {
|
|
200
|
-
const
|
|
200
|
+
if ('pk' in strategies && strategies.pk) {
|
|
201
|
+
const pkStrategy = strategies.pk as KeyStrategy;
|
|
202
|
+
const pkValue = resolveKeyStrategy(pkStrategy, availableValues);
|
|
201
203
|
if (pkValue) {
|
|
202
204
|
result.keys[pkCol.name] = pkValue;
|
|
203
205
|
result.hasPartitionKey = true;
|
|
204
206
|
}
|
|
205
207
|
}
|
|
206
208
|
|
|
207
|
-
if (strategies.sk) {
|
|
208
|
-
const
|
|
209
|
+
if ('sk' in strategies && strategies.sk) {
|
|
210
|
+
const skStrategy = strategies.sk as KeyStrategy;
|
|
211
|
+
const skValue = resolveKeyStrategy(skStrategy, availableValues);
|
|
209
212
|
if (skValue) {
|
|
210
213
|
if (skCol) {
|
|
211
214
|
result.keys[skCol.name] = skValue;
|
|
@@ -217,13 +220,14 @@ export function resolveStrategies(
|
|
|
217
220
|
}
|
|
218
221
|
|
|
219
222
|
if (!result.hasPartitionKey) {
|
|
220
|
-
const indexes = physicalTable[TABLE_SYMBOLS.INDEXES];
|
|
223
|
+
const indexes = physicalTable[TABLE_SYMBOLS.INDEXES] as Record<string, unknown> | undefined;
|
|
221
224
|
if (indexes) {
|
|
222
225
|
for (const [indexName, indexBuilderBase] of Object.entries(indexes)) {
|
|
223
226
|
const indexBuilder = indexBuilderBase as { config: { pk: string; sk?: string } };
|
|
224
|
-
const
|
|
225
|
-
|
|
227
|
+
const strategy = strategies[indexName];
|
|
228
|
+
const indexStrategy = (strategy && 'pk' in strategy) ? strategy as { pk: KeyStrategy; sk?: KeyStrategy } : undefined;
|
|
226
229
|
|
|
230
|
+
if (!indexStrategy) continue;
|
|
227
231
|
if (availableValues[indexBuilder.config.pk] !== undefined) {
|
|
228
232
|
result.indexName = indexName;
|
|
229
233
|
result.keys = {};
|
package/src/core/table.ts
CHANGED
|
@@ -244,7 +244,7 @@ export function dynamoEntity<
|
|
|
244
244
|
normalizedStrategies[key] = { type: "prefix", segments: ["", val] };
|
|
245
245
|
} else if (val && typeof val === "object" && !("type" in val && "segments" in val)) {
|
|
246
246
|
// It's an index strategy object { pk, sk }
|
|
247
|
-
const indexStrategy:
|
|
247
|
+
const indexStrategy: Record<string, unknown> = { ...val as object };
|
|
248
248
|
if (indexStrategy.pk instanceof Column) {
|
|
249
249
|
indexStrategy.pk = { type: "prefix", segments: ["", indexStrategy.pk] };
|
|
250
250
|
}
|
package/src/db.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
|
|
|
3
3
|
import { InsertBuilder } from "./builders/insert";
|
|
4
4
|
import { RelationnalQueryBuilder } from "./builders/relational-builder";
|
|
5
5
|
import { SelectBuilder, type SelectedFields } from "./builders/select";
|
|
6
|
+
import type { BaseBuilder } from "./builders/base";
|
|
6
7
|
import type { Entity, InferInsertModel, InferSelectModel } from "./core/table";
|
|
7
8
|
import { UpdateBuilder } from "./builders/update";
|
|
8
9
|
import { DeleteBuilder } from "./builders/delete";
|
|
@@ -13,14 +14,14 @@ import { extractMetadata, type InternalRelationalSchema } from "./core/relations
|
|
|
13
14
|
import { RetryHandler, type RetryConfig } from "./core/retry";
|
|
14
15
|
import { MizzleClient, type IMizzleClient } from "./core/client";
|
|
15
16
|
|
|
16
|
-
export type QuerySchema<TSchema extends Record<string,
|
|
17
|
+
export type QuerySchema<TSchema extends Record<string, any>> = {
|
|
17
18
|
[K in keyof TSchema as TSchema[K] extends Entity ? K : never]: RelationnalQueryBuilder<TSchema[K] extends Entity ? TSchema[K] : never>;
|
|
18
19
|
};
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* DynamoDB database instance.
|
|
22
23
|
*/
|
|
23
|
-
export class DynamoDB<TSchema extends Record<string,
|
|
24
|
+
export class DynamoDB<TSchema extends Record<string, any> = Record<string, any>> {
|
|
24
25
|
private docClient: IMizzleClient;
|
|
25
26
|
private schema?: InternalRelationalSchema;
|
|
26
27
|
private retryConfig: RetryConfig;
|
|
@@ -200,7 +201,7 @@ export class DynamoDB<TSchema extends Record<string, unknown> = Record<string, u
|
|
|
200
201
|
*/
|
|
201
202
|
async transaction(
|
|
202
203
|
token: string,
|
|
203
|
-
callback: (tx: TransactionProxy) =>
|
|
204
|
+
callback: (tx: TransactionProxy) => BaseBuilder<Entity, unknown>[] | Promise<BaseBuilder<Entity, unknown>[]>
|
|
204
205
|
): Promise<void> {
|
|
205
206
|
const proxy = new TransactionProxy(this.docClient);
|
|
206
207
|
const operations = await callback(proxy);
|
|
@@ -220,7 +221,7 @@ export class DynamoDB<TSchema extends Record<string, unknown> = Record<string, u
|
|
|
220
221
|
/**
|
|
221
222
|
* Configuration for initializing Mizzle.
|
|
222
223
|
*/
|
|
223
|
-
export interface MizzleConfig<TSchema extends Record<string,
|
|
224
|
+
export interface MizzleConfig<TSchema extends Record<string, any> = Record<string, any>> {
|
|
224
225
|
/**
|
|
225
226
|
* AWS DynamoDB Client instance from `@aws-sdk/client-dynamodb`.
|
|
226
227
|
*/
|
|
@@ -253,7 +254,7 @@ export interface MizzleConfig<TSchema extends Record<string, unknown> = Record<s
|
|
|
253
254
|
* @param config A DynamoDBClient instance or a MizzleConfig object.
|
|
254
255
|
* @returns A DynamoDB instance for performing database operations.
|
|
255
256
|
*/
|
|
256
|
-
export function mizzle<TSchema extends Record<string,
|
|
257
|
+
export function mizzle<TSchema extends Record<string, any> = Record<string, any>>(
|
|
257
258
|
config: DynamoDBClient | MizzleConfig<TSchema>
|
|
258
259
|
): DynamoDB<TSchema> {
|
|
259
260
|
if (config instanceof DynamoDBClient) {
|
|
@@ -35,8 +35,8 @@ export function buildExpression(
|
|
|
35
35
|
return undefined;
|
|
36
36
|
}
|
|
37
37
|
const colName = addName(cond.column.name);
|
|
38
|
-
const mapValue = (v: unknown) => typeof (cond.column as
|
|
39
|
-
? (cond.column as
|
|
38
|
+
const mapValue = (v: unknown) => typeof (cond.column as unknown as { mapToDynamoValue: Function }).mapToDynamoValue === "function"
|
|
39
|
+
? (cond.column as unknown as { mapToDynamoValue: (v: unknown) => unknown }).mapToDynamoValue(v)
|
|
40
40
|
: v;
|
|
41
41
|
|
|
42
42
|
if (cond.operator === "between") {
|
|
@@ -61,8 +61,8 @@ export function buildExpression(
|
|
|
61
61
|
return undefined;
|
|
62
62
|
}
|
|
63
63
|
const colName = addName(cond.column.name);
|
|
64
|
-
const mapValue = (v: unknown) => typeof (cond.column as
|
|
65
|
-
? (cond.column as
|
|
64
|
+
const mapValue = (v: unknown) => typeof (cond.column as unknown as { mapToDynamoValue: Function }).mapToDynamoValue === "function"
|
|
65
|
+
? (cond.column as unknown as { mapToDynamoValue: (v: unknown) => unknown }).mapToDynamoValue(v)
|
|
66
66
|
: v;
|
|
67
67
|
|
|
68
68
|
if (cond.operator === "attribute_exists") {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Column } from "../core/column";
|
|
2
|
-
import { UpdateAction } from "./actions";
|
|
2
|
+
import { UpdateAction, SetAction, AddAction, DeleteAction } from "./actions";
|
|
3
3
|
|
|
4
4
|
export interface UpdateState {
|
|
5
5
|
set: Record<string, { value: unknown; functionName?: string; usePathAsFirstArg?: boolean }>;
|
|
@@ -24,27 +24,29 @@ export function partitionUpdateValues(
|
|
|
24
24
|
): void {
|
|
25
25
|
for (const [key, val] of Object.entries(values)) {
|
|
26
26
|
const col = columns?.[key];
|
|
27
|
-
const mapValue = (v: unknown) => (col && typeof (col as
|
|
28
|
-
? (col as
|
|
27
|
+
const mapValue = (v: unknown) => (col && typeof (col as unknown as { mapToDynamoValue: Function }).mapToDynamoValue === "function")
|
|
28
|
+
? (col as unknown as { mapToDynamoValue: (v: unknown) => unknown }).mapToDynamoValue(v)
|
|
29
29
|
: v;
|
|
30
30
|
|
|
31
31
|
if (val instanceof UpdateAction) {
|
|
32
32
|
switch (val.action) {
|
|
33
|
-
case "SET":
|
|
33
|
+
case "SET": {
|
|
34
|
+
const setVal = val as SetAction;
|
|
34
35
|
state.set[key] = {
|
|
35
|
-
value: mapValue(
|
|
36
|
-
functionName:
|
|
37
|
-
usePathAsFirstArg:
|
|
36
|
+
value: mapValue(setVal.value),
|
|
37
|
+
functionName: setVal.functionName,
|
|
38
|
+
usePathAsFirstArg: setVal.usePathAsFirstArg,
|
|
38
39
|
};
|
|
39
40
|
break;
|
|
41
|
+
}
|
|
40
42
|
case "ADD":
|
|
41
|
-
state.add[key] = mapValue((val as
|
|
43
|
+
state.add[key] = mapValue((val as AddAction).value);
|
|
42
44
|
break;
|
|
43
45
|
case "REMOVE":
|
|
44
46
|
state.remove.push(key);
|
|
45
47
|
break;
|
|
46
48
|
case "DELETE":
|
|
47
|
-
state.delete[key] = mapValue((val as
|
|
49
|
+
state.delete[key] = mapValue((val as DeleteAction).value);
|
|
48
50
|
break;
|
|
49
51
|
}
|
|
50
52
|
} else if (val !== undefined) {
|
package/src/index.ts
CHANGED
|
@@ -13,6 +13,7 @@ export * from "./builders/relational-builder";
|
|
|
13
13
|
export * from "./core/table";
|
|
14
14
|
export * from "./core/strategies";
|
|
15
15
|
export * from "./core/relations";
|
|
16
|
+
export * from "./core/diff";
|
|
16
17
|
export * from "./core/retry";
|
|
17
18
|
export * from "./core/errors";
|
|
18
19
|
export * from "./columns";
|
package/tsconfig.json
CHANGED