@proofkit/fmodata 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -0
- package/dist/esm/client/base-table.d.ts +13 -0
- package/dist/esm/client/base-table.js +19 -0
- package/dist/esm/client/base-table.js.map +1 -0
- package/dist/esm/client/database.d.ts +49 -0
- package/dist/esm/client/database.js +90 -0
- package/dist/esm/client/database.js.map +1 -0
- package/dist/esm/client/delete-builder.d.ts +61 -0
- package/dist/esm/client/delete-builder.js +121 -0
- package/dist/esm/client/delete-builder.js.map +1 -0
- package/dist/esm/client/entity-set.d.ts +43 -0
- package/dist/esm/client/entity-set.js +120 -0
- package/dist/esm/client/entity-set.js.map +1 -0
- package/dist/esm/client/filemaker-odata.d.ts +26 -0
- package/dist/esm/client/filemaker-odata.js +85 -0
- package/dist/esm/client/filemaker-odata.js.map +1 -0
- package/dist/esm/client/insert-builder.d.ts +23 -0
- package/dist/esm/client/insert-builder.js +69 -0
- package/dist/esm/client/insert-builder.js.map +1 -0
- package/dist/esm/client/query-builder.d.ts +94 -0
- package/dist/esm/client/query-builder.js +649 -0
- package/dist/esm/client/query-builder.js.map +1 -0
- package/dist/esm/client/record-builder.d.ts +43 -0
- package/dist/esm/client/record-builder.js +121 -0
- package/dist/esm/client/record-builder.js.map +1 -0
- package/dist/esm/client/table-occurrence.d.ts +25 -0
- package/dist/esm/client/table-occurrence.js +47 -0
- package/dist/esm/client/table-occurrence.js.map +1 -0
- package/dist/esm/client/update-builder.d.ts +69 -0
- package/dist/esm/client/update-builder.js +134 -0
- package/dist/esm/client/update-builder.js.map +1 -0
- package/dist/esm/filter-types.d.ts +76 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/types.d.ts +67 -0
- package/dist/esm/validation.d.ts +41 -0
- package/dist/esm/validation.js +270 -0
- package/dist/esm/validation.js.map +1 -0
- package/package.json +68 -0
- package/src/client/base-table.ts +25 -0
- package/src/client/database.ts +177 -0
- package/src/client/delete-builder.ts +193 -0
- package/src/client/entity-set.ts +310 -0
- package/src/client/filemaker-odata.ts +119 -0
- package/src/client/insert-builder.ts +93 -0
- package/src/client/query-builder.ts +1076 -0
- package/src/client/record-builder.ts +240 -0
- package/src/client/table-occurrence.ts +100 -0
- package/src/client/update-builder.ts +212 -0
- package/src/filter-types.ts +97 -0
- package/src/index.ts +17 -0
- package/src/types.ts +123 -0
- package/src/validation.ts +397 -0
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# @proofkit/fmodata
|
|
2
|
+
|
|
3
|
+
FileMaker OData API client
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @proofkit/fmodata
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { createODataClient } from "@proofkit/fmodata";
|
|
15
|
+
|
|
16
|
+
// Usage example coming soon
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Development
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Install dependencies
|
|
23
|
+
pnpm install
|
|
24
|
+
|
|
25
|
+
# Build the package
|
|
26
|
+
pnpm build
|
|
27
|
+
|
|
28
|
+
# Run tests
|
|
29
|
+
pnpm test
|
|
30
|
+
|
|
31
|
+
# Watch mode for development
|
|
32
|
+
pnpm dev
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## License
|
|
36
|
+
|
|
37
|
+
MIT
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
2
|
+
export declare class BaseTable<Schema extends Record<string, StandardSchemaV1> = any, IdField extends keyof Schema | undefined = undefined, InsertRequired extends readonly (keyof Schema)[] = readonly [], UpdateRequired extends readonly (keyof Schema)[] = readonly []> {
|
|
3
|
+
readonly schema: Schema;
|
|
4
|
+
readonly idField?: IdField;
|
|
5
|
+
readonly insertRequired?: InsertRequired;
|
|
6
|
+
readonly updateRequired?: UpdateRequired;
|
|
7
|
+
constructor(config: {
|
|
8
|
+
schema: Schema;
|
|
9
|
+
idField?: IdField;
|
|
10
|
+
insertRequired?: InsertRequired;
|
|
11
|
+
updateRequired?: UpdateRequired;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
class BaseTable {
|
|
5
|
+
constructor(config) {
|
|
6
|
+
__publicField(this, "schema");
|
|
7
|
+
__publicField(this, "idField");
|
|
8
|
+
__publicField(this, "insertRequired");
|
|
9
|
+
__publicField(this, "updateRequired");
|
|
10
|
+
this.schema = config.schema;
|
|
11
|
+
this.idField = config.idField;
|
|
12
|
+
this.insertRequired = config.insertRequired;
|
|
13
|
+
this.updateRequired = config.updateRequired;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export {
|
|
17
|
+
BaseTable
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=base-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base-table.js","sources":["../../../src/client/base-table.ts"],"sourcesContent":["import { StandardSchemaV1 } from \"@standard-schema/spec\";\n\nexport class BaseTable<\n Schema extends Record<string, StandardSchemaV1> = any,\n IdField extends keyof Schema | undefined = undefined,\n InsertRequired extends readonly (keyof Schema)[] = readonly [],\n UpdateRequired extends readonly (keyof Schema)[] = readonly [],\n> {\n public readonly schema: Schema;\n public readonly idField?: IdField;\n public readonly insertRequired?: InsertRequired;\n public readonly updateRequired?: UpdateRequired;\n\n constructor(config: {\n schema: Schema;\n idField?: IdField;\n insertRequired?: InsertRequired;\n updateRequired?: UpdateRequired;\n }) {\n this.schema = config.schema;\n this.idField = config.idField;\n this.insertRequired = config.insertRequired;\n this.updateRequired = config.updateRequired;\n }\n}\n"],"names":[],"mappings":";;;AAEO,MAAM,UAKX;AAAA,EAMA,YAAY,QAKT;AAVa;AACA;AACA;AACA;AAQd,SAAK,SAAS,OAAO;AACrB,SAAK,UAAU,OAAO;AACtB,SAAK,iBAAiB,OAAO;AAC7B,SAAK,iBAAiB,OAAO;AAAA,EAAA;AAEjC;"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
import { StandardSchemaV1 } from '@standard-schema/spec';
|
|
3
|
+
import { ExecutionContext } from '../types.js';
|
|
4
|
+
import { BaseTable } from './base-table.js';
|
|
5
|
+
import { TableOccurrence } from './table-occurrence.js';
|
|
6
|
+
import { EntitySet } from './entity-set.js';
|
|
7
|
+
type ExtractSchemaFromOccurrence<O> = O extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<infer S, any> ? S : never : never;
|
|
8
|
+
type FindOccurrenceByName<Occurrences extends readonly TableOccurrence<any, any, any, any>[], Name extends string> = Occurrences extends readonly [
|
|
9
|
+
infer First,
|
|
10
|
+
...infer Rest extends readonly TableOccurrence<any, any, any, any>[]
|
|
11
|
+
] ? First extends TableOccurrence<any, any, any, any> ? First["name"] extends Name ? First : FindOccurrenceByName<Rest, Name> : never : never;
|
|
12
|
+
type ExtractOccurrenceNames<Occurrences extends readonly TableOccurrence<any, any, any, any>[]> = Occurrences extends readonly [] ? string : Occurrences[number]["name"];
|
|
13
|
+
export declare class Database<Occurrences extends readonly TableOccurrence<any, any, any, any>[] = readonly []> {
|
|
14
|
+
private readonly databaseName;
|
|
15
|
+
private readonly context;
|
|
16
|
+
private occurrenceMap;
|
|
17
|
+
constructor(databaseName: string, context: ExecutionContext, config?: {
|
|
18
|
+
occurrences?: Occurrences;
|
|
19
|
+
});
|
|
20
|
+
from<Name extends ExtractOccurrenceNames<Occurrences> | (string & {})>(name: Name): Occurrences extends readonly [] ? EntitySet<Record<string, z.ZodTypeAny>, undefined> : Name extends ExtractOccurrenceNames<Occurrences> ? EntitySet<ExtractSchemaFromOccurrence<FindOccurrenceByName<Occurrences, Name>>, FindOccurrenceByName<Occurrences, Name>> : EntitySet<Record<string, z.ZodTypeAny>, undefined>;
|
|
21
|
+
getMetadata(): Promise<unknown>;
|
|
22
|
+
/**
|
|
23
|
+
* Lists all available tables (entity sets) in this database.
|
|
24
|
+
* @returns Promise resolving to an array of table names
|
|
25
|
+
*/
|
|
26
|
+
listTableNames(): Promise<string[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Executes a FileMaker script.
|
|
29
|
+
* @param scriptName - The name of the script to execute (must be valid according to OData rules)
|
|
30
|
+
* @param options - Optional script parameter and result schema
|
|
31
|
+
* @returns Promise resolving to script execution result
|
|
32
|
+
*/
|
|
33
|
+
runScript<ResultSchema extends StandardSchemaV1<string, any> = never>(scriptName: string, options?: {
|
|
34
|
+
scriptParam?: string | number | Record<string, any>;
|
|
35
|
+
resultSchema?: ResultSchema;
|
|
36
|
+
}): Promise<[
|
|
37
|
+
ResultSchema
|
|
38
|
+
] extends [never] ? {
|
|
39
|
+
resultCode: number;
|
|
40
|
+
result?: string;
|
|
41
|
+
} : ResultSchema extends StandardSchemaV1<string, infer Output> ? {
|
|
42
|
+
resultCode: number;
|
|
43
|
+
result: Output;
|
|
44
|
+
} : {
|
|
45
|
+
resultCode: number;
|
|
46
|
+
result?: string;
|
|
47
|
+
}>;
|
|
48
|
+
}
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { EntitySet } from "./entity-set.js";
|
|
5
|
+
class Database {
|
|
6
|
+
constructor(databaseName, context, config) {
|
|
7
|
+
__publicField(this, "occurrenceMap");
|
|
8
|
+
this.databaseName = databaseName;
|
|
9
|
+
this.context = context;
|
|
10
|
+
this.occurrenceMap = /* @__PURE__ */ new Map();
|
|
11
|
+
if (config == null ? void 0 : config.occurrences) {
|
|
12
|
+
for (const occ of config.occurrences) {
|
|
13
|
+
this.occurrenceMap.set(occ.name, occ);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
from(name) {
|
|
18
|
+
const occurrence = this.occurrenceMap.get(name);
|
|
19
|
+
if (occurrence) {
|
|
20
|
+
return EntitySet.create({
|
|
21
|
+
occurrence,
|
|
22
|
+
tableName: name,
|
|
23
|
+
databaseName: this.databaseName,
|
|
24
|
+
context: this.context
|
|
25
|
+
});
|
|
26
|
+
} else {
|
|
27
|
+
return new EntitySet({
|
|
28
|
+
tableName: name,
|
|
29
|
+
databaseName: this.databaseName,
|
|
30
|
+
context: this.context
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// Example method showing how to use the request method
|
|
35
|
+
async getMetadata() {
|
|
36
|
+
return this.context._makeRequest(`/${this.databaseName}/$metadata`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Lists all available tables (entity sets) in this database.
|
|
40
|
+
* @returns Promise resolving to an array of table names
|
|
41
|
+
*/
|
|
42
|
+
async listTableNames() {
|
|
43
|
+
const response = await this.context._makeRequest(
|
|
44
|
+
`/${this.databaseName}`
|
|
45
|
+
);
|
|
46
|
+
if (response.value && Array.isArray(response.value)) {
|
|
47
|
+
return response.value.map((item) => item.name);
|
|
48
|
+
}
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Executes a FileMaker script.
|
|
53
|
+
* @param scriptName - The name of the script to execute (must be valid according to OData rules)
|
|
54
|
+
* @param options - Optional script parameter and result schema
|
|
55
|
+
* @returns Promise resolving to script execution result
|
|
56
|
+
*/
|
|
57
|
+
async runScript(scriptName, options) {
|
|
58
|
+
const body = {};
|
|
59
|
+
if ((options == null ? void 0 : options.scriptParam) !== void 0) {
|
|
60
|
+
body.scriptParameterValue = options.scriptParam;
|
|
61
|
+
}
|
|
62
|
+
const response = await this.context._makeRequest(`/${this.databaseName}/Script.${scriptName}`, {
|
|
63
|
+
method: "POST",
|
|
64
|
+
body: Object.keys(body).length > 0 ? JSON.stringify(body) : void 0
|
|
65
|
+
});
|
|
66
|
+
if ((options == null ? void 0 : options.resultSchema) && response.scriptResult !== void 0) {
|
|
67
|
+
const validationResult = options.resultSchema["~standard"].validate(
|
|
68
|
+
response.scriptResult.resultParameter
|
|
69
|
+
);
|
|
70
|
+
const result = validationResult instanceof Promise ? await validationResult : validationResult;
|
|
71
|
+
if (result.issues) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
`Script result validation failed: ${JSON.stringify(result.issues)}`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
resultCode: response.scriptResult.code,
|
|
78
|
+
result: result.value
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
resultCode: response.scriptResult.code,
|
|
83
|
+
result: response.scriptResult.resultParameter
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export {
|
|
88
|
+
Database
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sources":["../../../src/client/database.ts"],"sourcesContent":["import { z } from \"zod/v4\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { ExecutionContext } from \"../types\";\nimport type { BaseTable } from \"./base-table\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport { EntitySet } from \"./entity-set\";\n\n// Helper type to extract schema from a TableOccurrence\ntype ExtractSchemaFromOccurrence<O> =\n O extends TableOccurrence<infer BT, any, any, any>\n ? BT extends BaseTable<infer S, any>\n ? S\n : never\n : never;\n\n// Helper type to find an occurrence by name in the occurrences tuple\ntype FindOccurrenceByName<\n Occurrences extends readonly TableOccurrence<any, any, any, any>[],\n Name extends string,\n> = Occurrences extends readonly [\n infer First,\n ...infer Rest extends readonly TableOccurrence<any, any, any, any>[],\n]\n ? First extends TableOccurrence<any, any, any, any>\n ? First[\"name\"] extends Name\n ? First\n : FindOccurrenceByName<Rest, Name>\n : never\n : never;\n\n// Helper type to extract all occurrence names from the tuple\ntype ExtractOccurrenceNames<\n Occurrences extends readonly TableOccurrence<any, any, any, any>[],\n> = Occurrences extends readonly []\n ? string // If no occurrences, allow any string\n : Occurrences[number][\"name\"]; // Otherwise, extract union of names\n\nexport class Database<\n Occurrences extends readonly TableOccurrence<\n any,\n any,\n any,\n any\n >[] = readonly [],\n> {\n private occurrenceMap: Map<string, TableOccurrence<any, any, any, any>>;\n\n constructor(\n private readonly databaseName: string,\n private readonly context: ExecutionContext,\n config?: { occurrences?: Occurrences },\n ) {\n this.occurrenceMap = new Map();\n if (config?.occurrences) {\n for (const occ of config.occurrences) {\n this.occurrenceMap.set(occ.name, occ);\n }\n }\n }\n\n from<Name extends ExtractOccurrenceNames<Occurrences> | (string & {})>(\n name: Name,\n ): Occurrences extends readonly []\n ? EntitySet<Record<string, z.ZodTypeAny>, undefined>\n : Name extends ExtractOccurrenceNames<Occurrences>\n ? EntitySet<\n ExtractSchemaFromOccurrence<FindOccurrenceByName<Occurrences, Name>>,\n FindOccurrenceByName<Occurrences, Name>\n >\n : EntitySet<Record<string, z.ZodTypeAny>, undefined> {\n const occurrence = this.occurrenceMap.get(name as string);\n\n if (occurrence) {\n // Use EntitySet.create to preserve types better\n type OccType = FindOccurrenceByName<Occurrences, Name>;\n type SchemaType = ExtractSchemaFromOccurrence<OccType>;\n\n return EntitySet.create<SchemaType, OccType>({\n occurrence: occurrence as any,\n tableName: name as string,\n databaseName: this.databaseName,\n context: this.context,\n }) as any;\n } else {\n // Return untyped EntitySet for dynamic table access\n return new EntitySet<Record<string, z.ZodTypeAny>, undefined>({\n tableName: name as string,\n databaseName: this.databaseName,\n context: this.context,\n }) as any;\n }\n }\n\n // Example method showing how to use the request method\n async getMetadata() {\n return this.context._makeRequest(`/${this.databaseName}/$metadata`);\n }\n\n /**\n * Lists all available tables (entity sets) in this database.\n * @returns Promise resolving to an array of table names\n */\n async listTableNames(): Promise<string[]> {\n const response = (await this.context._makeRequest(\n `/${this.databaseName}`,\n )) as {\n value?: Array<{ name: string }>;\n };\n if (response.value && Array.isArray(response.value)) {\n return response.value.map((item) => item.name);\n }\n return [];\n }\n\n /**\n * Executes a FileMaker script.\n * @param scriptName - The name of the script to execute (must be valid according to OData rules)\n * @param options - Optional script parameter and result schema\n * @returns Promise resolving to script execution result\n */\n async runScript<ResultSchema extends StandardSchemaV1<string, any> = never>(\n scriptName: string,\n options?: {\n scriptParam?: string | number | Record<string, any>;\n resultSchema?: ResultSchema;\n },\n ): Promise<\n [ResultSchema] extends [never]\n ? { resultCode: number; result?: string }\n : ResultSchema extends StandardSchemaV1<string, infer Output>\n ? { resultCode: number; result: Output }\n : { resultCode: number; result?: string }\n > {\n const body: { scriptParameterValue?: unknown } = {};\n if (options?.scriptParam !== undefined) {\n body.scriptParameterValue = options.scriptParam;\n }\n\n const response = await this.context._makeRequest<{\n scriptResult: {\n code: number;\n resultParameter?: string;\n };\n }>(`/${this.databaseName}/Script.${scriptName}`, {\n method: \"POST\",\n body: Object.keys(body).length > 0 ? JSON.stringify(body) : undefined,\n });\n\n // If resultSchema is provided, validate the result through it\n if (options?.resultSchema && response.scriptResult !== undefined) {\n const validationResult = options.resultSchema[\"~standard\"].validate(\n response.scriptResult.resultParameter,\n );\n // Handle both sync and async validation\n const result =\n validationResult instanceof Promise\n ? await validationResult\n : validationResult;\n\n if (result.issues) {\n throw new Error(\n `Script result validation failed: ${JSON.stringify(result.issues)}`,\n );\n }\n\n return {\n resultCode: response.scriptResult.code,\n result: result.value,\n } as any;\n }\n\n return {\n resultCode: response.scriptResult.code,\n result: response.scriptResult.resultParameter,\n } as any;\n }\n}\n"],"names":[],"mappings":";;;;AAqCO,MAAM,SAOX;AAAA,EAGA,YACmB,cACA,SACjB,QACA;AANM;AAGW,SAAA,eAAA;AACA,SAAA,UAAA;AAGZ,SAAA,oCAAoB,IAAI;AAC7B,QAAI,iCAAQ,aAAa;AACZ,iBAAA,OAAO,OAAO,aAAa;AACpC,aAAK,cAAc,IAAI,IAAI,MAAM,GAAG;AAAA,MAAA;AAAA,IACtC;AAAA,EACF;AAAA,EAGF,KACE,MAQuD;AACvD,UAAM,aAAa,KAAK,cAAc,IAAI,IAAc;AAExD,QAAI,YAAY;AAKd,aAAO,UAAU,OAA4B;AAAA,QAC3C;AAAA,QACA,WAAW;AAAA,QACX,cAAc,KAAK;AAAA,QACnB,SAAS,KAAK;AAAA,MAAA,CACf;AAAA,IAAA,OACI;AAEL,aAAO,IAAI,UAAmD;AAAA,QAC5D,WAAW;AAAA,QACX,cAAc,KAAK;AAAA,QACnB,SAAS,KAAK;AAAA,MAAA,CACf;AAAA,IAAA;AAAA,EACH;AAAA;AAAA,EAIF,MAAM,cAAc;AAClB,WAAO,KAAK,QAAQ,aAAa,IAAI,KAAK,YAAY,YAAY;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOpE,MAAM,iBAAoC;AAClC,UAAA,WAAY,MAAM,KAAK,QAAQ;AAAA,MACnC,IAAI,KAAK,YAAY;AAAA,IACvB;AAGA,QAAI,SAAS,SAAS,MAAM,QAAQ,SAAS,KAAK,GAAG;AACnD,aAAO,SAAS,MAAM,IAAI,CAAC,SAAS,KAAK,IAAI;AAAA,IAAA;AAE/C,WAAO,CAAC;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASV,MAAM,UACJ,YACA,SAUA;AACA,UAAM,OAA2C,CAAC;AAC9C,SAAA,mCAAS,iBAAgB,QAAW;AACtC,WAAK,uBAAuB,QAAQ;AAAA,IAAA;AAGhC,UAAA,WAAW,MAAM,KAAK,QAAQ,aAKjC,IAAI,KAAK,YAAY,WAAW,UAAU,IAAI;AAAA,MAC/C,QAAQ;AAAA,MACR,MAAM,OAAO,KAAK,IAAI,EAAE,SAAS,IAAI,KAAK,UAAU,IAAI,IAAI;AAAA,IAAA,CAC7D;AAGD,SAAI,mCAAS,iBAAgB,SAAS,iBAAiB,QAAW;AAChE,YAAM,mBAAmB,QAAQ,aAAa,WAAW,EAAE;AAAA,QACzD,SAAS,aAAa;AAAA,MACxB;AAEA,YAAM,SACJ,4BAA4B,UACxB,MAAM,mBACN;AAEN,UAAI,OAAO,QAAQ;AACjB,cAAM,IAAI;AAAA,UACR,oCAAoC,KAAK,UAAU,OAAO,MAAM,CAAC;AAAA,QACnE;AAAA,MAAA;AAGK,aAAA;AAAA,QACL,YAAY,SAAS,aAAa;AAAA,QAClC,QAAQ,OAAO;AAAA,MACjB;AAAA,IAAA;AAGK,WAAA;AAAA,MACL,YAAY,SAAS,aAAa;AAAA,MAClC,QAAQ,SAAS,aAAa;AAAA,IAChC;AAAA,EAAA;AAEJ;"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ExecutionContext, ExecutableBuilder, Result, WithSystemFields } from '../types.js';
|
|
2
|
+
import { TableOccurrence } from './table-occurrence.js';
|
|
3
|
+
import { QueryBuilder } from './query-builder.js';
|
|
4
|
+
import { FFetchOptions } from '@fetchkit/ffetch';
|
|
5
|
+
/**
|
|
6
|
+
* Initial delete builder returned from EntitySet.delete()
|
|
7
|
+
* Requires calling .byId() or .where() before .execute() is available
|
|
8
|
+
*/
|
|
9
|
+
export declare class DeleteBuilder<T extends Record<string, any>> {
|
|
10
|
+
private tableName;
|
|
11
|
+
private databaseName;
|
|
12
|
+
private context;
|
|
13
|
+
private occurrence?;
|
|
14
|
+
constructor(config: {
|
|
15
|
+
occurrence?: TableOccurrence<any, any, any, any>;
|
|
16
|
+
tableName: string;
|
|
17
|
+
databaseName: string;
|
|
18
|
+
context: ExecutionContext;
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Delete a single record by ID
|
|
22
|
+
*/
|
|
23
|
+
byId(id: string | number): ExecutableDeleteBuilder<T>;
|
|
24
|
+
/**
|
|
25
|
+
* Delete records matching a filter query
|
|
26
|
+
* @param fn Callback that receives a QueryBuilder for building the filter
|
|
27
|
+
*/
|
|
28
|
+
where(fn: (q: QueryBuilder<WithSystemFields<T>>) => QueryBuilder<WithSystemFields<T>>): ExecutableDeleteBuilder<T>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Executable delete builder - has execute() method
|
|
32
|
+
* Returned after calling .byId() or .where()
|
|
33
|
+
*/
|
|
34
|
+
export declare class ExecutableDeleteBuilder<T extends Record<string, any>> implements ExecutableBuilder<{
|
|
35
|
+
deletedCount: number;
|
|
36
|
+
}> {
|
|
37
|
+
private tableName;
|
|
38
|
+
private databaseName;
|
|
39
|
+
private context;
|
|
40
|
+
private occurrence?;
|
|
41
|
+
private mode;
|
|
42
|
+
private recordId?;
|
|
43
|
+
private queryBuilder?;
|
|
44
|
+
constructor(config: {
|
|
45
|
+
occurrence?: TableOccurrence<any, any, any, any>;
|
|
46
|
+
tableName: string;
|
|
47
|
+
databaseName: string;
|
|
48
|
+
context: ExecutionContext;
|
|
49
|
+
mode: "byId" | "byFilter";
|
|
50
|
+
recordId?: string | number;
|
|
51
|
+
queryBuilder?: QueryBuilder<any>;
|
|
52
|
+
});
|
|
53
|
+
execute(options?: RequestInit & FFetchOptions): Promise<Result<{
|
|
54
|
+
deletedCount: number;
|
|
55
|
+
}>>;
|
|
56
|
+
getRequestConfig(): {
|
|
57
|
+
method: string;
|
|
58
|
+
url: string;
|
|
59
|
+
body?: any;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { QueryBuilder } from "./query-builder.js";
|
|
5
|
+
class DeleteBuilder {
|
|
6
|
+
constructor(config) {
|
|
7
|
+
__publicField(this, "tableName");
|
|
8
|
+
__publicField(this, "databaseName");
|
|
9
|
+
__publicField(this, "context");
|
|
10
|
+
__publicField(this, "occurrence");
|
|
11
|
+
this.occurrence = config.occurrence;
|
|
12
|
+
this.tableName = config.tableName;
|
|
13
|
+
this.databaseName = config.databaseName;
|
|
14
|
+
this.context = config.context;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Delete a single record by ID
|
|
18
|
+
*/
|
|
19
|
+
byId(id) {
|
|
20
|
+
return new ExecutableDeleteBuilder({
|
|
21
|
+
occurrence: this.occurrence,
|
|
22
|
+
tableName: this.tableName,
|
|
23
|
+
databaseName: this.databaseName,
|
|
24
|
+
context: this.context,
|
|
25
|
+
mode: "byId",
|
|
26
|
+
recordId: id
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Delete records matching a filter query
|
|
31
|
+
* @param fn Callback that receives a QueryBuilder for building the filter
|
|
32
|
+
*/
|
|
33
|
+
where(fn) {
|
|
34
|
+
const queryBuilder = new QueryBuilder({
|
|
35
|
+
occurrence: void 0,
|
|
36
|
+
tableName: this.tableName,
|
|
37
|
+
databaseName: this.databaseName,
|
|
38
|
+
context: this.context
|
|
39
|
+
});
|
|
40
|
+
const configuredBuilder = fn(queryBuilder);
|
|
41
|
+
return new ExecutableDeleteBuilder({
|
|
42
|
+
occurrence: this.occurrence,
|
|
43
|
+
tableName: this.tableName,
|
|
44
|
+
databaseName: this.databaseName,
|
|
45
|
+
context: this.context,
|
|
46
|
+
mode: "byFilter",
|
|
47
|
+
queryBuilder: configuredBuilder
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
class ExecutableDeleteBuilder {
|
|
52
|
+
constructor(config) {
|
|
53
|
+
__publicField(this, "tableName");
|
|
54
|
+
__publicField(this, "databaseName");
|
|
55
|
+
__publicField(this, "context");
|
|
56
|
+
__publicField(this, "occurrence");
|
|
57
|
+
__publicField(this, "mode");
|
|
58
|
+
__publicField(this, "recordId");
|
|
59
|
+
__publicField(this, "queryBuilder");
|
|
60
|
+
this.occurrence = config.occurrence;
|
|
61
|
+
this.tableName = config.tableName;
|
|
62
|
+
this.databaseName = config.databaseName;
|
|
63
|
+
this.context = config.context;
|
|
64
|
+
this.mode = config.mode;
|
|
65
|
+
this.recordId = config.recordId;
|
|
66
|
+
this.queryBuilder = config.queryBuilder;
|
|
67
|
+
}
|
|
68
|
+
async execute(options) {
|
|
69
|
+
try {
|
|
70
|
+
let url;
|
|
71
|
+
if (this.mode === "byId") {
|
|
72
|
+
url = `/${this.databaseName}/${this.tableName}('${this.recordId}')`;
|
|
73
|
+
} else {
|
|
74
|
+
if (!this.queryBuilder) {
|
|
75
|
+
throw new Error("Query builder is required for filter-based delete");
|
|
76
|
+
}
|
|
77
|
+
const queryString = this.queryBuilder.getQueryString();
|
|
78
|
+
const queryParams = queryString.startsWith(`/${this.tableName}`) ? queryString.slice(`/${this.tableName}`.length) : queryString;
|
|
79
|
+
url = `/${this.databaseName}/${this.tableName}${queryParams}`;
|
|
80
|
+
}
|
|
81
|
+
const response = await this.context._makeRequest(url, {
|
|
82
|
+
method: "DELETE",
|
|
83
|
+
...options
|
|
84
|
+
});
|
|
85
|
+
let deletedCount = 0;
|
|
86
|
+
if (typeof response === "number") {
|
|
87
|
+
deletedCount = response;
|
|
88
|
+
} else if (response && typeof response === "object") {
|
|
89
|
+
deletedCount = response.deletedCount || 0;
|
|
90
|
+
}
|
|
91
|
+
return { data: { deletedCount }, error: void 0 };
|
|
92
|
+
} catch (error) {
|
|
93
|
+
return {
|
|
94
|
+
data: void 0,
|
|
95
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
getRequestConfig() {
|
|
100
|
+
let url;
|
|
101
|
+
if (this.mode === "byId") {
|
|
102
|
+
url = `/${this.databaseName}/${this.tableName}('${this.recordId}')`;
|
|
103
|
+
} else {
|
|
104
|
+
if (!this.queryBuilder) {
|
|
105
|
+
throw new Error("Query builder is required for filter-based delete");
|
|
106
|
+
}
|
|
107
|
+
const queryString = this.queryBuilder.getQueryString();
|
|
108
|
+
const queryParams = queryString.startsWith(`/${this.tableName}`) ? queryString.slice(`/${this.tableName}`.length) : queryString;
|
|
109
|
+
url = `/${this.databaseName}/${this.tableName}${queryParams}`;
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
method: "DELETE",
|
|
113
|
+
url
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export {
|
|
118
|
+
DeleteBuilder,
|
|
119
|
+
ExecutableDeleteBuilder
|
|
120
|
+
};
|
|
121
|
+
//# sourceMappingURL=delete-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete-builder.js","sources":["../../../src/client/delete-builder.ts"],"sourcesContent":["import type {\n ExecutionContext,\n ExecutableBuilder,\n Result,\n WithSystemFields,\n} from \"../types\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport { QueryBuilder } from \"./query-builder\";\nimport { type FFetchOptions } from \"@fetchkit/ffetch\";\nimport buildQuery from \"odata-query\";\n\n/**\n * Initial delete builder returned from EntitySet.delete()\n * Requires calling .byId() or .where() before .execute() is available\n */\nexport class DeleteBuilder<T extends Record<string, any>> {\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private occurrence?: TableOccurrence<any, any, any, any>;\n\n constructor(config: {\n occurrence?: TableOccurrence<any, any, any, any>;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n }) {\n this.occurrence = config.occurrence;\n this.tableName = config.tableName;\n this.databaseName = config.databaseName;\n this.context = config.context;\n }\n\n /**\n * Delete a single record by ID\n */\n byId(id: string | number): ExecutableDeleteBuilder<T> {\n return new ExecutableDeleteBuilder<T>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n mode: \"byId\",\n recordId: id,\n });\n }\n\n /**\n * Delete records matching a filter query\n * @param fn Callback that receives a QueryBuilder for building the filter\n */\n where(\n fn: (\n q: QueryBuilder<WithSystemFields<T>>,\n ) => QueryBuilder<WithSystemFields<T>>,\n ): ExecutableDeleteBuilder<T> {\n // Create a QueryBuilder for the user to configure\n const queryBuilder = new QueryBuilder<\n WithSystemFields<T>,\n keyof WithSystemFields<T>,\n false,\n false,\n undefined\n >({\n occurrence: undefined,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n });\n\n // Let the user configure it\n const configuredBuilder = fn(queryBuilder);\n\n return new ExecutableDeleteBuilder<T>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n mode: \"byFilter\",\n queryBuilder: configuredBuilder,\n });\n }\n}\n\n/**\n * Executable delete builder - has execute() method\n * Returned after calling .byId() or .where()\n */\nexport class ExecutableDeleteBuilder<T extends Record<string, any>>\n implements ExecutableBuilder<{ deletedCount: number }>\n{\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private occurrence?: TableOccurrence<any, any, any, any>;\n private mode: \"byId\" | \"byFilter\";\n private recordId?: string | number;\n private queryBuilder?: QueryBuilder<any>;\n\n constructor(config: {\n occurrence?: TableOccurrence<any, any, any, any>;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n mode: \"byId\" | \"byFilter\";\n recordId?: string | number;\n queryBuilder?: QueryBuilder<any>;\n }) {\n this.occurrence = config.occurrence;\n this.tableName = config.tableName;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.mode = config.mode;\n this.recordId = config.recordId;\n this.queryBuilder = config.queryBuilder;\n }\n\n async execute(\n options?: RequestInit & FFetchOptions,\n ): Promise<Result<{ deletedCount: number }>> {\n try {\n let url: string;\n\n if (this.mode === \"byId\") {\n // Delete single record by ID: DELETE /{database}/{table}('id')\n url = `/${this.databaseName}/${this.tableName}('${this.recordId}')`;\n } else {\n // Delete by filter: DELETE /{database}/{table}?$filter=...\n if (!this.queryBuilder) {\n throw new Error(\"Query builder is required for filter-based delete\");\n }\n\n // Get the query string from the configured QueryBuilder\n const queryString = this.queryBuilder.getQueryString();\n // Remove the leading \"/\" from the query string as we'll build our own URL\n const queryParams = queryString.startsWith(`/${this.tableName}`)\n ? queryString.slice(`/${this.tableName}`.length)\n : queryString;\n\n url = `/${this.databaseName}/${this.tableName}${queryParams}`;\n }\n\n // Make DELETE request\n const response = await this.context._makeRequest(url, {\n method: \"DELETE\",\n ...options,\n });\n\n // OData returns 204 No Content with fmodata.affected_rows header\n // The _makeRequest should handle extracting the header value\n // For now, we'll check if response contains the count\n let deletedCount = 0;\n\n if (typeof response === \"number\") {\n deletedCount = response;\n } else if (response && typeof response === \"object\") {\n // Check if the response has a count property (fallback)\n deletedCount = (response as any).deletedCount || 0;\n }\n\n return { data: { deletedCount }, error: undefined };\n } catch (error) {\n return {\n data: undefined,\n error: error instanceof Error ? error : new Error(String(error)),\n };\n }\n }\n\n getRequestConfig(): { method: string; url: string; body?: any } {\n let url: string;\n\n if (this.mode === \"byId\") {\n url = `/${this.databaseName}/${this.tableName}('${this.recordId}')`;\n } else {\n if (!this.queryBuilder) {\n throw new Error(\"Query builder is required for filter-based delete\");\n }\n\n const queryString = this.queryBuilder.getQueryString();\n const queryParams = queryString.startsWith(`/${this.tableName}`)\n ? queryString.slice(`/${this.tableName}`.length)\n : queryString;\n\n url = `/${this.databaseName}/${this.tableName}${queryParams}`;\n }\n\n return {\n method: \"DELETE\",\n url,\n };\n }\n}\n"],"names":[],"mappings":";;;;AAeO,MAAM,cAA6C;AAAA,EAMxD,YAAY,QAKT;AAVK;AACA;AACA;AACA;AAQN,SAAK,aAAa,OAAO;AACzB,SAAK,YAAY,OAAO;AACxB,SAAK,eAAe,OAAO;AAC3B,SAAK,UAAU,OAAO;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMxB,KAAK,IAAiD;AACpD,WAAO,IAAI,wBAA2B;AAAA,MACpC,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,MAAM;AAAA,MACN,UAAU;AAAA,IAAA,CACX;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOH,MACE,IAG4B;AAEtB,UAAA,eAAe,IAAI,aAMvB;AAAA,MACA,YAAY;AAAA,MACZ,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAAA,CACf;AAGK,UAAA,oBAAoB,GAAG,YAAY;AAEzC,WAAO,IAAI,wBAA2B;AAAA,MACpC,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,MAAM;AAAA,MACN,cAAc;AAAA,IAAA,CACf;AAAA,EAAA;AAEL;AAMO,MAAM,wBAEb;AAAA,EASE,YAAY,QAQT;AAhBK;AACA;AACA;AACA;AACA;AACA;AACA;AAWN,SAAK,aAAa,OAAO;AACzB,SAAK,YAAY,OAAO;AACxB,SAAK,eAAe,OAAO;AAC3B,SAAK,UAAU,OAAO;AACtB,SAAK,OAAO,OAAO;AACnB,SAAK,WAAW,OAAO;AACvB,SAAK,eAAe,OAAO;AAAA,EAAA;AAAA,EAG7B,MAAM,QACJ,SAC2C;AACvC,QAAA;AACE,UAAA;AAEA,UAAA,KAAK,SAAS,QAAQ;AAElB,cAAA,IAAI,KAAK,YAAY,IAAI,KAAK,SAAS,KAAK,KAAK,QAAQ;AAAA,MAAA,OAC1D;AAED,YAAA,CAAC,KAAK,cAAc;AAChB,gBAAA,IAAI,MAAM,mDAAmD;AAAA,QAAA;AAI/D,cAAA,cAAc,KAAK,aAAa,eAAe;AAErD,cAAM,cAAc,YAAY,WAAW,IAAI,KAAK,SAAS,EAAE,IAC3D,YAAY,MAAM,IAAI,KAAK,SAAS,GAAG,MAAM,IAC7C;AAEJ,cAAM,IAAI,KAAK,YAAY,IAAI,KAAK,SAAS,GAAG,WAAW;AAAA,MAAA;AAI7D,YAAM,WAAW,MAAM,KAAK,QAAQ,aAAa,KAAK;AAAA,QACpD,QAAQ;AAAA,QACR,GAAG;AAAA,MAAA,CACJ;AAKD,UAAI,eAAe;AAEf,UAAA,OAAO,aAAa,UAAU;AACjB,uBAAA;AAAA,MACN,WAAA,YAAY,OAAO,aAAa,UAAU;AAEnD,uBAAgB,SAAiB,gBAAgB;AAAA,MAAA;AAGnD,aAAO,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,OAAU;AAAA,aAC3C,OAAO;AACP,aAAA;AAAA,QACL,MAAM;AAAA,QACN,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,MACjE;AAAA,IAAA;AAAA,EACF;AAAA,EAGF,mBAAgE;AAC1D,QAAA;AAEA,QAAA,KAAK,SAAS,QAAQ;AAClB,YAAA,IAAI,KAAK,YAAY,IAAI,KAAK,SAAS,KAAK,KAAK,QAAQ;AAAA,IAAA,OAC1D;AACD,UAAA,CAAC,KAAK,cAAc;AAChB,cAAA,IAAI,MAAM,mDAAmD;AAAA,MAAA;AAG/D,YAAA,cAAc,KAAK,aAAa,eAAe;AACrD,YAAM,cAAc,YAAY,WAAW,IAAI,KAAK,SAAS,EAAE,IAC3D,YAAY,MAAM,IAAI,KAAK,SAAS,GAAG,MAAM,IAC7C;AAEJ,YAAM,IAAI,KAAK,YAAY,IAAI,KAAK,SAAS,GAAG,WAAW;AAAA,IAAA;AAGtD,WAAA;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,IACF;AAAA,EAAA;AAEJ;"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
import { ExecutionContext, InferSchemaType, InsertData, UpdateData } from '../types.js';
|
|
3
|
+
import { BaseTable } from './base-table.js';
|
|
4
|
+
import { TableOccurrence } from './table-occurrence.js';
|
|
5
|
+
import { QueryBuilder } from './query-builder.js';
|
|
6
|
+
import { RecordBuilder } from './record-builder.js';
|
|
7
|
+
import { InsertBuilder } from './insert-builder.js';
|
|
8
|
+
import { DeleteBuilder } from './delete-builder.js';
|
|
9
|
+
import { UpdateBuilder } from './update-builder.js';
|
|
10
|
+
type ExtractNavigationNames<O extends TableOccurrence<any, any, any, any> | undefined> = O extends TableOccurrence<any, any, infer Nav, any> ? Nav extends Record<string, any> ? keyof Nav & string : never : never;
|
|
11
|
+
type ExtractSchemaFromOccurrence<O> = O extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<infer S, any> ? S : never : never;
|
|
12
|
+
type ExtractDefaultSelect<O> = O extends TableOccurrence<infer BT, any, any, infer DefSelect> ? BT extends BaseTable<infer S, any> ? DefSelect extends "all" ? keyof S : DefSelect extends "schema" ? keyof S : DefSelect extends readonly (infer K)[] ? K & keyof S : keyof S : never : never;
|
|
13
|
+
type ResolveNavigationItem<T> = T extends () => infer R ? R : T;
|
|
14
|
+
type FindNavigationTarget<O extends TableOccurrence<any, any, any, any> | undefined, Name extends string> = O extends TableOccurrence<any, any, infer Nav, any> ? Nav extends Record<string, any> ? Name extends keyof Nav ? ResolveNavigationItem<Nav[Name]> : TableOccurrence<BaseTable<Record<string, z.ZodTypeAny>, any>, any, any, any> : TableOccurrence<BaseTable<Record<string, z.ZodTypeAny>, any>, any, any, any> : TableOccurrence<BaseTable<Record<string, z.ZodTypeAny>, any>, any, any, any>;
|
|
15
|
+
export declare class EntitySet<Schema extends Record<string, z.ZodType> = any, Occ extends TableOccurrence<any, any, any, any> | undefined = undefined> {
|
|
16
|
+
private occurrence?;
|
|
17
|
+
private tableName;
|
|
18
|
+
private databaseName;
|
|
19
|
+
private context;
|
|
20
|
+
private isNavigateFromEntitySet?;
|
|
21
|
+
private navigateRelation?;
|
|
22
|
+
private navigateSourceTableName?;
|
|
23
|
+
constructor(config: {
|
|
24
|
+
occurrence?: Occ;
|
|
25
|
+
tableName: string;
|
|
26
|
+
databaseName: string;
|
|
27
|
+
context: ExecutionContext;
|
|
28
|
+
});
|
|
29
|
+
static create<OccurrenceSchema extends Record<string, z.ZodType>, Occ extends TableOccurrence<BaseTable<OccurrenceSchema, any>, any, any, any> | undefined = undefined>(config: {
|
|
30
|
+
occurrence?: Occ;
|
|
31
|
+
tableName: string;
|
|
32
|
+
databaseName: string;
|
|
33
|
+
context: ExecutionContext;
|
|
34
|
+
}): EntitySet<OccurrenceSchema, Occ>;
|
|
35
|
+
list(): QueryBuilder<InferSchemaType<Schema>, Occ extends TableOccurrence<any, any, any, any> ? ExtractDefaultSelect<Occ> : keyof InferSchemaType<Schema>, false, false, Occ>;
|
|
36
|
+
get(id: string | number): RecordBuilder<InferSchemaType<Schema>, false, keyof InferSchemaType<Schema>, Occ>;
|
|
37
|
+
insert(data: Occ extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<any, any, any, any> ? InsertData<BT> : Partial<InferSchemaType<Schema>> : Partial<InferSchemaType<Schema>>): InsertBuilder<InferSchemaType<Schema>, Occ>;
|
|
38
|
+
update(data: Occ extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<any, any, any, any> ? UpdateData<BT> : Partial<InferSchemaType<Schema>> : Partial<InferSchemaType<Schema>>): UpdateBuilder<InferSchemaType<Schema>, Occ extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<any, any, any, any> ? BT : BaseTable<Schema, any, any, any> : BaseTable<Schema, any, any, any>>;
|
|
39
|
+
delete(): DeleteBuilder<InferSchemaType<Schema>>;
|
|
40
|
+
navigate<RelationName extends ExtractNavigationNames<Occ>>(relationName: RelationName): EntitySet<ExtractSchemaFromOccurrence<FindNavigationTarget<Occ, RelationName>> extends Record<string, z.ZodType> ? ExtractSchemaFromOccurrence<FindNavigationTarget<Occ, RelationName>> : Record<string, z.ZodTypeAny>, FindNavigationTarget<Occ, RelationName>>;
|
|
41
|
+
navigate(relationName: string): EntitySet<Record<string, z.ZodTypeAny>, undefined>;
|
|
42
|
+
}
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { QueryBuilder } from "./query-builder.js";
|
|
5
|
+
import { RecordBuilder } from "./record-builder.js";
|
|
6
|
+
import { InsertBuilder } from "./insert-builder.js";
|
|
7
|
+
import { DeleteBuilder } from "./delete-builder.js";
|
|
8
|
+
import { UpdateBuilder } from "./update-builder.js";
|
|
9
|
+
class EntitySet {
|
|
10
|
+
constructor(config) {
|
|
11
|
+
__publicField(this, "occurrence");
|
|
12
|
+
__publicField(this, "tableName");
|
|
13
|
+
__publicField(this, "databaseName");
|
|
14
|
+
__publicField(this, "context");
|
|
15
|
+
__publicField(this, "isNavigateFromEntitySet");
|
|
16
|
+
__publicField(this, "navigateRelation");
|
|
17
|
+
__publicField(this, "navigateSourceTableName");
|
|
18
|
+
this.occurrence = config.occurrence;
|
|
19
|
+
this.tableName = config.tableName;
|
|
20
|
+
this.databaseName = config.databaseName;
|
|
21
|
+
this.context = config.context;
|
|
22
|
+
}
|
|
23
|
+
// Type-only method to help TypeScript infer the schema from occurrence
|
|
24
|
+
static create(config) {
|
|
25
|
+
return new EntitySet({
|
|
26
|
+
occurrence: config.occurrence,
|
|
27
|
+
tableName: config.tableName,
|
|
28
|
+
databaseName: config.databaseName,
|
|
29
|
+
context: config.context
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
list() {
|
|
33
|
+
const builder = new QueryBuilder({
|
|
34
|
+
occurrence: this.occurrence,
|
|
35
|
+
tableName: this.tableName,
|
|
36
|
+
databaseName: this.databaseName,
|
|
37
|
+
context: this.context
|
|
38
|
+
});
|
|
39
|
+
if (this.occurrence) {
|
|
40
|
+
const defaultSelect = this.occurrence.defaultSelect;
|
|
41
|
+
if (defaultSelect === "schema") {
|
|
42
|
+
const schema = this.occurrence.baseTable.schema;
|
|
43
|
+
const fields = Object.keys(schema);
|
|
44
|
+
const uniqueFields = [...new Set(fields)];
|
|
45
|
+
return builder.select(...uniqueFields);
|
|
46
|
+
} else if (Array.isArray(defaultSelect)) {
|
|
47
|
+
const uniqueFields = [
|
|
48
|
+
...new Set(defaultSelect)
|
|
49
|
+
];
|
|
50
|
+
return builder.select(...uniqueFields);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (this.isNavigateFromEntitySet) {
|
|
54
|
+
builder.isNavigate = true;
|
|
55
|
+
builder.navigateRelation = this.navigateRelation;
|
|
56
|
+
builder.navigateSourceTableName = this.navigateSourceTableName;
|
|
57
|
+
}
|
|
58
|
+
return builder;
|
|
59
|
+
}
|
|
60
|
+
get(id) {
|
|
61
|
+
const builder = new RecordBuilder({
|
|
62
|
+
occurrence: this.occurrence,
|
|
63
|
+
tableName: this.tableName,
|
|
64
|
+
databaseName: this.databaseName,
|
|
65
|
+
context: this.context,
|
|
66
|
+
recordId: id
|
|
67
|
+
});
|
|
68
|
+
if (this.isNavigateFromEntitySet) {
|
|
69
|
+
builder.isNavigateFromEntitySet = true;
|
|
70
|
+
builder.navigateRelation = this.navigateRelation;
|
|
71
|
+
builder.navigateSourceTableName = this.navigateSourceTableName;
|
|
72
|
+
}
|
|
73
|
+
return builder;
|
|
74
|
+
}
|
|
75
|
+
insert(data) {
|
|
76
|
+
return new InsertBuilder({
|
|
77
|
+
occurrence: this.occurrence,
|
|
78
|
+
tableName: this.tableName,
|
|
79
|
+
databaseName: this.databaseName,
|
|
80
|
+
context: this.context,
|
|
81
|
+
data
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
update(data) {
|
|
85
|
+
return new UpdateBuilder({
|
|
86
|
+
occurrence: this.occurrence,
|
|
87
|
+
tableName: this.tableName,
|
|
88
|
+
databaseName: this.databaseName,
|
|
89
|
+
context: this.context,
|
|
90
|
+
data
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
delete() {
|
|
94
|
+
return new DeleteBuilder({
|
|
95
|
+
occurrence: this.occurrence,
|
|
96
|
+
tableName: this.tableName,
|
|
97
|
+
databaseName: this.databaseName,
|
|
98
|
+
context: this.context
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
// Implementation
|
|
102
|
+
navigate(relationName) {
|
|
103
|
+
var _a;
|
|
104
|
+
const targetOccurrence = (_a = this.occurrence) == null ? void 0 : _a.navigation[relationName];
|
|
105
|
+
const entitySet = new EntitySet({
|
|
106
|
+
occurrence: targetOccurrence,
|
|
107
|
+
tableName: (targetOccurrence == null ? void 0 : targetOccurrence.name) ?? relationName,
|
|
108
|
+
databaseName: this.databaseName,
|
|
109
|
+
context: this.context
|
|
110
|
+
});
|
|
111
|
+
entitySet.isNavigateFromEntitySet = true;
|
|
112
|
+
entitySet.navigateRelation = relationName;
|
|
113
|
+
entitySet.navigateSourceTableName = this.tableName;
|
|
114
|
+
return entitySet;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export {
|
|
118
|
+
EntitySet
|
|
119
|
+
};
|
|
120
|
+
//# sourceMappingURL=entity-set.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entity-set.js","sources":["../../../src/client/entity-set.ts"],"sourcesContent":["import { z } from \"zod/v4\";\nimport type {\n ExecutionContext,\n InferSchemaType,\n WithSystemFields,\n InsertData,\n UpdateData,\n} from \"../types\";\nimport type { BaseTable } from \"./base-table\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport { QueryBuilder } from \"./query-builder\";\nimport { RecordBuilder } from \"./record-builder\";\nimport { InsertBuilder } from \"./insert-builder\";\nimport { DeleteBuilder } from \"./delete-builder\";\nimport { UpdateBuilder } from \"./update-builder\";\n\n// Helper type to extract navigation relation names from an occurrence\ntype ExtractNavigationNames<\n O extends TableOccurrence<any, any, any, any> | undefined,\n> =\n O extends TableOccurrence<any, any, infer Nav, any>\n ? Nav extends Record<string, any>\n ? keyof Nav & string\n : never\n : never;\n\n// Helper type to extract schema from a TableOccurrence\ntype ExtractSchemaFromOccurrence<O> =\n O extends TableOccurrence<infer BT, any, any, any>\n ? BT extends BaseTable<infer S, any>\n ? S\n : never\n : never;\n\n// Helper type to extract defaultSelect from a TableOccurrence\ntype ExtractDefaultSelect<O> =\n O extends TableOccurrence<infer BT, any, any, infer DefSelect>\n ? BT extends BaseTable<infer S, any>\n ? DefSelect extends \"all\"\n ? keyof S\n : DefSelect extends \"schema\"\n ? keyof S\n : DefSelect extends readonly (infer K)[]\n ? K & keyof S\n : keyof S\n : never\n : never;\n\n// Helper type to resolve a navigation item (handles both direct and lazy-loaded)\ntype ResolveNavigationItem<T> = T extends () => infer R ? R : T;\n\n// Helper type to find target occurrence by relation name\ntype FindNavigationTarget<\n O extends TableOccurrence<any, any, any, any> | undefined,\n Name extends string,\n> =\n O extends TableOccurrence<any, any, infer Nav, any>\n ? Nav extends Record<string, any>\n ? Name extends keyof Nav\n ? ResolveNavigationItem<Nav[Name]>\n : TableOccurrence<\n BaseTable<Record<string, z.ZodTypeAny>, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, z.ZodTypeAny>, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, z.ZodTypeAny>, any>,\n any,\n any,\n any\n >;\n\n// Helper type to get the inferred schema type from a target occurrence\ntype GetTargetSchemaType<\n O extends TableOccurrence<any, any, any, any> | undefined,\n Rel extends string,\n> = [FindNavigationTarget<O, Rel>] extends [\n TableOccurrence<infer BT, any, any, any>,\n]\n ? [BT] extends [BaseTable<infer S, any>]\n ? [S] extends [Record<string, z.ZodType>]\n ? InferSchemaType<S>\n : Record<string, any>\n : Record<string, any>\n : Record<string, any>;\n\nexport class EntitySet<\n Schema extends Record<string, z.ZodType> = any,\n Occ extends TableOccurrence<any, any, any, any> | undefined = undefined,\n> {\n private occurrence?: Occ;\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private isNavigateFromEntitySet?: boolean;\n private navigateRelation?: string;\n private navigateSourceTableName?: string;\n\n constructor(config: {\n occurrence?: Occ;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n }) {\n this.occurrence = config.occurrence;\n this.tableName = config.tableName;\n this.databaseName = config.databaseName;\n this.context = config.context;\n }\n\n // Type-only method to help TypeScript infer the schema from occurrence\n static create<\n OccurrenceSchema extends Record<string, z.ZodType>,\n Occ extends\n | TableOccurrence<BaseTable<OccurrenceSchema, any>, any, any, any>\n | undefined = undefined,\n >(config: {\n occurrence?: Occ;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n }): EntitySet<OccurrenceSchema, Occ> {\n return new EntitySet<OccurrenceSchema, Occ>({\n occurrence: config.occurrence,\n tableName: config.tableName,\n databaseName: config.databaseName,\n context: config.context,\n });\n }\n\n list(): QueryBuilder<\n InferSchemaType<Schema>,\n Occ extends TableOccurrence<any, any, any, any>\n ? ExtractDefaultSelect<Occ>\n : keyof InferSchemaType<Schema>,\n false,\n false,\n Occ\n > {\n const builder = new QueryBuilder<\n InferSchemaType<Schema>,\n Occ extends TableOccurrence<any, any, any, any>\n ? ExtractDefaultSelect<Occ>\n : keyof InferSchemaType<Schema>,\n false,\n false,\n Occ\n >({\n occurrence: this.occurrence as Occ,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n });\n\n // Apply defaultSelect if occurrence exists and select hasn't been called\n if (this.occurrence) {\n const defaultSelect = this.occurrence.defaultSelect;\n\n if (defaultSelect === \"schema\") {\n // Extract field names from schema\n const schema = this.occurrence.baseTable.schema;\n const fields = Object.keys(schema) as (keyof InferSchemaType<Schema>)[];\n // Deduplicate fields (same as select method)\n const uniqueFields = [...new Set(fields)];\n return builder.select(...uniqueFields);\n } else if (Array.isArray(defaultSelect)) {\n // Use the provided field names, deduplicated\n const uniqueFields = [\n ...new Set(defaultSelect),\n ] as (keyof InferSchemaType<Schema>)[];\n return builder.select(...uniqueFields);\n }\n // If defaultSelect is \"all\", no changes needed (current behavior)\n }\n\n // Propagate navigation context if present\n if (this.isNavigateFromEntitySet) {\n (builder as any).isNavigate = true;\n (builder as any).navigateRelation = this.navigateRelation;\n (builder as any).navigateSourceTableName = this.navigateSourceTableName;\n // navigateRecordId is intentionally not set (undefined) to indicate navigation from EntitySet\n }\n return builder;\n }\n\n get(\n id: string | number,\n ): RecordBuilder<\n InferSchemaType<Schema>,\n false,\n keyof InferSchemaType<Schema>,\n Occ\n > {\n const builder = new RecordBuilder<\n InferSchemaType<Schema>,\n false,\n keyof InferSchemaType<Schema>,\n Occ\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n recordId: id,\n });\n // Propagate navigation context if present\n if (this.isNavigateFromEntitySet) {\n (builder as any).isNavigateFromEntitySet = true;\n (builder as any).navigateRelation = this.navigateRelation;\n (builder as any).navigateSourceTableName = this.navigateSourceTableName;\n }\n return builder;\n }\n\n insert(\n data: Occ extends TableOccurrence<infer BT, any, any, any>\n ? BT extends BaseTable<any, any, any, any>\n ? InsertData<BT>\n : Partial<InferSchemaType<Schema>>\n : Partial<InferSchemaType<Schema>>,\n ): InsertBuilder<InferSchemaType<Schema>, Occ> {\n return new InsertBuilder<InferSchemaType<Schema>, Occ>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n data: data as Partial<InferSchemaType<Schema>>,\n });\n }\n\n update(\n data: Occ extends TableOccurrence<infer BT, any, any, any>\n ? BT extends BaseTable<any, any, any, any>\n ? UpdateData<BT>\n : Partial<InferSchemaType<Schema>>\n : Partial<InferSchemaType<Schema>>,\n ): UpdateBuilder<\n InferSchemaType<Schema>,\n Occ extends TableOccurrence<infer BT, any, any, any>\n ? BT extends BaseTable<any, any, any, any>\n ? BT\n : BaseTable<Schema, any, any, any>\n : BaseTable<Schema, any, any, any>\n > {\n return new UpdateBuilder<\n InferSchemaType<Schema>,\n Occ extends TableOccurrence<infer BT, any, any, any>\n ? BT extends BaseTable<any, any, any, any>\n ? BT\n : BaseTable<Schema, any, any, any>\n : BaseTable<Schema, any, any, any>\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n data: data as Partial<InferSchemaType<Schema>>,\n });\n }\n\n delete(): DeleteBuilder<InferSchemaType<Schema>> {\n return new DeleteBuilder<InferSchemaType<Schema>>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n });\n }\n\n // Overload for valid relation names - returns typed EntitySet\n navigate<RelationName extends ExtractNavigationNames<Occ>>(\n relationName: RelationName,\n ): EntitySet<\n ExtractSchemaFromOccurrence<\n FindNavigationTarget<Occ, RelationName>\n > extends Record<string, z.ZodType>\n ? ExtractSchemaFromOccurrence<FindNavigationTarget<Occ, RelationName>>\n : Record<string, z.ZodTypeAny>,\n FindNavigationTarget<Occ, RelationName>\n >;\n // Overload for arbitrary strings - returns generic EntitySet\n navigate(\n relationName: string,\n ): EntitySet<Record<string, z.ZodTypeAny>, undefined>;\n // Implementation\n navigate(relationName: string): EntitySet<any, any> {\n // Use the target occurrence if available, otherwise allow untyped navigation\n // (useful when types might be incomplete)\n const targetOccurrence = this.occurrence?.navigation[relationName];\n const entitySet = new EntitySet<any, any>({\n occurrence: targetOccurrence,\n tableName: targetOccurrence?.name ?? relationName,\n databaseName: this.databaseName,\n context: this.context,\n });\n // Store the navigation info in the EntitySet\n // We'll need to pass this through when creating QueryBuilders\n (entitySet as any).isNavigateFromEntitySet = true;\n (entitySet as any).navigateRelation = relationName;\n (entitySet as any).navigateSourceTableName = this.tableName;\n return entitySet;\n }\n}\n"],"names":[],"mappings":";;;;;;;;AA6FO,MAAM,UAGX;AAAA,EASA,YAAY,QAKT;AAbK;AACA;AACA;AACA;AACA;AACA;AACA;AAQN,SAAK,aAAa,OAAO;AACzB,SAAK,YAAY,OAAO;AACxB,SAAK,eAAe,OAAO;AAC3B,SAAK,UAAU,OAAO;AAAA,EAAA;AAAA;AAAA,EAIxB,OAAO,OAKL,QAKmC;AACnC,WAAO,IAAI,UAAiC;AAAA,MAC1C,YAAY,OAAO;AAAA,MACnB,WAAW,OAAO;AAAA,MAClB,cAAc,OAAO;AAAA,MACrB,SAAS,OAAO;AAAA,IAAA,CACjB;AAAA,EAAA;AAAA,EAGH,OAQE;AACM,UAAA,UAAU,IAAI,aAQlB;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAAA,CACf;AAGD,QAAI,KAAK,YAAY;AACb,YAAA,gBAAgB,KAAK,WAAW;AAEtC,UAAI,kBAAkB,UAAU;AAExB,cAAA,SAAS,KAAK,WAAW,UAAU;AACnC,cAAA,SAAS,OAAO,KAAK,MAAM;AAEjC,cAAM,eAAe,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC;AACjC,eAAA,QAAQ,OAAO,GAAG,YAAY;AAAA,MAC5B,WAAA,MAAM,QAAQ,aAAa,GAAG;AAEvC,cAAM,eAAe;AAAA,UACnB,GAAG,IAAI,IAAI,aAAa;AAAA,QAC1B;AACO,eAAA,QAAQ,OAAO,GAAG,YAAY;AAAA,MAAA;AAAA,IACvC;AAKF,QAAI,KAAK,yBAAyB;AAC/B,cAAgB,aAAa;AAC7B,cAAgB,mBAAmB,KAAK;AACxC,cAAgB,0BAA0B,KAAK;AAAA,IAAA;AAG3C,WAAA;AAAA,EAAA;AAAA,EAGT,IACE,IAMA;AACM,UAAA,UAAU,IAAI,cAKlB;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,UAAU;AAAA,IAAA,CACX;AAED,QAAI,KAAK,yBAAyB;AAC/B,cAAgB,0BAA0B;AAC1C,cAAgB,mBAAmB,KAAK;AACxC,cAAgB,0BAA0B,KAAK;AAAA,IAAA;AAE3C,WAAA;AAAA,EAAA;AAAA,EAGT,OACE,MAK6C;AAC7C,WAAO,IAAI,cAA4C;AAAA,MACrD,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd;AAAA,IAAA,CACD;AAAA,EAAA;AAAA,EAGH,OACE,MAYA;AACA,WAAO,IAAI,cAOT;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd;AAAA,IAAA,CACD;AAAA,EAAA;AAAA,EAGH,SAAiD;AAC/C,WAAO,IAAI,cAAuC;AAAA,MAChD,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAAA,CACf;AAAA,EAAA;AAAA;AAAA,EAmBH,SAAS,cAA2C;;AAGlD,UAAM,oBAAmB,UAAK,eAAL,mBAAiB,WAAW;AAC/C,UAAA,YAAY,IAAI,UAAoB;AAAA,MACxC,YAAY;AAAA,MACZ,YAAW,qDAAkB,SAAQ;AAAA,MACrC,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAAA,CACf;AAGA,cAAkB,0BAA0B;AAC5C,cAAkB,mBAAmB;AACrC,cAAkB,0BAA0B,KAAK;AAC3C,WAAA;AAAA,EAAA;AAEX;"}
|