@stonyx/orm 0.3.2-alpha.125 → 0.3.2-alpha.126
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 +2 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/main.d.ts +1 -0
- package/dist/manage-record.d.ts +4 -0
- package/dist/manage-record.js +72 -42
- package/dist/mysql/mysql-db.d.ts +1 -0
- package/dist/mysql/mysql-db.js +1 -0
- package/dist/postgres/postgres-db.d.ts +1 -0
- package/dist/postgres/postgres-db.js +1 -0
- package/package.json +1 -1
- package/src/index.ts +2 -2
- package/src/main.ts +1 -0
- package/src/manage-record.ts +89 -42
- package/src/mysql/mysql-db.ts +1 -0
- package/src/postgres/postgres-db.ts +1 -0
package/README.md
CHANGED
|
@@ -1057,6 +1057,8 @@ test('validation hook rejects negative age', async () => {
|
|
|
1057
1057
|
| `hasMany` | Define a one-to-many relationship. |
|
|
1058
1058
|
| `createRecord` | Instantiate a record with proper serialization and relationships. |
|
|
1059
1059
|
| `updateRecord` | Update an existing record with new data. |
|
|
1060
|
+
| `createRecordAndPersist` | `createRecord`, awaited: resolves once the write has landed, rejects with its error. Not on DynamoDB yet (#299). |
|
|
1061
|
+
| `updateRecordAndPersist` | `updateRecord`, awaited: resolves once the write has landed, rejects with its error. Not on DynamoDB yet (#299). |
|
|
1060
1062
|
| `store` | Singleton store for all model instances. |
|
|
1061
1063
|
| `relationships` | Access all relationships (`hasMany`, `belongsTo`, `global`, `pending`). |
|
|
1062
1064
|
| `beforeHook` | Register a before hook that can halt operations. |
|
package/dist/index.d.ts
CHANGED
|
@@ -4,13 +4,13 @@ import Serializer from './serializer.js';
|
|
|
4
4
|
import attr from './attr.js';
|
|
5
5
|
import belongsTo from './belongs-to.js';
|
|
6
6
|
import hasMany from './has-many.js';
|
|
7
|
-
import { createRecord, updateRecord } from './manage-record.js';
|
|
7
|
+
import { createRecord, updateRecord, createRecordAndPersist, updateRecordAndPersist } from './manage-record.js';
|
|
8
8
|
import { count, avg, sum, min, max } from './aggregates.js';
|
|
9
9
|
export { default } from './main.js';
|
|
10
10
|
export { store, relationships } from './main.js';
|
|
11
11
|
export type { PersistErrorDetail } from './main.js';
|
|
12
12
|
export { Model, View, Serializer };
|
|
13
|
-
export { attr, belongsTo, hasMany, createRecord, updateRecord };
|
|
13
|
+
export { attr, belongsTo, hasMany, createRecord, updateRecord, createRecordAndPersist, updateRecordAndPersist };
|
|
14
14
|
export { count, avg, sum, min, max };
|
|
15
15
|
export { default as normalizeRecordId } from './normalize-record-id.js';
|
|
16
16
|
export type { OrmRequest$ as OrmAccessRequest } from './orm-request.js';
|
package/dist/index.js
CHANGED
|
@@ -19,12 +19,12 @@ import Serializer from './serializer.js';
|
|
|
19
19
|
import attr from './attr.js';
|
|
20
20
|
import belongsTo from './belongs-to.js';
|
|
21
21
|
import hasMany from './has-many.js';
|
|
22
|
-
import { createRecord, updateRecord } from './manage-record.js';
|
|
22
|
+
import { createRecord, updateRecord, createRecordAndPersist, updateRecordAndPersist } from './manage-record.js';
|
|
23
23
|
import { count, avg, sum, min, max } from './aggregates.js';
|
|
24
24
|
export { default } from './main.js';
|
|
25
25
|
export { store, relationships } from './main.js';
|
|
26
26
|
export { Model, View, Serializer }; // base classes
|
|
27
|
-
export { attr, belongsTo, hasMany, createRecord, updateRecord };
|
|
27
|
+
export { attr, belongsTo, hasMany, createRecord, updateRecord, createRecordAndPersist, updateRecordAndPersist };
|
|
28
28
|
export { count, avg, sum, min, max }; // aggregate helpers
|
|
29
29
|
export { default as normalizeRecordId } from './normalize-record-id.js'; // canonical URL-id -> record-id resolution (#270)
|
|
30
30
|
export { beforeHook, afterHook, clearHook, clearAllHooks } from './hooks.js'; // middleware hooks
|
package/dist/main.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ export interface SqlDb {
|
|
|
7
7
|
startup(): Promise<void>;
|
|
8
8
|
shutdown(): Promise<void>;
|
|
9
9
|
persist(operation: string, model: string, context: unknown, response: unknown): Promise<void>;
|
|
10
|
+
persistResolvesAfterWrite?: boolean;
|
|
10
11
|
findRecord(modelName: string, id: unknown): Promise<unknown>;
|
|
11
12
|
findAll(modelName: string, conditions?: Record<string, unknown>): Promise<unknown[]>;
|
|
12
13
|
}
|
package/dist/manage-record.d.ts
CHANGED
|
@@ -11,4 +11,8 @@ export declare function createRecord(modelName: string, rawData?: {
|
|
|
11
11
|
[key: string]: unknown;
|
|
12
12
|
}, userOptions?: CreateRecordOptions): OrmRecord;
|
|
13
13
|
export declare function updateRecord(record: OrmRecord, rawData: unknown, userOptions?: CreateRecordOptions): void;
|
|
14
|
+
export declare function createRecordAndPersist(modelName: string, rawData?: {
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}, userOptions?: CreateRecordOptions): Promise<OrmRecord>;
|
|
17
|
+
export declare function updateRecordAndPersist(record: OrmRecord, rawData: unknown, userOptions?: CreateRecordOptions): Promise<void>;
|
|
14
18
|
export {};
|
package/dist/manage-record.js
CHANGED
|
@@ -8,7 +8,57 @@ const defaultOptions = {
|
|
|
8
8
|
transform: true
|
|
9
9
|
};
|
|
10
10
|
let pendingIdCounter = 0;
|
|
11
|
+
const writeNotRequested = Promise.resolve();
|
|
12
|
+
function ignoreReportedFailure() { }
|
|
13
|
+
function persistRequested(options, userOptions) {
|
|
14
|
+
return !options.isDbRecord && !userOptions._relationshipKey && !options._skipAutoPersist;
|
|
15
|
+
}
|
|
16
|
+
function reportPersistFailure(operation, modelName, recordId, failure) {
|
|
17
|
+
const error = failure instanceof Error ? failure : new Error(String(failure));
|
|
18
|
+
Orm.instance.emitPersistError({ operation, modelName, recordId, error });
|
|
19
|
+
return error;
|
|
20
|
+
}
|
|
11
21
|
export function createRecord(modelName, rawData = {}, userOptions = {}) {
|
|
22
|
+
const { result: record, written } = createRecordWrite(modelName, rawData, userOptions);
|
|
23
|
+
written.catch(ignoreReportedFailure);
|
|
24
|
+
return record;
|
|
25
|
+
}
|
|
26
|
+
export function updateRecord(record, rawData, userOptions = {}) {
|
|
27
|
+
updateRecordWrite(record, rawData, userOptions).written.catch(ignoreReportedFailure);
|
|
28
|
+
}
|
|
29
|
+
export async function createRecordAndPersist(modelName, rawData = {}, userOptions = {}) {
|
|
30
|
+
assertWriteCanBeAwaited();
|
|
31
|
+
const { result: record, written } = createRecordWrite(modelName, rawData, userOptions);
|
|
32
|
+
await written;
|
|
33
|
+
await saveJsonDatabase('create', modelName, record.id, { ...defaultOptions, ...userOptions }, userOptions);
|
|
34
|
+
return record;
|
|
35
|
+
}
|
|
36
|
+
export async function updateRecordAndPersist(record, rawData, userOptions = {}) {
|
|
37
|
+
assertWriteCanBeAwaited();
|
|
38
|
+
await updateRecordWrite(record, rawData, userOptions).written;
|
|
39
|
+
await saveJsonDatabase('update', record?.__model?.__name ?? '', record.id, { ...defaultOptions, ...userOptions }, userOptions);
|
|
40
|
+
}
|
|
41
|
+
function assertWriteCanBeAwaited() {
|
|
42
|
+
const sqlDb = Orm.instance?.sqlDb;
|
|
43
|
+
if (sqlDb && sqlDb.persistResolvesAfterWrite !== true) {
|
|
44
|
+
throw new Error('The configured database adapter cannot confirm a write has landed, so createRecordAndPersist/updateRecordAndPersist are unavailable for it (DynamoDB: abofs/stonyx-orm#299)');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async function saveJsonDatabase(operation, modelName, recordId, options, userOptions) {
|
|
48
|
+
const orm = Orm.instance;
|
|
49
|
+
if (orm.sqlDb || !persistRequested(options, userOptions))
|
|
50
|
+
return;
|
|
51
|
+
const jsonDatabase = orm.db;
|
|
52
|
+
if (!jsonDatabase?.save)
|
|
53
|
+
return;
|
|
54
|
+
try {
|
|
55
|
+
await jsonDatabase.save();
|
|
56
|
+
}
|
|
57
|
+
catch (failure) {
|
|
58
|
+
throw reportPersistFailure(operation, modelName, recordId, failure);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function createRecordWrite(modelName, rawData, userOptions) {
|
|
12
62
|
const orm = Orm.instance;
|
|
13
63
|
const { initialized } = Orm;
|
|
14
64
|
const options = { ...defaultOptions, ...userOptions };
|
|
@@ -26,9 +76,7 @@ export function createRecord(modelName, rawData = {}, userOptions = {}) {
|
|
|
26
76
|
assignRecordId(modelName, rawData);
|
|
27
77
|
const existingRecord = modelStore.get(rawData.id);
|
|
28
78
|
if (existingRecord instanceof OrmRecord) {
|
|
29
|
-
|
|
30
|
-
updateRecord(existingRecord, rawData, { ...options, update: true });
|
|
31
|
-
return existingRecord;
|
|
79
|
+
return { result: existingRecord, written: updateRecordWrite(existingRecord, rawData, { ...options, update: true }).written };
|
|
32
80
|
}
|
|
33
81
|
const recordClasses = orm.getRecordClasses(modelName);
|
|
34
82
|
const modelClass = recordClasses.modelClass;
|
|
@@ -101,56 +149,38 @@ export function createRecord(modelName, rawData = {}, userOptions = {}) {
|
|
|
101
149
|
// Clear the pending queue
|
|
102
150
|
pendingBelongsTo.length = 0;
|
|
103
151
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
});
|
|
119
|
-
})
|
|
120
|
-
.finally(() => {
|
|
121
|
-
// Evict non-memory records after persist to prevent unbounded heap growth (stonyx#81)
|
|
122
|
-
if (store._memoryResolver && !store._memoryResolver(modelName)) {
|
|
123
|
-
store.evictRecord(modelName, record.id, registryId);
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
return record;
|
|
152
|
+
if (!orm?.sqlDb || !persistRequested(options, userOptions))
|
|
153
|
+
return { result: record, written: writeNotRequested };
|
|
154
|
+
const registryIdBeforePersist = record.id;
|
|
155
|
+
const response = { data: { id: record.id } };
|
|
156
|
+
const written = orm.sqlDb.persist('create', modelName, { rawData }, response)
|
|
157
|
+
.catch((failure) => {
|
|
158
|
+
throw reportPersistFailure('create', modelName, record.id, failure);
|
|
159
|
+
})
|
|
160
|
+
.finally(() => {
|
|
161
|
+
if (store._memoryResolver && !store._memoryResolver(modelName)) {
|
|
162
|
+
store.evictRecord(modelName, record.id, registryIdBeforePersist);
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
return { result: record, written };
|
|
128
166
|
}
|
|
129
|
-
|
|
167
|
+
function updateRecordWrite(record, rawData, userOptions) {
|
|
130
168
|
if (!rawData)
|
|
131
169
|
throw new Error('rawData must be passed in to updateRecord call');
|
|
132
|
-
// Guard: read-only views cannot be updated
|
|
133
170
|
const modelName = record?.__model?.__name;
|
|
134
171
|
if (modelName && Orm.instance?.isView?.(modelName)) {
|
|
135
172
|
throw new Error(`Cannot update records for read-only view '${modelName}'`);
|
|
136
173
|
}
|
|
137
174
|
const options = { ...defaultOptions, ...userOptions, update: true };
|
|
138
|
-
// Capture old state before update for SQL diff
|
|
139
175
|
const oldState = record.__data ? JSON.parse(JSON.stringify(record.__data)) : {};
|
|
140
176
|
record.serialize(rawData, options);
|
|
141
|
-
// Auto-persist to SQL — skip for DB loads (isDbRecord) and relationship resolution (_relationshipKey)
|
|
142
177
|
const orm = Orm.instance;
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
recordId: record.id,
|
|
150
|
-
error: err instanceof Error ? err : new Error(String(err)),
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
}
|
|
178
|
+
if (!orm?.sqlDb || !modelName || !persistRequested(options, userOptions))
|
|
179
|
+
return { result: undefined, written: writeNotRequested };
|
|
180
|
+
const written = orm.sqlDb.persist('update', modelName, { record, oldState }, {}).catch((failure) => {
|
|
181
|
+
throw reportPersistFailure('update', modelName, record.id, failure);
|
|
182
|
+
});
|
|
183
|
+
return { result: undefined, written };
|
|
154
184
|
}
|
|
155
185
|
/**
|
|
156
186
|
* gets the next available id based on last record entry.
|
package/dist/mysql/mysql-db.d.ts
CHANGED
package/dist/mysql/mysql-db.js
CHANGED
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -21,14 +21,14 @@ import Serializer from './serializer.js';
|
|
|
21
21
|
import attr from './attr.js';
|
|
22
22
|
import belongsTo from './belongs-to.js';
|
|
23
23
|
import hasMany from './has-many.js';
|
|
24
|
-
import { createRecord, updateRecord } from './manage-record.js';
|
|
24
|
+
import { createRecord, updateRecord, createRecordAndPersist, updateRecordAndPersist } from './manage-record.js';
|
|
25
25
|
import { count, avg, sum, min, max } from './aggregates.js';
|
|
26
26
|
|
|
27
27
|
export { default } from './main.js';
|
|
28
28
|
export { store, relationships } from './main.js';
|
|
29
29
|
export type { PersistErrorDetail } from './main.js';
|
|
30
30
|
export { Model, View, Serializer }; // base classes
|
|
31
|
-
export { attr, belongsTo, hasMany, createRecord, updateRecord };
|
|
31
|
+
export { attr, belongsTo, hasMany, createRecord, updateRecord, createRecordAndPersist, updateRecordAndPersist };
|
|
32
32
|
export { count, avg, sum, min, max }; // aggregate helpers
|
|
33
33
|
export { default as normalizeRecordId } from './normalize-record-id.js'; // canonical URL-id -> record-id resolution (#270)
|
|
34
34
|
export type { OrmRequest$ as OrmAccessRequest } from './orm-request.js'; // the request access() is handed, incl. recordId (#270)
|
package/src/main.ts
CHANGED
|
@@ -34,6 +34,7 @@ export interface SqlDb {
|
|
|
34
34
|
startup(): Promise<void>;
|
|
35
35
|
shutdown(): Promise<void>;
|
|
36
36
|
persist(operation: string, model: string, context: unknown, response: unknown): Promise<void>;
|
|
37
|
+
persistResolvesAfterWrite?: boolean;
|
|
37
38
|
findRecord(modelName: string, id: unknown): Promise<unknown>;
|
|
38
39
|
findAll(modelName: string, conditions?: Record<string, unknown>): Promise<unknown[]>;
|
|
39
40
|
}
|
package/src/manage-record.ts
CHANGED
|
@@ -28,7 +28,73 @@ const defaultOptions: CreateRecordOptions = {
|
|
|
28
28
|
|
|
29
29
|
let pendingIdCounter = 0;
|
|
30
30
|
|
|
31
|
+
interface RecordWrite<Result> {
|
|
32
|
+
result: Result;
|
|
33
|
+
written: Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
type AwaitedOperation = 'create' | 'update';
|
|
37
|
+
|
|
38
|
+
const writeNotRequested = Promise.resolve();
|
|
39
|
+
|
|
40
|
+
function ignoreReportedFailure(): void {}
|
|
41
|
+
|
|
42
|
+
function persistRequested(options: CreateRecordOptions, userOptions: CreateRecordOptions): boolean {
|
|
43
|
+
return !options.isDbRecord && !userOptions._relationshipKey && !options._skipAutoPersist;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function reportPersistFailure(operation: AwaitedOperation, modelName: string, recordId: unknown, failure: unknown): Error {
|
|
47
|
+
const error = failure instanceof Error ? failure : new Error(String(failure));
|
|
48
|
+
Orm.instance.emitPersistError({ operation, modelName, recordId, error });
|
|
49
|
+
return error;
|
|
50
|
+
}
|
|
51
|
+
|
|
31
52
|
export function createRecord(modelName: string, rawData: { [key: string]: unknown } = {}, userOptions: CreateRecordOptions = {}): OrmRecord {
|
|
53
|
+
const { result: record, written } = createRecordWrite(modelName, rawData, userOptions);
|
|
54
|
+
written.catch(ignoreReportedFailure);
|
|
55
|
+
return record;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function updateRecord(record: OrmRecord, rawData: unknown, userOptions: CreateRecordOptions = {}): void {
|
|
59
|
+
updateRecordWrite(record, rawData, userOptions).written.catch(ignoreReportedFailure);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export async function createRecordAndPersist(modelName: string, rawData: { [key: string]: unknown } = {}, userOptions: CreateRecordOptions = {}): Promise<OrmRecord> {
|
|
63
|
+
assertWriteCanBeAwaited();
|
|
64
|
+
const { result: record, written } = createRecordWrite(modelName, rawData, userOptions);
|
|
65
|
+
await written;
|
|
66
|
+
await saveJsonDatabase('create', modelName, record.id, { ...defaultOptions, ...userOptions }, userOptions);
|
|
67
|
+
return record;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export async function updateRecordAndPersist(record: OrmRecord, rawData: unknown, userOptions: CreateRecordOptions = {}): Promise<void> {
|
|
71
|
+
assertWriteCanBeAwaited();
|
|
72
|
+
await updateRecordWrite(record, rawData, userOptions).written;
|
|
73
|
+
await saveJsonDatabase('update', record?.__model?.__name ?? '', record.id, { ...defaultOptions, ...userOptions }, userOptions);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function assertWriteCanBeAwaited(): void {
|
|
77
|
+
const sqlDb = Orm.instance?.sqlDb as { persistResolvesAfterWrite?: boolean } | undefined;
|
|
78
|
+
if (sqlDb && sqlDb.persistResolvesAfterWrite !== true) {
|
|
79
|
+
throw new Error('The configured database adapter cannot confirm a write has landed, so createRecordAndPersist/updateRecordAndPersist are unavailable for it (DynamoDB: abofs/stonyx-orm#299)');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
async function saveJsonDatabase(operation: AwaitedOperation, modelName: string, recordId: unknown, options: CreateRecordOptions, userOptions: CreateRecordOptions): Promise<void> {
|
|
84
|
+
const orm = Orm.instance;
|
|
85
|
+
if (orm.sqlDb || !persistRequested(options, userOptions)) return;
|
|
86
|
+
|
|
87
|
+
const jsonDatabase = orm.db as { save?: () => Promise<void> } | undefined;
|
|
88
|
+
if (!jsonDatabase?.save) return;
|
|
89
|
+
|
|
90
|
+
try {
|
|
91
|
+
await jsonDatabase.save();
|
|
92
|
+
} catch (failure) {
|
|
93
|
+
throw reportPersistFailure(operation, modelName, recordId, failure);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function createRecordWrite(modelName: string, rawData: { [key: string]: unknown }, userOptions: CreateRecordOptions): RecordWrite<OrmRecord> {
|
|
32
98
|
const orm = Orm.instance;
|
|
33
99
|
const { initialized } = Orm;
|
|
34
100
|
const options = { ...defaultOptions, ...userOptions };
|
|
@@ -50,9 +116,7 @@ export function createRecord(modelName: string, rawData: { [key: string]: unknow
|
|
|
50
116
|
const existingRecord = modelStore.get(rawData.id as number | string);
|
|
51
117
|
|
|
52
118
|
if (existingRecord instanceof OrmRecord) {
|
|
53
|
-
|
|
54
|
-
updateRecord(existingRecord, rawData, { ...options, update: true });
|
|
55
|
-
return existingRecord;
|
|
119
|
+
return { result: existingRecord, written: updateRecordWrite(existingRecord, rawData, { ...options, update: true }).written };
|
|
56
120
|
}
|
|
57
121
|
|
|
58
122
|
const recordClasses = orm.getRecordClasses(modelName);
|
|
@@ -136,37 +200,26 @@ export function createRecord(modelName: string, rawData: { [key: string]: unknow
|
|
|
136
200
|
pendingBelongsTo.length = 0;
|
|
137
201
|
}
|
|
138
202
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
error: err instanceof Error ? err : new Error(String(err)),
|
|
153
|
-
});
|
|
154
|
-
})
|
|
155
|
-
.finally(() => {
|
|
156
|
-
// Evict non-memory records after persist to prevent unbounded heap growth (stonyx#81)
|
|
157
|
-
if (store._memoryResolver && !store._memoryResolver(modelName)) {
|
|
158
|
-
store.evictRecord(modelName, record.id, registryId);
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
}
|
|
203
|
+
if (!orm?.sqlDb || !persistRequested(options, userOptions)) return { result: record, written: writeNotRequested };
|
|
204
|
+
|
|
205
|
+
const registryIdBeforePersist = record.id;
|
|
206
|
+
const response = { data: { id: record.id } };
|
|
207
|
+
const written = orm.sqlDb.persist('create', modelName, { rawData }, response)
|
|
208
|
+
.catch((failure: unknown) => {
|
|
209
|
+
throw reportPersistFailure('create', modelName, record.id, failure);
|
|
210
|
+
})
|
|
211
|
+
.finally(() => {
|
|
212
|
+
if (store._memoryResolver && !store._memoryResolver(modelName)) {
|
|
213
|
+
store.evictRecord(modelName, record.id, registryIdBeforePersist);
|
|
214
|
+
}
|
|
215
|
+
});
|
|
162
216
|
|
|
163
|
-
return record;
|
|
217
|
+
return { result: record, written };
|
|
164
218
|
}
|
|
165
219
|
|
|
166
|
-
|
|
220
|
+
function updateRecordWrite(record: OrmRecord, rawData: unknown, userOptions: CreateRecordOptions): RecordWrite<void> {
|
|
167
221
|
if (!rawData) throw new Error('rawData must be passed in to updateRecord call');
|
|
168
222
|
|
|
169
|
-
// Guard: read-only views cannot be updated
|
|
170
223
|
const modelName = record?.__model?.__name;
|
|
171
224
|
if (modelName && Orm.instance?.isView?.(modelName)) {
|
|
172
225
|
throw new Error(`Cannot update records for read-only view '${modelName}'`);
|
|
@@ -174,24 +227,18 @@ export function updateRecord(record: OrmRecord, rawData: unknown, userOptions: C
|
|
|
174
227
|
|
|
175
228
|
const options = { ...defaultOptions, ...userOptions, update: true };
|
|
176
229
|
|
|
177
|
-
// Capture old state before update for SQL diff
|
|
178
230
|
const oldState = record.__data ? JSON.parse(JSON.stringify(record.__data)) : {};
|
|
179
231
|
|
|
180
232
|
record.serialize(rawData, options);
|
|
181
233
|
|
|
182
|
-
// Auto-persist to SQL — skip for DB loads (isDbRecord) and relationship resolution (_relationshipKey)
|
|
183
234
|
const orm = Orm.instance;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
error: err instanceof Error ? err : new Error(String(err)),
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
}
|
|
235
|
+
if (!orm?.sqlDb || !modelName || !persistRequested(options, userOptions)) return { result: undefined, written: writeNotRequested };
|
|
236
|
+
|
|
237
|
+
const written = orm.sqlDb.persist('update', modelName, { record, oldState }, {}).catch((failure: unknown) => {
|
|
238
|
+
throw reportPersistFailure('update', modelName, record.id, failure);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
return { result: undefined, written };
|
|
195
242
|
}
|
|
196
243
|
|
|
197
244
|
/**
|
package/src/mysql/mysql-db.ts
CHANGED
|
@@ -123,6 +123,7 @@ export default class MysqlDB {
|
|
|
123
123
|
pool!: Pool | null;
|
|
124
124
|
mysqlConfig!: MysqlConfig;
|
|
125
125
|
|
|
126
|
+
readonly persistResolvesAfterWrite = true;
|
|
126
127
|
private _queuedWrites: QueuedWrite[] = [];
|
|
127
128
|
private _inFlightWrites = new Set<QueuedWrite>();
|
|
128
129
|
private _drainingWrites: Promise<void> | null = null;
|
|
@@ -134,6 +134,7 @@ export default class PostgresDB {
|
|
|
134
134
|
pool!: Pool | null;
|
|
135
135
|
pgConfig!: Record<string, unknown>;
|
|
136
136
|
|
|
137
|
+
readonly persistResolvesAfterWrite = true;
|
|
137
138
|
private _queuedWrites: QueuedWrite[] = [];
|
|
138
139
|
private _inFlightWrites = new Set<QueuedWrite>();
|
|
139
140
|
private _drainingWrites: Promise<void> | null = null;
|