@proofkit/fmodata 0.1.0-alpha.2 → 0.1.0-alpha.20
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 +1250 -377
- package/dist/esm/client/batch-builder.d.ts +56 -0
- package/dist/esm/client/batch-builder.js +238 -0
- package/dist/esm/client/batch-builder.js.map +1 -0
- package/dist/esm/client/batch-request.d.ts +61 -0
- package/dist/esm/client/batch-request.js +252 -0
- package/dist/esm/client/batch-request.js.map +1 -0
- package/dist/esm/client/builders/default-select.d.ts +10 -0
- package/dist/esm/client/builders/default-select.js +43 -0
- package/dist/esm/client/builders/default-select.js.map +1 -0
- package/dist/esm/client/builders/expand-builder.d.ts +45 -0
- package/dist/esm/client/builders/expand-builder.js +174 -0
- package/dist/esm/client/builders/expand-builder.js.map +1 -0
- package/dist/esm/client/builders/index.d.ts +8 -0
- package/dist/esm/client/builders/query-string-builder.d.ts +18 -0
- package/dist/esm/client/builders/query-string-builder.js +25 -0
- package/dist/esm/client/builders/query-string-builder.js.map +1 -0
- package/dist/esm/client/builders/response-processor.d.ts +43 -0
- package/dist/esm/client/builders/response-processor.js +176 -0
- package/dist/esm/client/builders/response-processor.js.map +1 -0
- package/dist/esm/client/builders/select-mixin.d.ts +32 -0
- package/dist/esm/client/builders/select-mixin.js +30 -0
- package/dist/esm/client/builders/select-mixin.js.map +1 -0
- package/dist/esm/client/builders/select-utils.d.ts +18 -0
- package/dist/esm/client/builders/select-utils.js +23 -0
- package/dist/esm/client/builders/select-utils.js.map +1 -0
- package/dist/esm/client/builders/shared-types.d.ts +40 -0
- package/dist/esm/client/builders/table-utils.d.ts +35 -0
- package/dist/esm/client/builders/table-utils.js +45 -0
- package/dist/esm/client/builders/table-utils.js.map +1 -0
- package/dist/esm/client/database.d.ts +68 -15
- package/dist/esm/client/database.js +88 -34
- package/dist/esm/client/database.js.map +1 -1
- package/dist/esm/client/delete-builder.d.ts +31 -17
- package/dist/esm/client/delete-builder.js +114 -47
- package/dist/esm/client/delete-builder.js.map +1 -1
- package/dist/esm/client/entity-set.d.ts +33 -27
- package/dist/esm/client/entity-set.js +123 -45
- package/dist/esm/client/entity-set.js.map +1 -1
- package/dist/esm/client/error-parser.d.ts +12 -0
- package/dist/esm/client/error-parser.js +30 -0
- package/dist/esm/client/error-parser.js.map +1 -0
- package/dist/esm/client/filemaker-odata.d.ts +44 -6
- package/dist/esm/client/filemaker-odata.js +172 -28
- package/dist/esm/client/filemaker-odata.js.map +1 -1
- package/dist/esm/client/insert-builder.d.ts +39 -9
- package/dist/esm/client/insert-builder.js +265 -36
- package/dist/esm/client/insert-builder.js.map +1 -1
- package/dist/esm/client/query/expand-builder.d.ts +35 -0
- package/dist/esm/client/query/index.d.ts +3 -0
- package/dist/esm/client/query/query-builder.d.ts +139 -0
- package/dist/esm/client/query/query-builder.js +481 -0
- package/dist/esm/client/query/query-builder.js.map +1 -0
- package/dist/esm/client/query/response-processor.d.ts +25 -0
- package/dist/esm/client/query/types.d.ts +77 -0
- package/dist/esm/client/query/url-builder.d.ts +71 -0
- package/dist/esm/client/query/url-builder.js +107 -0
- package/dist/esm/client/query/url-builder.js.map +1 -0
- package/dist/esm/client/query-builder.d.ts +1 -94
- package/dist/esm/client/record-builder.d.ts +107 -22
- package/dist/esm/client/record-builder.js +342 -64
- package/dist/esm/client/record-builder.js.map +1 -1
- package/dist/esm/client/response-processor.d.ts +33 -0
- package/dist/esm/client/sanitize-json.d.ts +35 -0
- package/dist/esm/client/sanitize-json.js +27 -0
- package/dist/esm/client/sanitize-json.js.map +1 -0
- package/dist/esm/client/schema-manager.d.ts +57 -0
- package/dist/esm/client/schema-manager.js +132 -0
- package/dist/esm/client/schema-manager.js.map +1 -0
- package/dist/esm/client/update-builder.d.ts +42 -25
- package/dist/esm/client/update-builder.js +179 -46
- package/dist/esm/client/update-builder.js.map +1 -1
- package/dist/esm/client/webhook-builder.d.ts +126 -0
- package/dist/esm/client/webhook-builder.js +197 -0
- package/dist/esm/client/webhook-builder.js.map +1 -0
- package/dist/esm/errors.d.ts +90 -0
- package/dist/esm/errors.js +180 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.d.ts +12 -4
- package/dist/esm/index.js +59 -6
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/logger.d.ts +47 -0
- package/dist/esm/logger.js +72 -0
- package/dist/esm/logger.js.map +1 -0
- package/dist/esm/logger.test.d.ts +1 -0
- package/dist/esm/orm/column.d.ts +62 -0
- package/dist/esm/orm/column.js +62 -0
- package/dist/esm/orm/column.js.map +1 -0
- package/dist/esm/orm/field-builders.d.ts +164 -0
- package/dist/esm/orm/field-builders.js +168 -0
- package/dist/esm/orm/field-builders.js.map +1 -0
- package/dist/esm/orm/index.d.ts +4 -0
- package/dist/esm/orm/operators.d.ts +175 -0
- package/dist/esm/orm/operators.js +242 -0
- package/dist/esm/orm/operators.js.map +1 -0
- package/dist/esm/orm/table.d.ts +355 -0
- package/dist/esm/orm/table.js +200 -0
- package/dist/esm/orm/table.js.map +1 -0
- package/dist/esm/transform.d.ts +64 -0
- package/dist/esm/transform.js +110 -0
- package/dist/esm/transform.js.map +1 -0
- package/dist/esm/types.d.ts +157 -7
- package/dist/esm/types.js +7 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/validation.d.ts +22 -9
- package/dist/esm/validation.js +195 -50
- package/dist/esm/validation.js.map +1 -1
- package/package.json +19 -4
- package/src/client/batch-builder.ts +334 -0
- package/src/client/batch-request.ts +485 -0
- package/src/client/builders/default-select.ts +80 -0
- package/src/client/builders/expand-builder.ts +245 -0
- package/src/client/builders/index.ts +11 -0
- package/src/client/builders/query-string-builder.ts +49 -0
- package/src/client/builders/response-processor.ts +286 -0
- package/src/client/builders/select-mixin.ts +75 -0
- package/src/client/builders/select-utils.ts +56 -0
- package/src/client/builders/shared-types.ts +42 -0
- package/src/client/builders/table-utils.ts +87 -0
- package/src/client/database.ts +147 -89
- package/src/client/delete-builder.ts +189 -87
- package/src/client/entity-set.ts +316 -205
- package/src/client/error-parser.ts +59 -0
- package/src/client/filemaker-odata.ts +254 -41
- package/src/client/insert-builder.ts +420 -49
- package/src/client/query/expand-builder.ts +164 -0
- package/src/client/query/index.ts +13 -0
- package/src/client/query/query-builder.ts +905 -0
- package/src/client/query/response-processor.ts +236 -0
- package/src/client/query/types.ts +128 -0
- package/src/client/query/url-builder.ts +179 -0
- package/src/client/query-builder.ts +8 -1076
- package/src/client/record-builder.ts +704 -139
- package/src/client/response-processor.ts +89 -0
- package/src/client/sanitize-json.ts +66 -0
- package/src/client/schema-manager.ts +246 -0
- package/src/client/update-builder.ts +318 -90
- package/src/client/webhook-builder.ts +285 -0
- package/src/errors.ts +261 -0
- package/src/index.ts +122 -14
- package/src/logger.test.ts +34 -0
- package/src/logger.ts +140 -0
- package/src/orm/column.ts +106 -0
- package/src/orm/field-builders.ts +318 -0
- package/src/orm/index.ts +60 -0
- package/src/orm/operators.ts +487 -0
- package/src/orm/table.ts +759 -0
- package/src/transform.ts +263 -0
- package/src/types.ts +275 -55
- package/src/validation.ts +255 -55
- package/dist/esm/client/base-table.d.ts +0 -13
- package/dist/esm/client/base-table.js +0 -19
- package/dist/esm/client/base-table.js.map +0 -1
- package/dist/esm/client/query-builder.js +0 -649
- package/dist/esm/client/query-builder.js.map +0 -1
- package/dist/esm/client/table-occurrence.d.ts +0 -25
- package/dist/esm/client/table-occurrence.js +0 -47
- package/dist/esm/client/table-occurrence.js.map +0 -1
- package/dist/esm/filter-types.d.ts +0 -76
- package/src/client/base-table.ts +0 -25
- package/src/client/table-occurrence.ts +0 -100
- package/src/filter-types.ts +0 -97
package/src/client/entity-set.ts
CHANGED
|
@@ -1,310 +1,421 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
InferSchemaType,
|
|
5
|
-
WithSystemFields,
|
|
6
|
-
InsertData,
|
|
7
|
-
UpdateData,
|
|
8
|
-
} from "../types";
|
|
9
|
-
import type { BaseTable } from "./base-table";
|
|
10
|
-
import type { TableOccurrence } from "./table-occurrence";
|
|
11
|
-
import { QueryBuilder } from "./query-builder";
|
|
1
|
+
import type { ExecutionContext } from "../types";
|
|
2
|
+
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
3
|
+
import { QueryBuilder } from "./query/index";
|
|
12
4
|
import { RecordBuilder } from "./record-builder";
|
|
13
5
|
import { InsertBuilder } from "./insert-builder";
|
|
14
6
|
import { DeleteBuilder } from "./delete-builder";
|
|
15
7
|
import { UpdateBuilder } from "./update-builder";
|
|
8
|
+
import { Database } from "./database";
|
|
9
|
+
import type {
|
|
10
|
+
FMTable,
|
|
11
|
+
InferSchemaOutputFromFMTable,
|
|
12
|
+
InsertDataFromFMTable,
|
|
13
|
+
UpdateDataFromFMTable,
|
|
14
|
+
ValidExpandTarget,
|
|
15
|
+
ColumnMap,
|
|
16
|
+
} from "../orm/table";
|
|
17
|
+
import {
|
|
18
|
+
FMTable as FMTableClass,
|
|
19
|
+
getDefaultSelect,
|
|
20
|
+
getTableName,
|
|
21
|
+
getTableColumns,
|
|
22
|
+
getTableSchema,
|
|
23
|
+
} from "../orm/table";
|
|
24
|
+
import type { FieldBuilder } from "../orm/field-builders";
|
|
25
|
+
import { createLogger, InternalLogger } from "../logger";
|
|
16
26
|
|
|
17
|
-
// Helper type to extract
|
|
18
|
-
type
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
O extends TableOccurrence<any, any, infer Nav, any>
|
|
22
|
-
? Nav extends Record<string, any>
|
|
23
|
-
? keyof Nav & string
|
|
24
|
-
: never
|
|
25
|
-
: never;
|
|
26
|
-
|
|
27
|
-
// Helper type to extract schema from a TableOccurrence
|
|
28
|
-
type ExtractSchemaFromOccurrence<O> =
|
|
29
|
-
O extends TableOccurrence<infer BT, any, any, any>
|
|
30
|
-
? BT extends BaseTable<infer S, any>
|
|
31
|
-
? S
|
|
32
|
-
: never
|
|
33
|
-
: never;
|
|
34
|
-
|
|
35
|
-
// Helper type to extract defaultSelect from a TableOccurrence
|
|
27
|
+
// Helper type to extract defaultSelect from an FMTable
|
|
28
|
+
// Since TypeScript can't extract Symbol-indexed properties at the type level,
|
|
29
|
+
// we simplify to return keyof InferSchemaFromFMTable<O> when O is an FMTable.
|
|
30
|
+
// The actual defaultSelect logic is handled at runtime.
|
|
36
31
|
type ExtractDefaultSelect<O> =
|
|
37
|
-
O extends
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
32
|
+
O extends FMTable<any, any> ? keyof InferSchemaOutputFromFMTable<O> : never;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Helper type to extract properly-typed columns from an FMTable.
|
|
36
|
+
* This preserves the specific column types instead of widening to `any`.
|
|
37
|
+
*/
|
|
38
|
+
type ExtractColumnsFromOcc<T> =
|
|
39
|
+
T extends FMTable<infer TFields, infer TName, any>
|
|
40
|
+
? TFields extends Record<string, FieldBuilder<any, any, any, any>>
|
|
41
|
+
? ColumnMap<TFields, TName>
|
|
46
42
|
: never
|
|
47
43
|
: never;
|
|
48
44
|
|
|
49
|
-
// Helper type to resolve a navigation item (handles both direct and lazy-loaded)
|
|
50
|
-
type ResolveNavigationItem<T> = T extends () => infer R ? R : T;
|
|
51
|
-
|
|
52
|
-
// Helper type to find target occurrence by relation name
|
|
53
|
-
type FindNavigationTarget<
|
|
54
|
-
O extends TableOccurrence<any, any, any, any> | undefined,
|
|
55
|
-
Name extends string,
|
|
56
|
-
> =
|
|
57
|
-
O extends TableOccurrence<any, any, infer Nav, any>
|
|
58
|
-
? Nav extends Record<string, any>
|
|
59
|
-
? Name extends keyof Nav
|
|
60
|
-
? ResolveNavigationItem<Nav[Name]>
|
|
61
|
-
: TableOccurrence<
|
|
62
|
-
BaseTable<Record<string, z.ZodTypeAny>, any>,
|
|
63
|
-
any,
|
|
64
|
-
any,
|
|
65
|
-
any
|
|
66
|
-
>
|
|
67
|
-
: TableOccurrence<
|
|
68
|
-
BaseTable<Record<string, z.ZodTypeAny>, any>,
|
|
69
|
-
any,
|
|
70
|
-
any,
|
|
71
|
-
any
|
|
72
|
-
>
|
|
73
|
-
: TableOccurrence<
|
|
74
|
-
BaseTable<Record<string, z.ZodTypeAny>, any>,
|
|
75
|
-
any,
|
|
76
|
-
any,
|
|
77
|
-
any
|
|
78
|
-
>;
|
|
79
|
-
|
|
80
|
-
// Helper type to get the inferred schema type from a target occurrence
|
|
81
|
-
type GetTargetSchemaType<
|
|
82
|
-
O extends TableOccurrence<any, any, any, any> | undefined,
|
|
83
|
-
Rel extends string,
|
|
84
|
-
> = [FindNavigationTarget<O, Rel>] extends [
|
|
85
|
-
TableOccurrence<infer BT, any, any, any>,
|
|
86
|
-
]
|
|
87
|
-
? [BT] extends [BaseTable<infer S, any>]
|
|
88
|
-
? [S] extends [Record<string, z.ZodType>]
|
|
89
|
-
? InferSchemaType<S>
|
|
90
|
-
: Record<string, any>
|
|
91
|
-
: Record<string, any>
|
|
92
|
-
: Record<string, any>;
|
|
93
|
-
|
|
94
45
|
export class EntitySet<
|
|
95
|
-
|
|
96
|
-
|
|
46
|
+
Occ extends FMTable<any, any>,
|
|
47
|
+
DatabaseIncludeSpecialColumns extends boolean = false,
|
|
97
48
|
> {
|
|
98
|
-
private occurrence
|
|
99
|
-
private tableName: string;
|
|
49
|
+
private occurrence: Occ;
|
|
100
50
|
private databaseName: string;
|
|
101
51
|
private context: ExecutionContext;
|
|
52
|
+
private database: Database<DatabaseIncludeSpecialColumns>; // Database instance for accessing occurrences
|
|
102
53
|
private isNavigateFromEntitySet?: boolean;
|
|
103
54
|
private navigateRelation?: string;
|
|
104
55
|
private navigateSourceTableName?: string;
|
|
56
|
+
private navigateBasePath?: string; // Full base path for chained navigations
|
|
57
|
+
private databaseUseEntityIds: boolean;
|
|
58
|
+
private databaseIncludeSpecialColumns: DatabaseIncludeSpecialColumns;
|
|
59
|
+
private logger: InternalLogger;
|
|
105
60
|
|
|
106
61
|
constructor(config: {
|
|
107
|
-
occurrence
|
|
108
|
-
tableName: string;
|
|
62
|
+
occurrence: Occ;
|
|
109
63
|
databaseName: string;
|
|
110
64
|
context: ExecutionContext;
|
|
65
|
+
database?: any;
|
|
111
66
|
}) {
|
|
112
67
|
this.occurrence = config.occurrence;
|
|
113
|
-
this.tableName = config.tableName;
|
|
114
68
|
this.databaseName = config.databaseName;
|
|
115
69
|
this.context = config.context;
|
|
70
|
+
this.database = config.database;
|
|
71
|
+
// Get useEntityIds from database if available, otherwise default to false
|
|
72
|
+
this.databaseUseEntityIds =
|
|
73
|
+
(config.database as any)?._useEntityIds ?? false;
|
|
74
|
+
// Get includeSpecialColumns from database if available, otherwise default to false
|
|
75
|
+
this.databaseIncludeSpecialColumns =
|
|
76
|
+
(config.database as any)?._includeSpecialColumns ?? false;
|
|
77
|
+
this.logger = config.context?._getLogger?.() ?? createLogger();
|
|
116
78
|
}
|
|
117
79
|
|
|
118
|
-
// Type-only method to help TypeScript infer the schema from
|
|
80
|
+
// Type-only method to help TypeScript infer the schema from table
|
|
119
81
|
static create<
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
| TableOccurrence<BaseTable<OccurrenceSchema, any>, any, any, any>
|
|
123
|
-
| undefined = undefined,
|
|
82
|
+
Occ extends FMTable<any, any>,
|
|
83
|
+
DatabaseIncludeSpecialColumns extends boolean = false,
|
|
124
84
|
>(config: {
|
|
125
|
-
occurrence
|
|
126
|
-
tableName: string;
|
|
85
|
+
occurrence: Occ;
|
|
127
86
|
databaseName: string;
|
|
128
87
|
context: ExecutionContext;
|
|
129
|
-
|
|
130
|
-
|
|
88
|
+
database: Database<DatabaseIncludeSpecialColumns>;
|
|
89
|
+
}): EntitySet<Occ, DatabaseIncludeSpecialColumns> {
|
|
90
|
+
return new EntitySet<Occ, DatabaseIncludeSpecialColumns>({
|
|
131
91
|
occurrence: config.occurrence,
|
|
132
|
-
tableName: config.tableName,
|
|
133
92
|
databaseName: config.databaseName,
|
|
134
93
|
context: config.context,
|
|
94
|
+
database: config.database,
|
|
135
95
|
});
|
|
136
96
|
}
|
|
137
97
|
|
|
138
98
|
list(): QueryBuilder<
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
? ExtractDefaultSelect<Occ>
|
|
142
|
-
: keyof InferSchemaType<Schema>,
|
|
99
|
+
Occ,
|
|
100
|
+
keyof InferSchemaOutputFromFMTable<Occ>,
|
|
143
101
|
false,
|
|
144
102
|
false,
|
|
145
|
-
|
|
103
|
+
{},
|
|
104
|
+
DatabaseIncludeSpecialColumns
|
|
146
105
|
> {
|
|
147
106
|
const builder = new QueryBuilder<
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
? ExtractDefaultSelect<Occ>
|
|
151
|
-
: keyof InferSchemaType<Schema>,
|
|
107
|
+
Occ,
|
|
108
|
+
keyof InferSchemaOutputFromFMTable<Occ>,
|
|
152
109
|
false,
|
|
153
110
|
false,
|
|
154
|
-
|
|
111
|
+
{},
|
|
112
|
+
DatabaseIncludeSpecialColumns
|
|
155
113
|
>({
|
|
156
114
|
occurrence: this.occurrence as Occ,
|
|
157
|
-
tableName: this.tableName,
|
|
158
115
|
databaseName: this.databaseName,
|
|
159
116
|
context: this.context,
|
|
117
|
+
databaseUseEntityIds: this.databaseUseEntityIds,
|
|
118
|
+
databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns,
|
|
160
119
|
});
|
|
161
120
|
|
|
162
121
|
// Apply defaultSelect if occurrence exists and select hasn't been called
|
|
163
122
|
if (this.occurrence) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
//
|
|
171
|
-
|
|
172
|
-
return
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
123
|
+
// FMTable - access via helper functions
|
|
124
|
+
const defaultSelectValue = getDefaultSelect(this.occurrence);
|
|
125
|
+
// Schema is stored directly as Partial<Record<keyof TFields, StandardSchemaV1>>
|
|
126
|
+
const schema = getTableSchema(this.occurrence);
|
|
127
|
+
|
|
128
|
+
if (defaultSelectValue === "schema") {
|
|
129
|
+
// Use getTableColumns to get all columns and select them
|
|
130
|
+
// This is equivalent to select(getTableColumns(occurrence))
|
|
131
|
+
// Cast to the declared return type - runtime behavior handles the actual selection
|
|
132
|
+
const allColumns = getTableColumns(
|
|
133
|
+
this.occurrence,
|
|
134
|
+
) as ExtractColumnsFromOcc<Occ>;
|
|
135
|
+
|
|
136
|
+
// Include special columns if enabled at database level
|
|
137
|
+
const systemColumns = this.databaseIncludeSpecialColumns
|
|
138
|
+
? { ROWID: true, ROWMODID: true }
|
|
139
|
+
: undefined;
|
|
140
|
+
|
|
141
|
+
return builder
|
|
142
|
+
.select(allColumns, systemColumns)
|
|
143
|
+
.top(1000) as QueryBuilder<
|
|
144
|
+
Occ,
|
|
145
|
+
keyof InferSchemaOutputFromFMTable<Occ>,
|
|
146
|
+
false,
|
|
147
|
+
false,
|
|
148
|
+
{},
|
|
149
|
+
DatabaseIncludeSpecialColumns,
|
|
150
|
+
typeof systemColumns
|
|
151
|
+
>;
|
|
152
|
+
} else if (typeof defaultSelectValue === "object") {
|
|
153
|
+
// defaultSelectValue is a select object (Record<string, Column>)
|
|
154
|
+
// Cast to the declared return type - runtime behavior handles the actual selection
|
|
155
|
+
return builder
|
|
156
|
+
.select(defaultSelectValue as ExtractColumnsFromOcc<Occ>)
|
|
157
|
+
.top(1000) as QueryBuilder<
|
|
158
|
+
Occ,
|
|
159
|
+
keyof InferSchemaOutputFromFMTable<Occ>,
|
|
160
|
+
false,
|
|
161
|
+
false,
|
|
162
|
+
{},
|
|
163
|
+
DatabaseIncludeSpecialColumns
|
|
164
|
+
>;
|
|
179
165
|
}
|
|
180
166
|
// If defaultSelect is "all", no changes needed (current behavior)
|
|
181
167
|
}
|
|
182
168
|
|
|
183
169
|
// Propagate navigation context if present
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
170
|
+
if (
|
|
171
|
+
this.isNavigateFromEntitySet &&
|
|
172
|
+
this.navigateRelation &&
|
|
173
|
+
this.navigateSourceTableName
|
|
174
|
+
) {
|
|
175
|
+
(builder as any).navigation = {
|
|
176
|
+
relation: this.navigateRelation,
|
|
177
|
+
sourceTableName: this.navigateSourceTableName,
|
|
178
|
+
basePath: this.navigateBasePath,
|
|
179
|
+
// recordId is intentionally not set (undefined) to indicate navigation from EntitySet
|
|
180
|
+
};
|
|
189
181
|
}
|
|
190
|
-
|
|
182
|
+
|
|
183
|
+
// Apply default pagination limit of 1000 records to prevent stack overflow
|
|
184
|
+
// with large datasets. Users can override with .top() if needed.
|
|
185
|
+
return builder.top(1000);
|
|
191
186
|
}
|
|
192
187
|
|
|
193
188
|
get(
|
|
194
189
|
id: string | number,
|
|
195
190
|
): RecordBuilder<
|
|
196
|
-
|
|
191
|
+
Occ,
|
|
197
192
|
false,
|
|
198
|
-
|
|
199
|
-
Occ
|
|
193
|
+
undefined,
|
|
194
|
+
keyof InferSchemaOutputFromFMTable<Occ>,
|
|
195
|
+
{},
|
|
196
|
+
DatabaseIncludeSpecialColumns
|
|
200
197
|
> {
|
|
201
198
|
const builder = new RecordBuilder<
|
|
202
|
-
|
|
199
|
+
Occ,
|
|
203
200
|
false,
|
|
204
|
-
|
|
205
|
-
Occ
|
|
201
|
+
undefined,
|
|
202
|
+
keyof InferSchemaOutputFromFMTable<Occ>,
|
|
203
|
+
{},
|
|
204
|
+
DatabaseIncludeSpecialColumns
|
|
206
205
|
>({
|
|
207
206
|
occurrence: this.occurrence,
|
|
208
|
-
tableName: this.tableName,
|
|
209
207
|
databaseName: this.databaseName,
|
|
210
208
|
context: this.context,
|
|
211
209
|
recordId: id,
|
|
210
|
+
databaseUseEntityIds: this.databaseUseEntityIds,
|
|
211
|
+
databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns,
|
|
212
212
|
});
|
|
213
|
+
|
|
214
|
+
// Apply defaultSelect if occurrence exists
|
|
215
|
+
if (this.occurrence) {
|
|
216
|
+
// FMTable - access via helper functions
|
|
217
|
+
const defaultSelectValue = getDefaultSelect(this.occurrence);
|
|
218
|
+
// Schema is stored directly as Partial<Record<keyof TFields, StandardSchemaV1>>
|
|
219
|
+
const schema = getTableSchema(this.occurrence);
|
|
220
|
+
|
|
221
|
+
if (defaultSelectValue === "schema") {
|
|
222
|
+
// Use getTableColumns to get all columns and select them
|
|
223
|
+
// This is equivalent to select(getTableColumns(occurrence))
|
|
224
|
+
// Use ExtractColumnsFromOcc to preserve the properly-typed column types
|
|
225
|
+
const allColumns = getTableColumns(
|
|
226
|
+
this.occurrence as any,
|
|
227
|
+
) as ExtractColumnsFromOcc<Occ>;
|
|
228
|
+
|
|
229
|
+
// Include special columns if enabled at database level
|
|
230
|
+
const systemColumns = this.databaseIncludeSpecialColumns
|
|
231
|
+
? { ROWID: true, ROWMODID: true }
|
|
232
|
+
: undefined;
|
|
233
|
+
|
|
234
|
+
const selectedBuilder = builder.select(allColumns, systemColumns);
|
|
235
|
+
// Propagate navigation context if present
|
|
236
|
+
if (
|
|
237
|
+
this.isNavigateFromEntitySet &&
|
|
238
|
+
this.navigateRelation &&
|
|
239
|
+
this.navigateSourceTableName
|
|
240
|
+
) {
|
|
241
|
+
(selectedBuilder as any).navigation = {
|
|
242
|
+
relation: this.navigateRelation,
|
|
243
|
+
sourceTableName: this.navigateSourceTableName,
|
|
244
|
+
basePath: this.navigateBasePath,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
return selectedBuilder as any;
|
|
248
|
+
} else if (
|
|
249
|
+
typeof defaultSelectValue === "object" &&
|
|
250
|
+
defaultSelectValue !== null &&
|
|
251
|
+
!Array.isArray(defaultSelectValue)
|
|
252
|
+
) {
|
|
253
|
+
// defaultSelectValue is a select object (Record<string, Column>)
|
|
254
|
+
// Use it directly with select()
|
|
255
|
+
// Use ExtractColumnsFromOcc to preserve the properly-typed column types
|
|
256
|
+
const selectedBuilder = builder.select(
|
|
257
|
+
defaultSelectValue as ExtractColumnsFromOcc<Occ>,
|
|
258
|
+
);
|
|
259
|
+
// Propagate navigation context if present
|
|
260
|
+
if (
|
|
261
|
+
this.isNavigateFromEntitySet &&
|
|
262
|
+
this.navigateRelation &&
|
|
263
|
+
this.navigateSourceTableName
|
|
264
|
+
) {
|
|
265
|
+
(selectedBuilder as any).navigation = {
|
|
266
|
+
relation: this.navigateRelation,
|
|
267
|
+
sourceTableName: this.navigateSourceTableName,
|
|
268
|
+
basePath: this.navigateBasePath,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return selectedBuilder as any;
|
|
272
|
+
}
|
|
273
|
+
// If defaultSelect is "all", no changes needed (current behavior)
|
|
274
|
+
}
|
|
275
|
+
|
|
213
276
|
// Propagate navigation context if present
|
|
214
|
-
if (
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
277
|
+
if (
|
|
278
|
+
this.isNavigateFromEntitySet &&
|
|
279
|
+
this.navigateRelation &&
|
|
280
|
+
this.navigateSourceTableName
|
|
281
|
+
) {
|
|
282
|
+
(builder as any).navigation = {
|
|
283
|
+
relation: this.navigateRelation,
|
|
284
|
+
sourceTableName: this.navigateSourceTableName,
|
|
285
|
+
basePath: this.navigateBasePath,
|
|
286
|
+
};
|
|
218
287
|
}
|
|
219
|
-
return builder;
|
|
288
|
+
return builder as any;
|
|
220
289
|
}
|
|
221
290
|
|
|
291
|
+
// Overload: when returnFullRecord is false
|
|
292
|
+
insert(
|
|
293
|
+
data: InsertDataFromFMTable<Occ>,
|
|
294
|
+
options: { returnFullRecord: false },
|
|
295
|
+
): InsertBuilder<Occ, "minimal">;
|
|
296
|
+
|
|
297
|
+
// Overload: when returnFullRecord is true or omitted (default)
|
|
298
|
+
insert(
|
|
299
|
+
data: InsertDataFromFMTable<Occ>,
|
|
300
|
+
options?: { returnFullRecord?: true },
|
|
301
|
+
): InsertBuilder<Occ, "representation">;
|
|
302
|
+
|
|
303
|
+
// Implementation
|
|
222
304
|
insert(
|
|
223
|
-
data: Occ
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
:
|
|
228
|
-
|
|
229
|
-
return new InsertBuilder<
|
|
305
|
+
data: InsertDataFromFMTable<Occ>,
|
|
306
|
+
options?: { returnFullRecord?: boolean },
|
|
307
|
+
): InsertBuilder<Occ, "minimal" | "representation"> {
|
|
308
|
+
const returnPreference =
|
|
309
|
+
options?.returnFullRecord === false ? "minimal" : "representation";
|
|
310
|
+
|
|
311
|
+
return new InsertBuilder<Occ, typeof returnPreference>({
|
|
230
312
|
occurrence: this.occurrence,
|
|
231
|
-
tableName: this.tableName,
|
|
232
313
|
databaseName: this.databaseName,
|
|
233
314
|
context: this.context,
|
|
234
|
-
data: data as
|
|
315
|
+
data: data as any, // Input type is validated/transformed at runtime
|
|
316
|
+
returnPreference: returnPreference as any,
|
|
317
|
+
databaseUseEntityIds: this.databaseUseEntityIds,
|
|
318
|
+
databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns,
|
|
235
319
|
});
|
|
236
320
|
}
|
|
237
321
|
|
|
322
|
+
// Overload: when returnFullRecord is explicitly true
|
|
238
323
|
update(
|
|
239
|
-
data: Occ
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
: BaseTable<Schema, any, any, any>
|
|
259
|
-
>({
|
|
324
|
+
data: UpdateDataFromFMTable<Occ>,
|
|
325
|
+
options: { returnFullRecord: true },
|
|
326
|
+
): UpdateBuilder<Occ, "representation">;
|
|
327
|
+
|
|
328
|
+
// Overload: when returnFullRecord is false or omitted (default)
|
|
329
|
+
update(
|
|
330
|
+
data: UpdateDataFromFMTable<Occ>,
|
|
331
|
+
options?: { returnFullRecord?: false },
|
|
332
|
+
): UpdateBuilder<Occ, "minimal">;
|
|
333
|
+
|
|
334
|
+
// Implementation
|
|
335
|
+
update(
|
|
336
|
+
data: UpdateDataFromFMTable<Occ>,
|
|
337
|
+
options?: { returnFullRecord?: boolean },
|
|
338
|
+
): UpdateBuilder<Occ, "minimal" | "representation"> {
|
|
339
|
+
const returnPreference =
|
|
340
|
+
options?.returnFullRecord === true ? "representation" : "minimal";
|
|
341
|
+
|
|
342
|
+
return new UpdateBuilder<Occ, typeof returnPreference>({
|
|
260
343
|
occurrence: this.occurrence,
|
|
261
|
-
tableName: this.tableName,
|
|
262
344
|
databaseName: this.databaseName,
|
|
263
345
|
context: this.context,
|
|
264
|
-
data: data as
|
|
346
|
+
data: data as any, // Input type is validated/transformed at runtime
|
|
347
|
+
returnPreference: returnPreference as any,
|
|
348
|
+
databaseUseEntityIds: this.databaseUseEntityIds,
|
|
349
|
+
databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns,
|
|
265
350
|
});
|
|
266
351
|
}
|
|
267
352
|
|
|
268
|
-
delete(): DeleteBuilder<
|
|
269
|
-
return new DeleteBuilder<
|
|
353
|
+
delete(): DeleteBuilder<Occ> {
|
|
354
|
+
return new DeleteBuilder<Occ>({
|
|
270
355
|
occurrence: this.occurrence,
|
|
271
|
-
tableName: this.tableName,
|
|
272
356
|
databaseName: this.databaseName,
|
|
273
357
|
context: this.context,
|
|
274
|
-
|
|
358
|
+
databaseUseEntityIds: this.databaseUseEntityIds,
|
|
359
|
+
databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns,
|
|
360
|
+
}) as any;
|
|
275
361
|
}
|
|
276
362
|
|
|
277
|
-
// Overload for valid relation names - returns typed EntitySet
|
|
278
|
-
navigate<RelationName extends ExtractNavigationNames<Occ>>(
|
|
279
|
-
relationName: RelationName,
|
|
280
|
-
): EntitySet<
|
|
281
|
-
ExtractSchemaFromOccurrence<
|
|
282
|
-
FindNavigationTarget<Occ, RelationName>
|
|
283
|
-
> extends Record<string, z.ZodType>
|
|
284
|
-
? ExtractSchemaFromOccurrence<FindNavigationTarget<Occ, RelationName>>
|
|
285
|
-
: Record<string, z.ZodTypeAny>,
|
|
286
|
-
FindNavigationTarget<Occ, RelationName>
|
|
287
|
-
>;
|
|
288
|
-
// Overload for arbitrary strings - returns generic EntitySet
|
|
289
|
-
navigate(
|
|
290
|
-
relationName: string,
|
|
291
|
-
): EntitySet<Record<string, z.ZodTypeAny>, undefined>;
|
|
292
363
|
// Implementation
|
|
293
|
-
navigate
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
364
|
+
navigate<TargetTable extends FMTable<any, any>>(
|
|
365
|
+
targetTable: ValidExpandTarget<Occ, TargetTable>,
|
|
366
|
+
): EntitySet<
|
|
367
|
+
TargetTable extends FMTable<any, any> ? TargetTable : never,
|
|
368
|
+
DatabaseIncludeSpecialColumns
|
|
369
|
+
> {
|
|
370
|
+
// Check if it's an FMTable object or a string
|
|
371
|
+
let relationName: string;
|
|
372
|
+
|
|
373
|
+
// FMTable object - extract name and validate
|
|
374
|
+
relationName = getTableName(targetTable);
|
|
375
|
+
|
|
376
|
+
// Runtime validation: Check if relation name is in navigationPaths
|
|
377
|
+
if (
|
|
378
|
+
this.occurrence &&
|
|
379
|
+
FMTableClass.Symbol.NavigationPaths in this.occurrence
|
|
380
|
+
) {
|
|
381
|
+
const navigationPaths = (this.occurrence as any)[
|
|
382
|
+
FMTableClass.Symbol.NavigationPaths
|
|
383
|
+
] as readonly string[];
|
|
384
|
+
if (navigationPaths && !navigationPaths.includes(relationName)) {
|
|
385
|
+
this.logger.warn(
|
|
386
|
+
`Cannot navigate to "${relationName}". Valid navigation paths: ${navigationPaths.length > 0 ? navigationPaths.join(", ") : "none"}`,
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Create EntitySet with target table
|
|
392
|
+
const entitySet = new EntitySet<any, DatabaseIncludeSpecialColumns>({
|
|
393
|
+
occurrence: targetTable,
|
|
300
394
|
databaseName: this.databaseName,
|
|
301
395
|
context: this.context,
|
|
396
|
+
database: this.database,
|
|
302
397
|
});
|
|
303
398
|
// Store the navigation info in the EntitySet
|
|
304
|
-
// We'll need to pass this through when creating QueryBuilders
|
|
305
399
|
(entitySet as any).isNavigateFromEntitySet = true;
|
|
306
400
|
(entitySet as any).navigateRelation = relationName;
|
|
307
|
-
|
|
401
|
+
|
|
402
|
+
// Build the full base path for chained navigations
|
|
403
|
+
if (this.isNavigateFromEntitySet && this.navigateBasePath) {
|
|
404
|
+
// Already have a base path from previous navigation - extend it with current relation
|
|
405
|
+
(entitySet as any).navigateBasePath =
|
|
406
|
+
`${this.navigateBasePath}/${this.navigateRelation}`;
|
|
407
|
+
(entitySet as any).navigateSourceTableName = this.navigateSourceTableName;
|
|
408
|
+
} else if (this.isNavigateFromEntitySet && this.navigateRelation) {
|
|
409
|
+
// First chained navigation - create base path from source/relation
|
|
410
|
+
(entitySet as any).navigateBasePath =
|
|
411
|
+
`${this.navigateSourceTableName}/${this.navigateRelation}`;
|
|
412
|
+
(entitySet as any).navigateSourceTableName = this.navigateSourceTableName;
|
|
413
|
+
} else {
|
|
414
|
+
// Initial navigation - source is just the table name
|
|
415
|
+
(entitySet as any).navigateSourceTableName = getTableName(
|
|
416
|
+
this.occurrence,
|
|
417
|
+
);
|
|
418
|
+
}
|
|
308
419
|
return entitySet;
|
|
309
420
|
}
|
|
310
421
|
}
|