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