@fragno-dev/db 0.1.13 → 0.1.14
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/.turbo/turbo-build.log +48 -41
- package/CHANGELOG.md +6 -0
- package/dist/adapters/adapters.d.ts +13 -1
- package/dist/adapters/adapters.d.ts.map +1 -1
- package/dist/adapters/adapters.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.d.ts +2 -0
- package/dist/adapters/drizzle/drizzle-adapter.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-adapter.js +6 -1
- package/dist/adapters/drizzle/drizzle-adapter.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-query.js +6 -4
- package/dist/adapters/drizzle/drizzle-query.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts +0 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.d.ts.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-compiler.js +49 -36
- package/dist/adapters/drizzle/drizzle-uow-compiler.js.map +1 -1
- package/dist/adapters/drizzle/drizzle-uow-decoder.js +1 -1
- package/dist/adapters/drizzle/drizzle-uow-decoder.js.map +1 -1
- package/dist/adapters/drizzle/shared.d.ts +14 -1
- package/dist/adapters/drizzle/shared.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts +2 -0
- package/dist/adapters/kysely/kysely-adapter.d.ts.map +1 -1
- package/dist/adapters/kysely/kysely-adapter.js +7 -2
- package/dist/adapters/kysely/kysely-adapter.js.map +1 -1
- package/dist/adapters/kysely/kysely-query.js +5 -3
- package/dist/adapters/kysely/kysely-query.js.map +1 -1
- package/dist/adapters/kysely/kysely-shared.d.ts +11 -0
- package/dist/adapters/kysely/kysely-shared.d.ts.map +1 -0
- package/dist/adapters/kysely/kysely-uow-compiler.js +38 -9
- package/dist/adapters/kysely/kysely-uow-compiler.js.map +1 -1
- package/dist/bind-services.d.ts +7 -0
- package/dist/bind-services.d.ts.map +1 -0
- package/dist/bind-services.js +14 -0
- package/dist/bind-services.js.map +1 -0
- package/dist/fragment.d.ts +131 -12
- package/dist/fragment.d.ts.map +1 -1
- package/dist/fragment.js +107 -8
- package/dist/fragment.js.map +1 -1
- package/dist/mod.d.ts +4 -2
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +3 -2
- package/dist/mod.js.map +1 -1
- package/dist/query/query.d.ts +2 -2
- package/dist/query/query.d.ts.map +1 -1
- package/dist/query/unit-of-work.d.ts +100 -15
- package/dist/query/unit-of-work.d.ts.map +1 -1
- package/dist/query/unit-of-work.js +214 -7
- package/dist/query/unit-of-work.js.map +1 -1
- package/package.json +3 -3
- package/src/adapters/adapters.ts +14 -0
- package/src/adapters/drizzle/drizzle-adapter-pglite.test.ts +6 -1
- package/src/adapters/drizzle/drizzle-adapter-sqlite.test.ts +133 -5
- package/src/adapters/drizzle/drizzle-adapter.ts +16 -1
- package/src/adapters/drizzle/drizzle-query.ts +26 -15
- package/src/adapters/drizzle/drizzle-uow-compiler.test.ts +57 -57
- package/src/adapters/drizzle/drizzle-uow-compiler.ts +79 -39
- package/src/adapters/drizzle/drizzle-uow-decoder.ts +2 -5
- package/src/adapters/kysely/kysely-adapter-pglite.test.ts +2 -2
- package/src/adapters/kysely/kysely-adapter.ts +16 -1
- package/src/adapters/kysely/kysely-query.ts +26 -15
- package/src/adapters/kysely/kysely-uow-compiler.test.ts +43 -43
- package/src/adapters/kysely/kysely-uow-compiler.ts +50 -14
- package/src/adapters/kysely/kysely-uow-joins.test.ts +30 -30
- package/src/bind-services.test.ts +214 -0
- package/src/bind-services.ts +37 -0
- package/src/db-fragment.test.ts +800 -0
- package/src/fragment.ts +557 -28
- package/src/mod.ts +19 -0
- package/src/query/query.ts +2 -2
- package/src/query/unit-of-work-multi-schema.test.ts +64 -0
- package/src/query/unit-of-work-types.test.ts +13 -0
- package/src/query/unit-of-work.test.ts +5 -9
- package/src/query/unit-of-work.ts +511 -62
- package/src/uow-context-integration.test.ts +102 -0
- package/src/uow-context.test.ts +182 -0
- package/src/fragment.test.ts +0 -341
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import type { AnySchema, AnyTable, Index, IdColumn, AnyColumn, Relation } from "../schema/create";
|
|
2
2
|
import { FragnoId } from "../schema/create";
|
|
3
3
|
import type { Condition, ConditionBuilder } from "./condition-builder";
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
SelectClause,
|
|
6
|
+
TableToInsertValues,
|
|
7
|
+
TableToUpdateValues,
|
|
8
|
+
SelectResult,
|
|
9
|
+
ExtractSelect,
|
|
10
|
+
ExtractJoinOut,
|
|
11
|
+
} from "./query";
|
|
5
12
|
import { buildCondition } from "./condition-builder";
|
|
6
13
|
import type { CompiledJoin } from "./orm/orm";
|
|
7
14
|
import type { CursorResult } from "./cursor";
|
|
8
15
|
import { Cursor } from "./cursor";
|
|
16
|
+
import type { Prettify } from "../util/types";
|
|
9
17
|
|
|
10
18
|
/**
|
|
11
19
|
* Builder for updateMany operations that supports both whereIndex and set chaining
|
|
@@ -143,6 +151,8 @@ export type RetrievalOperation<
|
|
|
143
151
|
> =
|
|
144
152
|
| {
|
|
145
153
|
type: "find";
|
|
154
|
+
schema: TSchema;
|
|
155
|
+
namespace?: string;
|
|
146
156
|
table: TTable;
|
|
147
157
|
indexName: string;
|
|
148
158
|
options: FindOptions<TTable, SelectClause<TTable>>;
|
|
@@ -150,6 +160,8 @@ export type RetrievalOperation<
|
|
|
150
160
|
}
|
|
151
161
|
| {
|
|
152
162
|
type: "count";
|
|
163
|
+
schema: TSchema;
|
|
164
|
+
namespace?: string;
|
|
153
165
|
table: TTable;
|
|
154
166
|
indexName: string;
|
|
155
167
|
options: Pick<FindOptions<TTable>, "where" | "useIndex">;
|
|
@@ -164,6 +176,8 @@ export type MutationOperation<
|
|
|
164
176
|
> =
|
|
165
177
|
| {
|
|
166
178
|
type: "update";
|
|
179
|
+
schema: TSchema;
|
|
180
|
+
namespace?: string;
|
|
167
181
|
table: TTable["name"];
|
|
168
182
|
id: FragnoId | string;
|
|
169
183
|
checkVersion: boolean;
|
|
@@ -171,12 +185,16 @@ export type MutationOperation<
|
|
|
171
185
|
}
|
|
172
186
|
| {
|
|
173
187
|
type: "create";
|
|
188
|
+
schema: TSchema;
|
|
189
|
+
namespace?: string;
|
|
174
190
|
table: TTable["name"];
|
|
175
191
|
values: TableToInsertValues<TTable>;
|
|
176
192
|
generatedExternalId: string;
|
|
177
193
|
}
|
|
178
194
|
| {
|
|
179
195
|
type: "delete";
|
|
196
|
+
schema: TSchema;
|
|
197
|
+
namespace?: string;
|
|
180
198
|
table: TTable["name"];
|
|
181
199
|
id: FragnoId | string;
|
|
182
200
|
checkVersion: boolean;
|
|
@@ -198,16 +216,16 @@ export interface CompiledMutation<TOutput> {
|
|
|
198
216
|
/**
|
|
199
217
|
* Compiler interface for Unit of Work operations
|
|
200
218
|
*/
|
|
201
|
-
export interface UOWCompiler<
|
|
219
|
+
export interface UOWCompiler<TOutput> {
|
|
202
220
|
/**
|
|
203
221
|
* Compile a retrieval operation to the adapter's query format
|
|
204
222
|
*/
|
|
205
|
-
compileRetrievalOperation(op: RetrievalOperation<
|
|
223
|
+
compileRetrievalOperation(op: RetrievalOperation<AnySchema>): TOutput | null;
|
|
206
224
|
|
|
207
225
|
/**
|
|
208
226
|
* Compile a mutation operation to the adapter's query format
|
|
209
227
|
*/
|
|
210
|
-
compileMutationOperation(op: MutationOperation<
|
|
228
|
+
compileMutationOperation(op: MutationOperation<AnySchema>): CompiledMutation<TOutput> | null;
|
|
211
229
|
}
|
|
212
230
|
|
|
213
231
|
export type MutationResult =
|
|
@@ -237,7 +255,7 @@ export interface UOWExecutor<TOutput, TRawResult = unknown> {
|
|
|
237
255
|
* Transforms raw database results into application format (e.g., converting raw columns
|
|
238
256
|
* into FragnoId objects with external ID, internal ID, and version).
|
|
239
257
|
*/
|
|
240
|
-
export interface UOWDecoder<
|
|
258
|
+
export interface UOWDecoder<TRawInput = unknown> {
|
|
241
259
|
/**
|
|
242
260
|
* Decode raw database results from the retrieval phase
|
|
243
261
|
*
|
|
@@ -245,7 +263,7 @@ export interface UOWDecoder<TSchema extends AnySchema, TRawInput = unknown> {
|
|
|
245
263
|
* @param operations - Array of retrieval operations that produced these results
|
|
246
264
|
* @returns Decoded results in application format
|
|
247
265
|
*/
|
|
248
|
-
(rawResults: TRawInput[], operations: RetrievalOperation<
|
|
266
|
+
(rawResults: TRawInput[], operations: RetrievalOperation<AnySchema>[]): unknown[];
|
|
249
267
|
}
|
|
250
268
|
|
|
251
269
|
/**
|
|
@@ -843,22 +861,45 @@ export function buildJoinIndexed<TTable extends AnyTable, TJoinOut>(
|
|
|
843
861
|
return compiled;
|
|
844
862
|
}
|
|
845
863
|
|
|
864
|
+
/**
|
|
865
|
+
* Base interface for Unit of Work with schema-agnostic methods only.
|
|
866
|
+
* This allows UOW instances to be passed between services that use different schemas.
|
|
867
|
+
*/
|
|
868
|
+
export interface IUnitOfWorkBase {
|
|
869
|
+
// Getters (schema-agnostic)
|
|
870
|
+
readonly state: UOWState;
|
|
871
|
+
readonly name: string | undefined;
|
|
872
|
+
readonly retrievalPhase: Promise<unknown[]>;
|
|
873
|
+
readonly mutationPhase: Promise<void>;
|
|
874
|
+
|
|
875
|
+
// Execution (schema-agnostic)
|
|
876
|
+
executeRetrieve(): Promise<unknown[]>;
|
|
877
|
+
executeMutations(): Promise<{ success: boolean }>;
|
|
878
|
+
|
|
879
|
+
// Inspection (schema-agnostic)
|
|
880
|
+
getRetrievalOperations(): ReadonlyArray<RetrievalOperation<AnySchema>>;
|
|
881
|
+
getMutationOperations(): ReadonlyArray<MutationOperation<AnySchema>>;
|
|
882
|
+
getCreatedIds(): FragnoId[];
|
|
883
|
+
|
|
884
|
+
// Schema-specific view (for cross-schema operations)
|
|
885
|
+
forSchema<TOtherSchema extends AnySchema>(
|
|
886
|
+
schema: TOtherSchema,
|
|
887
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
888
|
+
): UnitOfWorkSchemaView<TOtherSchema, [], any>;
|
|
889
|
+
}
|
|
890
|
+
|
|
846
891
|
export function createUnitOfWork<
|
|
847
892
|
const TSchema extends AnySchema,
|
|
848
893
|
const TRetrievalResults extends unknown[] = [],
|
|
849
894
|
const TRawInput = unknown,
|
|
850
895
|
>(
|
|
851
896
|
schema: TSchema,
|
|
852
|
-
compiler: UOWCompiler<
|
|
897
|
+
compiler: UOWCompiler<unknown>,
|
|
853
898
|
executor: UOWExecutor<unknown, TRawInput>,
|
|
854
|
-
decoder: UOWDecoder<
|
|
899
|
+
decoder: UOWDecoder<TRawInput>,
|
|
855
900
|
name?: string,
|
|
856
901
|
): UnitOfWork<TSchema, TRetrievalResults, TRawInput> {
|
|
857
|
-
return new UnitOfWork(schema, compiler, executor, decoder, name)
|
|
858
|
-
TSchema,
|
|
859
|
-
TRetrievalResults,
|
|
860
|
-
TRawInput
|
|
861
|
-
>;
|
|
902
|
+
return new UnitOfWork(schema, compiler, executor, decoder, name);
|
|
862
903
|
}
|
|
863
904
|
|
|
864
905
|
export interface UnitOfWorkConfig {
|
|
@@ -898,7 +939,8 @@ export class UnitOfWork<
|
|
|
898
939
|
const TSchema extends AnySchema,
|
|
899
940
|
const TRetrievalResults extends unknown[] = [],
|
|
900
941
|
const TRawInput = unknown,
|
|
901
|
-
>
|
|
942
|
+
> implements IUnitOfWorkBase
|
|
943
|
+
{
|
|
902
944
|
#schema: TSchema;
|
|
903
945
|
|
|
904
946
|
#name?: string;
|
|
@@ -906,23 +948,32 @@ export class UnitOfWork<
|
|
|
906
948
|
|
|
907
949
|
#state: UOWState = "building-retrieval";
|
|
908
950
|
|
|
909
|
-
|
|
910
|
-
#
|
|
951
|
+
// Operations can now come from any schema
|
|
952
|
+
#retrievalOps: RetrievalOperation<AnySchema>[] = [];
|
|
953
|
+
#mutationOps: MutationOperation<AnySchema>[] = [];
|
|
911
954
|
|
|
912
|
-
#compiler: UOWCompiler<
|
|
955
|
+
#compiler: UOWCompiler<unknown>;
|
|
913
956
|
#executor: UOWExecutor<unknown, TRawInput>;
|
|
914
|
-
#decoder: UOWDecoder<
|
|
957
|
+
#decoder: UOWDecoder<TRawInput>;
|
|
958
|
+
#schemaNamespaceMap?: WeakMap<AnySchema, string>;
|
|
915
959
|
|
|
916
960
|
#retrievalResults?: TRetrievalResults;
|
|
917
961
|
#createdInternalIds: (bigint | null)[] = [];
|
|
918
962
|
|
|
963
|
+
// Phase coordination promises
|
|
964
|
+
#retrievalPhaseResolve?: (value: TRetrievalResults) => void;
|
|
965
|
+
#mutationPhaseResolve?: () => void;
|
|
966
|
+
#retrievalPhasePromise: Promise<TRetrievalResults>;
|
|
967
|
+
#mutationPhasePromise: Promise<void>;
|
|
968
|
+
|
|
919
969
|
constructor(
|
|
920
970
|
schema: TSchema,
|
|
921
|
-
compiler: UOWCompiler<
|
|
971
|
+
compiler: UOWCompiler<unknown>,
|
|
922
972
|
executor: UOWExecutor<unknown, TRawInput>,
|
|
923
|
-
decoder: UOWDecoder<
|
|
973
|
+
decoder: UOWDecoder<TRawInput>,
|
|
924
974
|
name?: string,
|
|
925
975
|
config?: UnitOfWorkConfig,
|
|
976
|
+
schemaNamespaceMap?: WeakMap<AnySchema, string>,
|
|
926
977
|
) {
|
|
927
978
|
this.#schema = schema;
|
|
928
979
|
this.#compiler = compiler;
|
|
@@ -930,12 +981,45 @@ export class UnitOfWork<
|
|
|
930
981
|
this.#decoder = decoder;
|
|
931
982
|
this.#name = name;
|
|
932
983
|
this.#config = config;
|
|
984
|
+
this.#schemaNamespaceMap = schemaNamespaceMap;
|
|
985
|
+
|
|
986
|
+
// Initialize phase coordination promises
|
|
987
|
+
this.#retrievalPhasePromise = new Promise<TRetrievalResults>((resolve) => {
|
|
988
|
+
this.#retrievalPhaseResolve = resolve;
|
|
989
|
+
});
|
|
990
|
+
this.#mutationPhasePromise = new Promise<void>((resolve) => {
|
|
991
|
+
this.#mutationPhaseResolve = resolve;
|
|
992
|
+
});
|
|
933
993
|
}
|
|
934
994
|
|
|
935
995
|
get schema(): TSchema {
|
|
936
996
|
return this.#schema;
|
|
937
997
|
}
|
|
938
998
|
|
|
999
|
+
get $results(): Prettify<TRetrievalResults> {
|
|
1000
|
+
throw new Error("type only");
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Get a schema-specific view of this UOW for type-safe operations
|
|
1005
|
+
* Returns a wrapper that uses a different schema for operations.
|
|
1006
|
+
* The namespace is automatically resolved from the schema-namespace map.
|
|
1007
|
+
*/
|
|
1008
|
+
forSchema<TOtherSchema extends AnySchema>(
|
|
1009
|
+
schema: TOtherSchema,
|
|
1010
|
+
): UnitOfWorkSchemaView<TOtherSchema, [], TRawInput> {
|
|
1011
|
+
// Look up namespace from map
|
|
1012
|
+
const resolvedNamespace = this.#schemaNamespaceMap?.get(schema);
|
|
1013
|
+
|
|
1014
|
+
// Safe cast: UnitOfWorkSchemaView starts with empty result types
|
|
1015
|
+
// As operations are added, the types will accumulate correctly
|
|
1016
|
+
return new UnitOfWorkSchemaView(
|
|
1017
|
+
schema,
|
|
1018
|
+
resolvedNamespace,
|
|
1019
|
+
this as unknown as UnitOfWork<AnySchema, unknown[], TRawInput>,
|
|
1020
|
+
);
|
|
1021
|
+
}
|
|
1022
|
+
|
|
939
1023
|
get state(): UOWState {
|
|
940
1024
|
return this.#state;
|
|
941
1025
|
}
|
|
@@ -944,28 +1028,46 @@ export class UnitOfWork<
|
|
|
944
1028
|
return this.#name;
|
|
945
1029
|
}
|
|
946
1030
|
|
|
1031
|
+
/**
|
|
1032
|
+
* Promise that resolves when the retrieval phase is executed
|
|
1033
|
+
* Service methods can await this to coordinate multi-phase logic
|
|
1034
|
+
*/
|
|
1035
|
+
get retrievalPhase(): Promise<TRetrievalResults> {
|
|
1036
|
+
return this.#retrievalPhasePromise;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
/**
|
|
1040
|
+
* Promise that resolves when the mutation phase is executed
|
|
1041
|
+
* Service methods can await this to coordinate multi-phase logic
|
|
1042
|
+
*/
|
|
1043
|
+
get mutationPhase(): Promise<void> {
|
|
1044
|
+
return this.#mutationPhasePromise;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
947
1047
|
/**
|
|
948
1048
|
* Execute the retrieval phase and transition to mutation phase
|
|
949
1049
|
* Returns all results from find operations
|
|
950
1050
|
*/
|
|
951
1051
|
async executeRetrieve(): Promise<TRetrievalResults> {
|
|
952
|
-
if (this.#retrievalOps.length === 0) {
|
|
953
|
-
return [] as unknown as TRetrievalResults;
|
|
954
|
-
}
|
|
955
|
-
|
|
956
1052
|
if (this.#state !== "building-retrieval") {
|
|
957
1053
|
throw new Error(
|
|
958
1054
|
`Cannot execute retrieval from state ${this.#state}. Must be in building-retrieval state.`,
|
|
959
1055
|
);
|
|
960
1056
|
}
|
|
961
1057
|
|
|
962
|
-
|
|
1058
|
+
if (this.#retrievalOps.length === 0) {
|
|
1059
|
+
this.#state = "building-mutation";
|
|
1060
|
+
const emptyResults = [] as unknown as TRetrievalResults;
|
|
1061
|
+
this.#retrievalPhaseResolve?.(emptyResults);
|
|
1062
|
+
return emptyResults;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// Compile retrieval operations using single compiler
|
|
963
1066
|
const retrievalBatch: unknown[] = [];
|
|
964
1067
|
for (const op of this.#retrievalOps) {
|
|
965
1068
|
const compiled = this.#compiler.compileRetrievalOperation(op);
|
|
966
1069
|
if (compiled !== null) {
|
|
967
1070
|
this.#config?.onQuery?.(compiled);
|
|
968
|
-
|
|
969
1071
|
retrievalBatch.push(compiled);
|
|
970
1072
|
}
|
|
971
1073
|
}
|
|
@@ -975,34 +1077,64 @@ export class UnitOfWork<
|
|
|
975
1077
|
return [] as unknown as TRetrievalResults;
|
|
976
1078
|
}
|
|
977
1079
|
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1080
|
+
// Execute all operations together (ideally in same transaction)
|
|
1081
|
+
const rawResults = await this.#executor.executeRetrievalPhase(retrievalBatch);
|
|
1082
|
+
|
|
1083
|
+
// Decode results using single decoder
|
|
1084
|
+
const results = this.#decoder(rawResults, this.#retrievalOps);
|
|
982
1085
|
|
|
983
1086
|
// Store results and transition to mutation phase
|
|
984
1087
|
this.#retrievalResults = results as TRetrievalResults;
|
|
985
1088
|
this.#state = "building-mutation";
|
|
986
1089
|
|
|
1090
|
+
// Resolve the retrieval phase promise to unblock waiting service methods
|
|
1091
|
+
this.#retrievalPhaseResolve?.(this.#retrievalResults);
|
|
1092
|
+
|
|
987
1093
|
return this.#retrievalResults;
|
|
988
1094
|
}
|
|
989
1095
|
|
|
990
1096
|
/**
|
|
991
1097
|
* Add a find operation using a builder callback (retrieval phase only)
|
|
992
1098
|
*/
|
|
993
|
-
find<
|
|
994
|
-
TTableName
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
1099
|
+
find<TTableName extends keyof TSchema["tables"] & string, const TBuilderResult>(
|
|
1100
|
+
tableName: TTableName,
|
|
1101
|
+
builderFn: (
|
|
1102
|
+
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1103
|
+
) => TBuilderResult,
|
|
1104
|
+
): UnitOfWork<
|
|
1105
|
+
TSchema,
|
|
1106
|
+
[
|
|
1107
|
+
...TRetrievalResults,
|
|
1108
|
+
SelectResult<
|
|
1109
|
+
TSchema["tables"][TTableName],
|
|
1110
|
+
ExtractJoinOut<TBuilderResult>,
|
|
1111
|
+
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1112
|
+
>[],
|
|
1113
|
+
],
|
|
1114
|
+
TRawInput
|
|
1115
|
+
>;
|
|
1116
|
+
find<TTableName extends keyof TSchema["tables"] & string>(
|
|
1117
|
+
tableName: TTableName,
|
|
1118
|
+
): UnitOfWork<
|
|
1119
|
+
TSchema,
|
|
1120
|
+
[...TRetrievalResults, SelectResult<TSchema["tables"][TTableName], {}, true>[]],
|
|
1121
|
+
TRawInput
|
|
1122
|
+
>;
|
|
1123
|
+
find<TTableName extends keyof TSchema["tables"] & string, const TBuilderResult>(
|
|
998
1124
|
tableName: TTableName,
|
|
999
1125
|
builderFn?: (
|
|
1000
|
-
// We omit "build" because we don't want to expose it to the user
|
|
1001
1126
|
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1002
|
-
) =>
|
|
1127
|
+
) => TBuilderResult,
|
|
1003
1128
|
): UnitOfWork<
|
|
1004
1129
|
TSchema,
|
|
1005
|
-
[
|
|
1130
|
+
[
|
|
1131
|
+
...TRetrievalResults,
|
|
1132
|
+
SelectResult<
|
|
1133
|
+
TSchema["tables"][TTableName],
|
|
1134
|
+
ExtractJoinOut<TBuilderResult>,
|
|
1135
|
+
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1136
|
+
>[],
|
|
1137
|
+
],
|
|
1006
1138
|
TRawInput
|
|
1007
1139
|
> {
|
|
1008
1140
|
if (this.#state !== "building-retrieval") {
|
|
@@ -1028,6 +1160,7 @@ export class UnitOfWork<
|
|
|
1028
1160
|
|
|
1029
1161
|
this.#retrievalOps.push({
|
|
1030
1162
|
type,
|
|
1163
|
+
schema: this.#schema,
|
|
1031
1164
|
// Safe: we know the table is part of the schema from the find() method
|
|
1032
1165
|
table: table as TSchema["tables"][TTableName],
|
|
1033
1166
|
indexName,
|
|
@@ -1036,31 +1169,31 @@ export class UnitOfWork<
|
|
|
1036
1169
|
options: options as any,
|
|
1037
1170
|
});
|
|
1038
1171
|
|
|
1039
|
-
return
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
TRawInput
|
|
1043
|
-
>;
|
|
1172
|
+
// Safe: return type is correctly specified in the method signature
|
|
1173
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1174
|
+
return this as any;
|
|
1044
1175
|
}
|
|
1045
1176
|
|
|
1046
1177
|
/**
|
|
1047
1178
|
* Add a find operation with cursor metadata (retrieval phase only)
|
|
1048
1179
|
*/
|
|
1049
|
-
findWithCursor<
|
|
1050
|
-
TTableName extends keyof TSchema["tables"] & string,
|
|
1051
|
-
TSelect extends SelectClause<TSchema["tables"][TTableName]> = true,
|
|
1052
|
-
TJoinOut = {},
|
|
1053
|
-
>(
|
|
1180
|
+
findWithCursor<TTableName extends keyof TSchema["tables"] & string, const TBuilderResult>(
|
|
1054
1181
|
tableName: TTableName,
|
|
1055
1182
|
builderFn: (
|
|
1056
1183
|
// We omit "build" because we don't want to expose it to the user
|
|
1057
1184
|
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1058
|
-
) =>
|
|
1185
|
+
) => TBuilderResult,
|
|
1059
1186
|
): UnitOfWork<
|
|
1060
1187
|
TSchema,
|
|
1061
1188
|
[
|
|
1062
1189
|
...TRetrievalResults,
|
|
1063
|
-
CursorResult<
|
|
1190
|
+
CursorResult<
|
|
1191
|
+
SelectResult<
|
|
1192
|
+
TSchema["tables"][TTableName],
|
|
1193
|
+
ExtractJoinOut<TBuilderResult>,
|
|
1194
|
+
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1195
|
+
>
|
|
1196
|
+
>,
|
|
1064
1197
|
],
|
|
1065
1198
|
TRawInput
|
|
1066
1199
|
> {
|
|
@@ -1082,6 +1215,7 @@ export class UnitOfWork<
|
|
|
1082
1215
|
|
|
1083
1216
|
this.#retrievalOps.push({
|
|
1084
1217
|
type,
|
|
1218
|
+
schema: this.#schema,
|
|
1085
1219
|
// Safe: we know the table is part of the schema from the findWithCursor() method
|
|
1086
1220
|
table: table as TSchema["tables"][TTableName],
|
|
1087
1221
|
indexName,
|
|
@@ -1091,14 +1225,9 @@ export class UnitOfWork<
|
|
|
1091
1225
|
withCursor: true,
|
|
1092
1226
|
});
|
|
1093
1227
|
|
|
1094
|
-
return
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
...TRetrievalResults,
|
|
1098
|
-
CursorResult<SelectResult<TSchema["tables"][TTableName], TJoinOut, TSelect>>,
|
|
1099
|
-
],
|
|
1100
|
-
TRawInput
|
|
1101
|
-
>;
|
|
1228
|
+
// Safe: return type is correctly specified in the method signature
|
|
1229
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1230
|
+
return this as any;
|
|
1102
1231
|
}
|
|
1103
1232
|
|
|
1104
1233
|
/**
|
|
@@ -1155,6 +1284,7 @@ export class UnitOfWork<
|
|
|
1155
1284
|
|
|
1156
1285
|
this.#mutationOps.push({
|
|
1157
1286
|
type: "create",
|
|
1287
|
+
schema: this.#schema,
|
|
1158
1288
|
table,
|
|
1159
1289
|
values: updatedValues,
|
|
1160
1290
|
generatedExternalId: externalId,
|
|
@@ -1185,6 +1315,7 @@ export class UnitOfWork<
|
|
|
1185
1315
|
|
|
1186
1316
|
this.#mutationOps.push({
|
|
1187
1317
|
type: "update",
|
|
1318
|
+
schema: this.#schema,
|
|
1188
1319
|
table,
|
|
1189
1320
|
id: opId,
|
|
1190
1321
|
checkVersion,
|
|
@@ -1214,6 +1345,7 @@ export class UnitOfWork<
|
|
|
1214
1345
|
|
|
1215
1346
|
this.#mutationOps.push({
|
|
1216
1347
|
type: "delete",
|
|
1348
|
+
schema: this.#schema,
|
|
1217
1349
|
table,
|
|
1218
1350
|
id: opId,
|
|
1219
1351
|
checkVersion,
|
|
@@ -1229,7 +1361,7 @@ export class UnitOfWork<
|
|
|
1229
1361
|
throw new Error(`Cannot execute mutations from state ${this.#state}.`);
|
|
1230
1362
|
}
|
|
1231
1363
|
|
|
1232
|
-
// Compile mutation operations
|
|
1364
|
+
// Compile mutation operations using single compiler
|
|
1233
1365
|
const mutationBatch: CompiledMutation<unknown>[] = [];
|
|
1234
1366
|
for (const op of this.#mutationOps) {
|
|
1235
1367
|
const compiled = this.#compiler.compileMutationOperation(op);
|
|
@@ -1254,6 +1386,9 @@ export class UnitOfWork<
|
|
|
1254
1386
|
this.#createdInternalIds = result.createdInternalIds;
|
|
1255
1387
|
}
|
|
1256
1388
|
|
|
1389
|
+
// Resolve the mutation phase promise to unblock waiting service methods
|
|
1390
|
+
this.#mutationPhaseResolve?.();
|
|
1391
|
+
|
|
1257
1392
|
return {
|
|
1258
1393
|
success: result.success,
|
|
1259
1394
|
};
|
|
@@ -1262,17 +1397,34 @@ export class UnitOfWork<
|
|
|
1262
1397
|
/**
|
|
1263
1398
|
* Get the retrieval operations (for inspection/debugging)
|
|
1264
1399
|
*/
|
|
1265
|
-
getRetrievalOperations(): ReadonlyArray<RetrievalOperation<
|
|
1400
|
+
getRetrievalOperations(): ReadonlyArray<RetrievalOperation<AnySchema>> {
|
|
1266
1401
|
return this.#retrievalOps;
|
|
1267
1402
|
}
|
|
1268
1403
|
|
|
1269
1404
|
/**
|
|
1270
1405
|
* Get the mutation operations (for inspection/debugging)
|
|
1271
1406
|
*/
|
|
1272
|
-
getMutationOperations(): ReadonlyArray<MutationOperation<
|
|
1407
|
+
getMutationOperations(): ReadonlyArray<MutationOperation<AnySchema>> {
|
|
1273
1408
|
return this.#mutationOps;
|
|
1274
1409
|
}
|
|
1275
1410
|
|
|
1411
|
+
/**
|
|
1412
|
+
* @internal
|
|
1413
|
+
* Add a retrieval operation (used by SchemaView)
|
|
1414
|
+
*/
|
|
1415
|
+
addRetrievalOperation(op: RetrievalOperation<AnySchema>): number {
|
|
1416
|
+
this.#retrievalOps.push(op);
|
|
1417
|
+
return this.#retrievalOps.length - 1;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
/**
|
|
1421
|
+
* @internal
|
|
1422
|
+
* Add a mutation operation (used by SchemaView)
|
|
1423
|
+
*/
|
|
1424
|
+
addMutationOperation(op: MutationOperation<AnySchema>): void {
|
|
1425
|
+
this.#mutationOps.push(op);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1276
1428
|
/**
|
|
1277
1429
|
* Get the IDs of created entities after executeMutations() has been called.
|
|
1278
1430
|
* Returns FragnoId objects with external IDs (always available) and internal IDs
|
|
@@ -1312,7 +1464,7 @@ export class UnitOfWork<
|
|
|
1312
1464
|
* @internal
|
|
1313
1465
|
* Compile the unit of work to executable queries for testing
|
|
1314
1466
|
*/
|
|
1315
|
-
compile<TOutput>(compiler: UOWCompiler<
|
|
1467
|
+
compile<TOutput>(compiler: UOWCompiler<TOutput>): {
|
|
1316
1468
|
name?: string;
|
|
1317
1469
|
retrievalBatch: TOutput[];
|
|
1318
1470
|
mutationBatch: CompiledMutation<TOutput>[];
|
|
@@ -1340,3 +1492,300 @@ export class UnitOfWork<
|
|
|
1340
1492
|
};
|
|
1341
1493
|
}
|
|
1342
1494
|
}
|
|
1495
|
+
|
|
1496
|
+
/**
|
|
1497
|
+
* A lightweight wrapper around a parent UOW that provides type-safe operations for a different schema.
|
|
1498
|
+
* All operations are stored in the parent UOW, but this wrapper ensures the correct schema is used.
|
|
1499
|
+
*/
|
|
1500
|
+
export class UnitOfWorkSchemaView<
|
|
1501
|
+
const TSchema extends AnySchema,
|
|
1502
|
+
const TRetrievalResults extends unknown[] = [],
|
|
1503
|
+
const TRawInput = unknown,
|
|
1504
|
+
> implements IUnitOfWorkBase
|
|
1505
|
+
{
|
|
1506
|
+
#schema: TSchema;
|
|
1507
|
+
#namespace?: string;
|
|
1508
|
+
#parent: UnitOfWork<AnySchema, unknown[], TRawInput>;
|
|
1509
|
+
#operationIndices: number[] = [];
|
|
1510
|
+
|
|
1511
|
+
constructor(
|
|
1512
|
+
schema: TSchema,
|
|
1513
|
+
namespace: string | undefined,
|
|
1514
|
+
parent: UnitOfWork<AnySchema, unknown[], TRawInput>,
|
|
1515
|
+
) {
|
|
1516
|
+
this.#schema = schema;
|
|
1517
|
+
this.#namespace = namespace;
|
|
1518
|
+
this.#parent = parent;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
get $results(): Prettify<TRetrievalResults> {
|
|
1522
|
+
throw new Error("type only");
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
get schema(): TSchema {
|
|
1526
|
+
return this.#schema;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
get name(): string | undefined {
|
|
1530
|
+
return this.#parent.name;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
get state() {
|
|
1534
|
+
return this.#parent.state;
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
get retrievalPhase(): Promise<TRetrievalResults> {
|
|
1538
|
+
// Filter parent's results to only include operations from this view
|
|
1539
|
+
return this.#parent.retrievalPhase.then((allResults) => {
|
|
1540
|
+
const filteredResults = this.#operationIndices.map((index) => allResults[index]);
|
|
1541
|
+
return filteredResults as TRetrievalResults;
|
|
1542
|
+
});
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
get mutationPhase(): Promise<void> {
|
|
1546
|
+
return this.#parent.mutationPhase;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
getRetrievalOperations() {
|
|
1550
|
+
return this.#parent.getRetrievalOperations();
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
getMutationOperations() {
|
|
1554
|
+
return this.#parent.getMutationOperations();
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
getCreatedIds() {
|
|
1558
|
+
return this.#parent.getCreatedIds();
|
|
1559
|
+
}
|
|
1560
|
+
|
|
1561
|
+
async executeRetrieve(): Promise<unknown[]> {
|
|
1562
|
+
return this.#parent.executeRetrieve();
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
async executeMutations(): Promise<{ success: boolean }> {
|
|
1566
|
+
return this.#parent.executeMutations();
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
find<TTableName extends keyof TSchema["tables"] & string, const TBuilderResult>(
|
|
1570
|
+
tableName: TTableName,
|
|
1571
|
+
builderFn: (
|
|
1572
|
+
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1573
|
+
) => TBuilderResult,
|
|
1574
|
+
): UnitOfWorkSchemaView<
|
|
1575
|
+
TSchema,
|
|
1576
|
+
[
|
|
1577
|
+
...TRetrievalResults,
|
|
1578
|
+
SelectResult<
|
|
1579
|
+
TSchema["tables"][TTableName],
|
|
1580
|
+
ExtractJoinOut<TBuilderResult>,
|
|
1581
|
+
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1582
|
+
>[],
|
|
1583
|
+
],
|
|
1584
|
+
TRawInput
|
|
1585
|
+
>;
|
|
1586
|
+
find<TTableName extends keyof TSchema["tables"] & string>(
|
|
1587
|
+
tableName: TTableName,
|
|
1588
|
+
): UnitOfWorkSchemaView<
|
|
1589
|
+
TSchema,
|
|
1590
|
+
[...TRetrievalResults, SelectResult<TSchema["tables"][TTableName], {}, true>[]],
|
|
1591
|
+
TRawInput
|
|
1592
|
+
>;
|
|
1593
|
+
find<TTableName extends keyof TSchema["tables"] & string, const TBuilderResult>(
|
|
1594
|
+
tableName: TTableName,
|
|
1595
|
+
builderFn?: (
|
|
1596
|
+
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1597
|
+
) => TBuilderResult,
|
|
1598
|
+
): UnitOfWorkSchemaView<
|
|
1599
|
+
TSchema,
|
|
1600
|
+
[
|
|
1601
|
+
...TRetrievalResults,
|
|
1602
|
+
SelectResult<
|
|
1603
|
+
TSchema["tables"][TTableName],
|
|
1604
|
+
ExtractJoinOut<TBuilderResult>,
|
|
1605
|
+
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1606
|
+
>[],
|
|
1607
|
+
],
|
|
1608
|
+
TRawInput
|
|
1609
|
+
> {
|
|
1610
|
+
const table = this.#schema.tables[tableName];
|
|
1611
|
+
if (!table) {
|
|
1612
|
+
throw new Error(`Table ${tableName} not found in schema`);
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
const builder = new FindBuilder(tableName, table as TSchema["tables"][TTableName]);
|
|
1616
|
+
if (builderFn) {
|
|
1617
|
+
builderFn(builder);
|
|
1618
|
+
} else {
|
|
1619
|
+
builder.whereIndex("primary");
|
|
1620
|
+
}
|
|
1621
|
+
const { indexName, options, type } = builder.build();
|
|
1622
|
+
|
|
1623
|
+
const operationIndex = this.#parent.addRetrievalOperation({
|
|
1624
|
+
type,
|
|
1625
|
+
schema: this.#schema,
|
|
1626
|
+
namespace: this.#namespace,
|
|
1627
|
+
table: table as TSchema["tables"][TTableName],
|
|
1628
|
+
indexName,
|
|
1629
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1630
|
+
options: options as any,
|
|
1631
|
+
});
|
|
1632
|
+
|
|
1633
|
+
// Track which operation index belongs to this view
|
|
1634
|
+
this.#operationIndices.push(operationIndex);
|
|
1635
|
+
|
|
1636
|
+
// Safe: return type is correctly specified in the method signature
|
|
1637
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1638
|
+
return this as any;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
findWithCursor<TTableName extends keyof TSchema["tables"] & string, const TBuilderResult>(
|
|
1642
|
+
tableName: TTableName,
|
|
1643
|
+
builderFn: (
|
|
1644
|
+
builder: Omit<FindBuilder<TSchema["tables"][TTableName]>, "build">,
|
|
1645
|
+
) => TBuilderResult,
|
|
1646
|
+
): UnitOfWorkSchemaView<
|
|
1647
|
+
TSchema,
|
|
1648
|
+
[
|
|
1649
|
+
...TRetrievalResults,
|
|
1650
|
+
CursorResult<
|
|
1651
|
+
SelectResult<
|
|
1652
|
+
TSchema["tables"][TTableName],
|
|
1653
|
+
ExtractJoinOut<TBuilderResult>,
|
|
1654
|
+
Extract<ExtractSelect<TBuilderResult>, SelectClause<TSchema["tables"][TTableName]>>
|
|
1655
|
+
>
|
|
1656
|
+
>,
|
|
1657
|
+
],
|
|
1658
|
+
TRawInput
|
|
1659
|
+
> {
|
|
1660
|
+
const table = this.#schema.tables[tableName];
|
|
1661
|
+
if (!table) {
|
|
1662
|
+
throw new Error(`Table ${tableName} not found in schema`);
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
const builder = new FindBuilder(tableName, table as TSchema["tables"][TTableName]);
|
|
1666
|
+
builderFn(builder);
|
|
1667
|
+
const { indexName, options, type } = builder.build();
|
|
1668
|
+
|
|
1669
|
+
const operationIndex = this.#parent.addRetrievalOperation({
|
|
1670
|
+
type,
|
|
1671
|
+
schema: this.#schema,
|
|
1672
|
+
namespace: this.#namespace,
|
|
1673
|
+
table: table as TSchema["tables"][TTableName],
|
|
1674
|
+
indexName,
|
|
1675
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1676
|
+
options: options as any,
|
|
1677
|
+
withCursor: true,
|
|
1678
|
+
});
|
|
1679
|
+
|
|
1680
|
+
// Track which operation index belongs to this view
|
|
1681
|
+
this.#operationIndices.push(operationIndex);
|
|
1682
|
+
|
|
1683
|
+
// Safe: return type is correctly specified in the method signature
|
|
1684
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1685
|
+
return this as any;
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
create<TableName extends keyof TSchema["tables"] & string>(
|
|
1689
|
+
tableName: TableName,
|
|
1690
|
+
values: TableToInsertValues<TSchema["tables"][TableName]>,
|
|
1691
|
+
): FragnoId {
|
|
1692
|
+
const tableSchema = this.#schema.tables[tableName];
|
|
1693
|
+
if (!tableSchema) {
|
|
1694
|
+
throw new Error(`Table ${tableName} not found in schema`);
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
const idColumn = tableSchema.getIdColumn();
|
|
1698
|
+
let externalId: string;
|
|
1699
|
+
let updatedValues = values;
|
|
1700
|
+
|
|
1701
|
+
// Check if ID value is provided in values
|
|
1702
|
+
const providedIdValue = (values as Record<string, unknown>)[idColumn.ormName];
|
|
1703
|
+
|
|
1704
|
+
if (providedIdValue !== undefined) {
|
|
1705
|
+
// Extract string from FragnoId or use string directly
|
|
1706
|
+
if (
|
|
1707
|
+
typeof providedIdValue === "object" &&
|
|
1708
|
+
providedIdValue !== null &&
|
|
1709
|
+
"externalId" in providedIdValue
|
|
1710
|
+
) {
|
|
1711
|
+
externalId = (providedIdValue as FragnoId).externalId;
|
|
1712
|
+
} else {
|
|
1713
|
+
externalId = providedIdValue as string;
|
|
1714
|
+
}
|
|
1715
|
+
} else {
|
|
1716
|
+
// Generate using the column's default configuration
|
|
1717
|
+
const generated = idColumn.generateDefaultValue();
|
|
1718
|
+
if (generated === undefined) {
|
|
1719
|
+
throw new Error(
|
|
1720
|
+
`No ID value provided and ID column ${idColumn.ormName} has no default generator`,
|
|
1721
|
+
);
|
|
1722
|
+
}
|
|
1723
|
+
externalId = generated as string;
|
|
1724
|
+
|
|
1725
|
+
// Add the generated ID to values so it's used in the insert
|
|
1726
|
+
updatedValues = {
|
|
1727
|
+
...values,
|
|
1728
|
+
[idColumn.ormName]: externalId,
|
|
1729
|
+
} as TableToInsertValues<TSchema["tables"][TableName]>;
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
this.#parent.addMutationOperation({
|
|
1733
|
+
type: "create",
|
|
1734
|
+
schema: this.#schema,
|
|
1735
|
+
namespace: this.#namespace,
|
|
1736
|
+
table: tableName,
|
|
1737
|
+
values: updatedValues,
|
|
1738
|
+
generatedExternalId: externalId,
|
|
1739
|
+
});
|
|
1740
|
+
|
|
1741
|
+
return FragnoId.fromExternal(externalId, 0);
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
update<TableName extends keyof TSchema["tables"] & string>(
|
|
1745
|
+
tableName: TableName,
|
|
1746
|
+
id: FragnoId | string,
|
|
1747
|
+
builderFn: (
|
|
1748
|
+
builder: Omit<UpdateBuilder<TSchema["tables"][TableName]>, "build">,
|
|
1749
|
+
) => Omit<UpdateBuilder<TSchema["tables"][TableName]>, "build"> | void,
|
|
1750
|
+
): void {
|
|
1751
|
+
const builder = new UpdateBuilder<TSchema["tables"][TableName]>(tableName, id);
|
|
1752
|
+
builderFn(builder);
|
|
1753
|
+
const { id: opId, checkVersion, set } = builder.build();
|
|
1754
|
+
|
|
1755
|
+
this.#parent.addMutationOperation({
|
|
1756
|
+
type: "update",
|
|
1757
|
+
schema: this.#schema,
|
|
1758
|
+
namespace: this.#namespace,
|
|
1759
|
+
table: tableName,
|
|
1760
|
+
id: opId,
|
|
1761
|
+
checkVersion,
|
|
1762
|
+
set,
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1765
|
+
|
|
1766
|
+
delete<TableName extends keyof TSchema["tables"] & string>(
|
|
1767
|
+
tableName: TableName,
|
|
1768
|
+
id: FragnoId | string,
|
|
1769
|
+
builderFn?: (builder: Omit<DeleteBuilder, "build">) => Omit<DeleteBuilder, "build"> | void,
|
|
1770
|
+
): void {
|
|
1771
|
+
const builder = new DeleteBuilder(tableName, id);
|
|
1772
|
+
builderFn?.(builder);
|
|
1773
|
+
const { id: opId, checkVersion } = builder.build();
|
|
1774
|
+
|
|
1775
|
+
this.#parent.addMutationOperation({
|
|
1776
|
+
type: "delete",
|
|
1777
|
+
schema: this.#schema,
|
|
1778
|
+
namespace: this.#namespace,
|
|
1779
|
+
table: tableName,
|
|
1780
|
+
id: opId,
|
|
1781
|
+
checkVersion,
|
|
1782
|
+
});
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
forSchema<TOtherSchema extends AnySchema>(
|
|
1786
|
+
schema: TOtherSchema,
|
|
1787
|
+
): UnitOfWorkSchemaView<TOtherSchema, [], TRawInput> {
|
|
1788
|
+
// Delegate to the parent's forSchema to create a new view
|
|
1789
|
+
return this.#parent.forSchema(schema);
|
|
1790
|
+
}
|
|
1791
|
+
}
|