@proofkit/fmodata 0.1.0-alpha.12 → 0.1.0-alpha.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +489 -334
- package/dist/esm/client/batch-builder.d.ts +7 -4
- package/dist/esm/client/batch-builder.js +84 -25
- package/dist/esm/client/batch-builder.js.map +1 -1
- package/dist/esm/client/builders/default-select.d.ts +7 -0
- package/dist/esm/client/builders/default-select.js +42 -0
- package/dist/esm/client/builders/default-select.js.map +1 -0
- package/dist/esm/client/builders/expand-builder.d.ts +43 -0
- package/dist/esm/client/builders/expand-builder.js +173 -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 +15 -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 +39 -0
- package/dist/esm/client/builders/response-processor.js +170 -0
- package/dist/esm/client/builders/response-processor.js.map +1 -0
- package/dist/esm/client/builders/select-mixin.d.ts +31 -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 +8 -0
- package/dist/esm/client/builders/select-utils.js +15 -0
- package/dist/esm/client/builders/select-utils.js.map +1 -0
- package/dist/esm/client/builders/shared-types.d.ts +39 -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 +3 -22
- package/dist/esm/client/database.js +14 -76
- package/dist/esm/client/database.js.map +1 -1
- package/dist/esm/client/delete-builder.d.ts +11 -15
- package/dist/esm/client/delete-builder.js +26 -26
- package/dist/esm/client/delete-builder.js.map +1 -1
- package/dist/esm/client/entity-set.d.ts +32 -32
- package/dist/esm/client/entity-set.js +92 -69
- 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 +2 -4
- package/dist/esm/client/filemaker-odata.js +1 -5
- package/dist/esm/client/filemaker-odata.js.map +1 -1
- package/dist/esm/client/insert-builder.d.ts +7 -9
- package/dist/esm/client/insert-builder.js +70 -24
- 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 +134 -0
- package/dist/esm/client/query/query-builder.js +505 -0
- package/dist/esm/client/query/query-builder.js.map +1 -0
- package/dist/esm/client/query/response-processor.d.ts +22 -0
- package/dist/esm/client/query/types.d.ts +52 -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 -111
- package/dist/esm/client/record-builder.d.ts +56 -63
- package/dist/esm/client/record-builder.js +158 -296
- package/dist/esm/client/record-builder.js.map +1 -1
- package/dist/esm/client/response-processor.d.ts +3 -3
- package/dist/esm/client/update-builder.d.ts +16 -21
- package/dist/esm/client/update-builder.js +56 -30
- package/dist/esm/client/update-builder.js.map +1 -1
- package/dist/esm/errors.d.ts +8 -1
- package/dist/esm/errors.js +17 -0
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.d.ts +3 -7
- package/dist/esm/index.js +37 -8
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/orm/column.d.ts +45 -0
- package/dist/esm/orm/column.js +59 -0
- package/dist/esm/orm/column.js.map +1 -0
- package/dist/esm/orm/field-builders.d.ts +154 -0
- package/dist/esm/orm/field-builders.js +152 -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 +221 -0
- package/dist/esm/orm/operators.js.map +1 -0
- package/dist/esm/orm/table.d.ts +341 -0
- package/dist/esm/orm/table.js +211 -0
- package/dist/esm/orm/table.js.map +1 -0
- package/dist/esm/transform.d.ts +20 -21
- package/dist/esm/transform.js +34 -34
- package/dist/esm/transform.js.map +1 -1
- package/dist/esm/types.d.ts +16 -13
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/validation.d.ts +14 -4
- package/dist/esm/validation.js +45 -1
- package/dist/esm/validation.js.map +1 -1
- package/package.json +5 -2
- package/src/client/batch-builder.ts +100 -32
- package/src/client/builders/default-select.ts +69 -0
- package/src/client/builders/expand-builder.ts +236 -0
- package/src/client/builders/index.ts +11 -0
- package/src/client/builders/query-string-builder.ts +41 -0
- package/src/client/builders/response-processor.ts +273 -0
- package/src/client/builders/select-mixin.ts +74 -0
- package/src/client/builders/select-utils.ts +34 -0
- package/src/client/builders/shared-types.ts +41 -0
- package/src/client/builders/table-utils.ts +87 -0
- package/src/client/database.ts +19 -160
- package/src/client/delete-builder.ts +46 -51
- package/src/client/entity-set.ts +227 -302
- package/src/client/error-parser.ts +59 -0
- package/src/client/filemaker-odata.ts +3 -14
- package/src/client/insert-builder.ts +124 -43
- package/src/client/query/expand-builder.ts +164 -0
- package/src/client/query/index.ts +13 -0
- package/src/client/query/query-builder.ts +816 -0
- package/src/client/query/response-processor.ts +244 -0
- package/src/client/query/types.ts +102 -0
- package/src/client/query/url-builder.ts +179 -0
- package/src/client/query-builder.ts +8 -1447
- package/src/client/record-builder.ts +325 -583
- package/src/client/response-processor.ts +4 -5
- package/src/client/update-builder.ts +102 -73
- package/src/errors.ts +22 -1
- package/src/index.ts +55 -5
- package/src/orm/column.ts +78 -0
- package/src/orm/field-builders.ts +296 -0
- package/src/orm/index.ts +60 -0
- package/src/orm/operators.ts +428 -0
- package/src/orm/table.ts +759 -0
- package/src/transform.ts +62 -48
- package/src/types.ts +20 -63
- package/src/validation.ts +76 -4
- package/dist/esm/client/base-table.d.ts +0 -128
- package/dist/esm/client/base-table.js +0 -57
- package/dist/esm/client/base-table.js.map +0 -1
- package/dist/esm/client/build-occurrences.d.ts +0 -74
- package/dist/esm/client/build-occurrences.js +0 -31
- package/dist/esm/client/build-occurrences.js.map +0 -1
- package/dist/esm/client/query-builder.js +0 -897
- package/dist/esm/client/query-builder.js.map +0 -1
- package/dist/esm/client/table-occurrence.d.ts +0 -86
- package/dist/esm/client/table-occurrence.js +0 -58
- package/dist/esm/client/table-occurrence.js.map +0 -1
- package/src/client/base-table.ts +0 -178
- package/src/client/build-occurrences.ts +0 -155
- package/src/client/query-builder.ts.bak +0 -1457
- package/src/client/table-occurrence.ts +0 -156
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
-
import { QueryBuilder } from "./query-builder.js";
|
|
4
|
+
import { QueryBuilder } from "./query/query-builder.js";
|
|
5
5
|
import { RecordBuilder } from "./record-builder.js";
|
|
6
6
|
import { InsertBuilder } from "./insert-builder.js";
|
|
7
7
|
import { DeleteBuilder } from "./delete-builder.js";
|
|
8
8
|
import { UpdateBuilder } from "./update-builder.js";
|
|
9
|
+
import { getDefaultSelect, FMTable, getTableColumns, getTableName } from "../orm/table.js";
|
|
9
10
|
class EntitySet {
|
|
10
|
-
// Full base path for chained navigations
|
|
11
11
|
constructor(config) {
|
|
12
12
|
__publicField(this, "occurrence");
|
|
13
|
-
__publicField(this, "tableName");
|
|
14
13
|
__publicField(this, "databaseName");
|
|
15
14
|
__publicField(this, "context");
|
|
16
15
|
__publicField(this, "database");
|
|
@@ -19,17 +18,19 @@ class EntitySet {
|
|
|
19
18
|
__publicField(this, "navigateRelation");
|
|
20
19
|
__publicField(this, "navigateSourceTableName");
|
|
21
20
|
__publicField(this, "navigateBasePath");
|
|
21
|
+
// Full base path for chained navigations
|
|
22
|
+
__publicField(this, "databaseUseEntityIds");
|
|
23
|
+
var _a;
|
|
22
24
|
this.occurrence = config.occurrence;
|
|
23
|
-
this.tableName = config.tableName;
|
|
24
25
|
this.databaseName = config.databaseName;
|
|
25
26
|
this.context = config.context;
|
|
26
27
|
this.database = config.database;
|
|
28
|
+
this.databaseUseEntityIds = ((_a = config.database) == null ? void 0 : _a._useEntityIds) ?? false;
|
|
27
29
|
}
|
|
28
|
-
// Type-only method to help TypeScript infer the schema from
|
|
30
|
+
// Type-only method to help TypeScript infer the schema from table
|
|
29
31
|
static create(config) {
|
|
30
32
|
return new EntitySet({
|
|
31
33
|
occurrence: config.occurrence,
|
|
32
|
-
tableName: config.tableName,
|
|
33
34
|
databaseName: config.databaseName,
|
|
34
35
|
context: config.context,
|
|
35
36
|
database: config.database
|
|
@@ -39,30 +40,35 @@ class EntitySet {
|
|
|
39
40
|
var _a;
|
|
40
41
|
const builder = new QueryBuilder({
|
|
41
42
|
occurrence: this.occurrence,
|
|
42
|
-
tableName: this.tableName,
|
|
43
43
|
databaseName: this.databaseName,
|
|
44
44
|
context: this.context,
|
|
45
|
-
databaseUseEntityIds:
|
|
45
|
+
databaseUseEntityIds: this.databaseUseEntityIds
|
|
46
46
|
});
|
|
47
47
|
if (this.occurrence) {
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
48
|
+
const defaultSelectValue = getDefaultSelect(this.occurrence);
|
|
49
|
+
const tableSchema = this.occurrence[FMTable.Symbol.Schema];
|
|
50
|
+
if (tableSchema) {
|
|
51
|
+
const zodSchema = (_a = tableSchema["~standard"]) == null ? void 0 : _a.schema;
|
|
52
|
+
if (zodSchema && typeof zodSchema === "object" && "shape" in zodSchema) {
|
|
53
|
+
zodSchema.shape;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (defaultSelectValue === "schema") {
|
|
57
|
+
const allColumns = getTableColumns(
|
|
58
|
+
this.occurrence
|
|
59
|
+
);
|
|
60
|
+
return builder.select(allColumns).top(1e3);
|
|
61
|
+
} else if (typeof defaultSelectValue === "object") {
|
|
62
|
+
return builder.select(defaultSelectValue).top(1e3);
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
|
-
if (this.isNavigateFromEntitySet) {
|
|
62
|
-
builder.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
if (this.isNavigateFromEntitySet && this.navigateRelation && this.navigateSourceTableName) {
|
|
66
|
+
builder.navigation = {
|
|
67
|
+
relation: this.navigateRelation,
|
|
68
|
+
sourceTableName: this.navigateSourceTableName,
|
|
69
|
+
basePath: this.navigateBasePath
|
|
70
|
+
// recordId is intentionally not set (undefined) to indicate navigation from EntitySet
|
|
71
|
+
};
|
|
66
72
|
}
|
|
67
73
|
return builder.top(1e3);
|
|
68
74
|
}
|
|
@@ -70,92 +76,107 @@ class EntitySet {
|
|
|
70
76
|
var _a;
|
|
71
77
|
const builder = new RecordBuilder({
|
|
72
78
|
occurrence: this.occurrence,
|
|
73
|
-
tableName: this.tableName,
|
|
74
79
|
databaseName: this.databaseName,
|
|
75
80
|
context: this.context,
|
|
76
81
|
recordId: id,
|
|
77
|
-
databaseUseEntityIds:
|
|
82
|
+
databaseUseEntityIds: this.databaseUseEntityIds
|
|
78
83
|
});
|
|
79
84
|
if (this.occurrence) {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
const defaultSelectValue = getDefaultSelect(this.occurrence);
|
|
86
|
+
const tableSchema = this.occurrence[FMTable.Symbol.Schema];
|
|
87
|
+
if (tableSchema) {
|
|
88
|
+
const zodSchema = (_a = tableSchema["~standard"]) == null ? void 0 : _a.schema;
|
|
89
|
+
if (zodSchema && typeof zodSchema === "object" && "shape" in zodSchema) {
|
|
90
|
+
zodSchema.shape;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (defaultSelectValue === "schema") {
|
|
94
|
+
const allColumns = getTableColumns(
|
|
95
|
+
this.occurrence
|
|
96
|
+
);
|
|
97
|
+
const selectedBuilder = builder.select(allColumns);
|
|
98
|
+
if (this.isNavigateFromEntitySet && this.navigateRelation && this.navigateSourceTableName) {
|
|
99
|
+
selectedBuilder.navigation = {
|
|
100
|
+
relation: this.navigateRelation,
|
|
101
|
+
sourceTableName: this.navigateSourceTableName,
|
|
102
|
+
basePath: this.navigateBasePath
|
|
103
|
+
};
|
|
90
104
|
}
|
|
91
105
|
return selectedBuilder;
|
|
92
|
-
} else if (Array.isArray(
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
106
|
+
} else if (typeof defaultSelectValue === "object" && defaultSelectValue !== null && !Array.isArray(defaultSelectValue)) {
|
|
107
|
+
const selectedBuilder = builder.select(
|
|
108
|
+
defaultSelectValue
|
|
109
|
+
);
|
|
110
|
+
if (this.isNavigateFromEntitySet && this.navigateRelation && this.navigateSourceTableName) {
|
|
111
|
+
selectedBuilder.navigation = {
|
|
112
|
+
relation: this.navigateRelation,
|
|
113
|
+
sourceTableName: this.navigateSourceTableName,
|
|
114
|
+
basePath: this.navigateBasePath
|
|
115
|
+
};
|
|
101
116
|
}
|
|
102
117
|
return selectedBuilder;
|
|
103
118
|
}
|
|
104
119
|
}
|
|
105
|
-
if (this.isNavigateFromEntitySet) {
|
|
106
|
-
builder.
|
|
107
|
-
|
|
108
|
-
|
|
120
|
+
if (this.isNavigateFromEntitySet && this.navigateRelation && this.navigateSourceTableName) {
|
|
121
|
+
builder.navigation = {
|
|
122
|
+
relation: this.navigateRelation,
|
|
123
|
+
sourceTableName: this.navigateSourceTableName,
|
|
124
|
+
basePath: this.navigateBasePath
|
|
125
|
+
};
|
|
109
126
|
}
|
|
110
127
|
return builder;
|
|
111
128
|
}
|
|
112
129
|
// Implementation
|
|
113
130
|
insert(data, options) {
|
|
114
|
-
|
|
115
|
-
const returnPref = (options == null ? void 0 : options.returnFullRecord) === false ? "minimal" : "representation";
|
|
131
|
+
const returnPreference = (options == null ? void 0 : options.returnFullRecord) === false ? "minimal" : "representation";
|
|
116
132
|
return new InsertBuilder({
|
|
117
133
|
occurrence: this.occurrence,
|
|
118
|
-
tableName: this.tableName,
|
|
119
134
|
databaseName: this.databaseName,
|
|
120
135
|
context: this.context,
|
|
121
136
|
data,
|
|
122
|
-
|
|
123
|
-
|
|
137
|
+
// Input type is validated/transformed at runtime
|
|
138
|
+
returnPreference,
|
|
139
|
+
databaseUseEntityIds: this.databaseUseEntityIds
|
|
124
140
|
});
|
|
125
141
|
}
|
|
126
142
|
// Implementation
|
|
127
143
|
update(data, options) {
|
|
128
|
-
|
|
129
|
-
const returnPref = (options == null ? void 0 : options.returnFullRecord) === true ? "representation" : "minimal";
|
|
144
|
+
const returnPreference = (options == null ? void 0 : options.returnFullRecord) === true ? "representation" : "minimal";
|
|
130
145
|
return new UpdateBuilder({
|
|
131
146
|
occurrence: this.occurrence,
|
|
132
|
-
tableName: this.tableName,
|
|
133
147
|
databaseName: this.databaseName,
|
|
134
148
|
context: this.context,
|
|
135
149
|
data,
|
|
136
|
-
|
|
137
|
-
|
|
150
|
+
// Input type is validated/transformed at runtime
|
|
151
|
+
returnPreference,
|
|
152
|
+
databaseUseEntityIds: this.databaseUseEntityIds
|
|
138
153
|
});
|
|
139
154
|
}
|
|
140
155
|
delete() {
|
|
141
|
-
var _a;
|
|
142
156
|
return new DeleteBuilder({
|
|
143
157
|
occurrence: this.occurrence,
|
|
144
|
-
tableName: this.tableName,
|
|
145
158
|
databaseName: this.databaseName,
|
|
146
159
|
context: this.context,
|
|
147
|
-
databaseUseEntityIds:
|
|
160
|
+
databaseUseEntityIds: this.databaseUseEntityIds
|
|
148
161
|
});
|
|
149
162
|
}
|
|
150
163
|
// Implementation
|
|
151
|
-
navigate(
|
|
152
|
-
|
|
153
|
-
|
|
164
|
+
navigate(targetTable) {
|
|
165
|
+
let relationName;
|
|
166
|
+
relationName = getTableName(targetTable);
|
|
167
|
+
if (this.occurrence && FMTable.Symbol.NavigationPaths in this.occurrence) {
|
|
168
|
+
const navigationPaths = this.occurrence[FMTable.Symbol.NavigationPaths];
|
|
169
|
+
if (navigationPaths && !navigationPaths.includes(relationName)) {
|
|
170
|
+
console.warn(
|
|
171
|
+
`Cannot navigate to "${relationName}". Valid navigation paths: ${navigationPaths.length > 0 ? navigationPaths.join(", ") : "none"}`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
154
175
|
const entitySet = new EntitySet({
|
|
155
|
-
occurrence:
|
|
156
|
-
tableName: (targetOccurrence == null ? void 0 : targetOccurrence.name) ?? relationName,
|
|
176
|
+
occurrence: targetTable,
|
|
157
177
|
databaseName: this.databaseName,
|
|
158
|
-
context: this.context
|
|
178
|
+
context: this.context,
|
|
179
|
+
database: this.database
|
|
159
180
|
});
|
|
160
181
|
entitySet.isNavigateFromEntitySet = true;
|
|
161
182
|
entitySet.navigateRelation = relationName;
|
|
@@ -166,7 +187,9 @@ class EntitySet {
|
|
|
166
187
|
entitySet.navigateBasePath = `${this.navigateSourceTableName}/${this.navigateRelation}`;
|
|
167
188
|
entitySet.navigateSourceTableName = this.navigateSourceTableName;
|
|
168
189
|
} else {
|
|
169
|
-
entitySet.navigateSourceTableName =
|
|
190
|
+
entitySet.navigateSourceTableName = getTableName(
|
|
191
|
+
this.occurrence
|
|
192
|
+
);
|
|
170
193
|
}
|
|
171
194
|
return entitySet;
|
|
172
195
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity-set.js","sources":["../../../src/client/entity-set.ts"],"sourcesContent":["import type {\n ExecutionContext,\n InferSchemaType,\n WithSystemFields,\n InsertData,\n UpdateData,\n} from \"../types\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\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\";\nimport { Database } from \"./database\";\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, any, 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, any, 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 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 ? Nav[Name]\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, any>,\n any,\n any,\n any\n >\n : TableOccurrence<\n BaseTable<Record<string, StandardSchemaV1>, any, any, 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, any, any>]\n ? [S] extends [Record<string, StandardSchemaV1>]\n ? InferSchemaType<S>\n : Record<string, any>\n : Record<string, any>\n : Record<string, any>;\n\nexport class EntitySet<\n Schema extends Record<string, StandardSchemaV1> = 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 database: Database<any>; // Database instance for accessing occurrences\n private isNavigateFromEntitySet?: boolean;\n private navigateRelation?: string;\n private navigateSourceTableName?: string;\n private navigateBasePath?: string; // Full base path for chained navigations\n\n constructor(config: {\n occurrence?: Occ;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n database?: any;\n }) {\n this.occurrence = config.occurrence;\n this.tableName = config.tableName;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.database = config.database;\n }\n\n // Type-only method to help TypeScript infer the schema from occurrence\n static create<\n OccurrenceSchema extends Record<string, StandardSchemaV1>,\n Occ extends\n | TableOccurrence<\n BaseTable<OccurrenceSchema, any, any, any>,\n any,\n any,\n any\n >\n | undefined = undefined,\n >(config: {\n occurrence?: Occ;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n database: Database<any>;\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 database: config.database,\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 databaseUseEntityIds: this.database?.isUsingEntityIds() ?? false,\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).top(1000);\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).top(1000);\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 (builder as any).navigateBasePath = this.navigateBasePath;\n // navigateRecordId is intentionally not set (undefined) to indicate navigation from EntitySet\n }\n\n // Apply default pagination limit of 1000 records to prevent stack overflow\n // with large datasets. Users can override with .top() if needed.\n return builder.top(1000);\n }\n\n get(\n id: string | number,\n ): RecordBuilder<\n InferSchemaType<Schema>,\n false,\n keyof InferSchemaType<Schema>,\n Occ,\n Occ extends TableOccurrence<any, any, any, any>\n ? ExtractDefaultSelect<Occ>\n : keyof InferSchemaType<Schema>,\n {}\n > {\n const builder = new RecordBuilder<\n InferSchemaType<Schema>,\n false,\n keyof InferSchemaType<Schema>,\n Occ,\n keyof InferSchemaType<Schema>,\n {}\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n recordId: id,\n databaseUseEntityIds: this.database?.isUsingEntityIds() ?? false,\n });\n\n // Apply defaultSelect if occurrence exists\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 const selectedBuilder = builder.select(...uniqueFields);\n // Propagate navigation context if present\n if (this.isNavigateFromEntitySet) {\n (selectedBuilder as any).isNavigateFromEntitySet = true;\n (selectedBuilder as any).navigateRelation = this.navigateRelation;\n (selectedBuilder as any).navigateSourceTableName = this.navigateSourceTableName;\n }\n return selectedBuilder as any;\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 const selectedBuilder = builder.select(...uniqueFields);\n // Propagate navigation context if present\n if (this.isNavigateFromEntitySet) {\n (selectedBuilder as any).isNavigateFromEntitySet = true;\n (selectedBuilder as any).navigateRelation = this.navigateRelation;\n (selectedBuilder as any).navigateSourceTableName = this.navigateSourceTableName;\n }\n return selectedBuilder as any;\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).isNavigateFromEntitySet = true;\n (builder as any).navigateRelation = this.navigateRelation;\n (builder as any).navigateSourceTableName = this.navigateSourceTableName;\n }\n return builder as any;\n }\n\n // Overload: when returnFullRecord is explicitly false\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 options: { returnFullRecord: false },\n ): InsertBuilder<InferSchemaType<Schema>, Occ, \"minimal\">;\n\n // Overload: when returnFullRecord is true or omitted (default)\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 options?: { returnFullRecord?: true },\n ): InsertBuilder<InferSchemaType<Schema>, Occ, \"representation\">;\n\n // Implementation\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 options?: { returnFullRecord?: boolean },\n ): InsertBuilder<InferSchemaType<Schema>, Occ, \"minimal\" | \"representation\"> {\n const returnPref =\n options?.returnFullRecord === false ? \"minimal\" : \"representation\";\n return new InsertBuilder<InferSchemaType<Schema>, Occ, typeof returnPref>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n data: data as Partial<InferSchemaType<Schema>>,\n returnPreference: returnPref as any,\n databaseUseEntityIds: this.database?.isUsingEntityIds() ?? false,\n });\n }\n\n // Overload: when returnFullRecord is explicitly true\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 options: { returnFullRecord: true },\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 \"representation\"\n >;\n\n // Overload: when returnFullRecord is false or omitted (default returns count)\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 options?: { returnFullRecord?: false },\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 \"minimal\"\n >;\n\n // Implementation\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 options?: { returnFullRecord?: boolean },\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 \"minimal\" | \"representation\"\n > {\n const returnPref =\n options?.returnFullRecord === true ? \"representation\" : \"minimal\";\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 typeof returnPref\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 returnPreference: returnPref as any,\n databaseUseEntityIds: this.database?.isUsingEntityIds() ?? false,\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 databaseUseEntityIds: this.database?.isUsingEntityIds() ?? false,\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, StandardSchemaV1>\n ? ExtractSchemaFromOccurrence<FindNavigationTarget<Occ, RelationName>>\n : Record<string, StandardSchemaV1>,\n FindNavigationTarget<Occ, RelationName>\n >;\n // Overload for arbitrary strings - returns generic EntitySet\n navigate(\n relationName: string,\n ): EntitySet<Record<string, StandardSchemaV1>, 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\n // Build the full base path for chained navigations\n // The base path should contain all segments BEFORE the final relation\n if (this.isNavigateFromEntitySet && this.navigateBasePath) {\n // Already have a base path from previous navigation - extend it with current relation\n (entitySet as any).navigateBasePath =\n `${this.navigateBasePath}/${this.navigateRelation}`;\n (entitySet as any).navigateSourceTableName = this.navigateSourceTableName;\n } else if (this.isNavigateFromEntitySet && this.navigateRelation) {\n // First chained navigation - create base path from source/relation\n (entitySet as any).navigateBasePath =\n `${this.navigateSourceTableName}/${this.navigateRelation}`;\n (entitySet as any).navigateSourceTableName = this.navigateSourceTableName;\n } else {\n // Initial navigation - source is just the table name\n (entitySet as any).navigateSourceTableName = this.tableName;\n }\n return entitySet;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"entity-set.js","sources":["../../../src/client/entity-set.ts"],"sourcesContent":["import type { ExecutionContext, InferSchemaType } from \"../types\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport { QueryBuilder } from \"./query\";\nimport { RecordBuilder } from \"./record-builder\";\nimport { InsertBuilder } from \"./insert-builder\";\nimport { DeleteBuilder } from \"./delete-builder\";\nimport { UpdateBuilder } from \"./update-builder\";\nimport { Database } from \"./database\";\nimport type {\n FMTable,\n InferSchemaOutputFromFMTable,\n InferInputSchemaFromFMTable,\n InsertDataFromFMTable,\n UpdateDataFromFMTable,\n ValidExpandTarget,\n ExtractTableName,\n FMTableWithColumns,\n InferFieldOutput,\n} from \"../orm/table\";\nimport {\n FMTable as FMTableClass,\n getDefaultSelect,\n getNavigationPaths,\n getTableName,\n getTableColumns,\n getTableFields,\n} from \"../orm/table\";\nimport type { Column } from \"../orm/column\";\nimport type { FieldBuilder } from \"../orm/field-builders\";\n\n// Helper type to extract defaultSelect from an FMTable\n// Since TypeScript can't extract Symbol-indexed properties at the type level,\n// we simplify to return keyof InferSchemaFromFMTable<O> when O is an FMTable.\n// The actual defaultSelect logic is handled at runtime.\ntype ExtractDefaultSelect<O> =\n O extends FMTable<any, any> ? keyof InferSchemaOutputFromFMTable<O> : never;\n\n/**\n * Helper type to extract properly-typed columns from an FMTable.\n * This preserves the specific column types instead of widening to `any`.\n */\ntype ExtractColumnsFromOcc<T> =\n T extends FMTable<infer TFields, infer TName, any>\n ? TFields extends Record<string, FieldBuilder<any, any, any, any>>\n ? { [K in keyof TFields]: Column<InferFieldOutput<TFields[K]>, TName> }\n : never\n : never;\n\nexport class EntitySet<Occ extends FMTable<any, any>> {\n private occurrence: Occ;\n private databaseName: string;\n private context: ExecutionContext;\n private database: Database; // Database instance for accessing occurrences\n private isNavigateFromEntitySet?: boolean;\n private navigateRelation?: string;\n private navigateSourceTableName?: string;\n private navigateBasePath?: string; // Full base path for chained navigations\n private databaseUseEntityIds: boolean;\n\n constructor(config: {\n occurrence: Occ;\n databaseName: string;\n context: ExecutionContext;\n database?: any;\n }) {\n this.occurrence = config.occurrence;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.database = config.database;\n // Get useEntityIds from database if available, otherwise default to false\n this.databaseUseEntityIds =\n (config.database as any)?._useEntityIds ?? false;\n }\n\n // Type-only method to help TypeScript infer the schema from table\n static create<Occ extends FMTable<any, any>>(config: {\n occurrence: Occ;\n databaseName: string;\n context: ExecutionContext;\n database: Database;\n }): EntitySet<Occ> {\n return new EntitySet<Occ>({\n occurrence: config.occurrence,\n databaseName: config.databaseName,\n context: config.context,\n database: config.database,\n });\n }\n\n list() {\n const builder = new QueryBuilder<Occ>({\n occurrence: this.occurrence as Occ,\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n\n // Apply defaultSelect if occurrence exists and select hasn't been called\n if (this.occurrence) {\n // FMTable - access via helper functions\n const defaultSelectValue = getDefaultSelect(this.occurrence);\n const tableSchema = (this.occurrence as any)[FMTableClass.Symbol.Schema];\n let schema: Record<string, StandardSchemaV1> | undefined;\n\n if (tableSchema) {\n // Extract schema from StandardSchemaV1\n const zodSchema = tableSchema[\"~standard\"]?.schema;\n if (\n zodSchema &&\n typeof zodSchema === \"object\" &&\n \"shape\" in zodSchema\n ) {\n schema = zodSchema.shape as Record<string, StandardSchemaV1>;\n }\n }\n\n if (defaultSelectValue === \"schema\") {\n // Use getTableColumns to get all columns and select them\n // This is equivalent to select(getTableColumns(occurrence))\n // Use ExtractColumnsFromOcc to preserve the properly-typed column types\n const allColumns = getTableColumns(\n this.occurrence as any,\n ) as ExtractColumnsFromOcc<Occ>;\n return builder.select(allColumns).top(1000);\n } else if (typeof defaultSelectValue === \"object\") {\n // defaultSelectValue is a select object (Record<string, Column>)\n // Use it directly with select()\n // Use ExtractColumnsFromOcc to preserve the properly-typed column types\n return builder\n .select(defaultSelectValue as ExtractColumnsFromOcc<Occ>)\n .top(1000);\n }\n // If defaultSelect is \"all\", no changes needed (current behavior)\n }\n\n // Propagate navigation context if present\n if (\n this.isNavigateFromEntitySet &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n (builder as any).navigation = {\n relation: this.navigateRelation,\n sourceTableName: this.navigateSourceTableName,\n basePath: this.navigateBasePath,\n // recordId is intentionally not set (undefined) to indicate navigation from EntitySet\n };\n }\n\n // Apply default pagination limit of 1000 records to prevent stack overflow\n // with large datasets. Users can override with .top() if needed.\n return builder.top(1000);\n }\n\n get(\n id: string | number,\n ): RecordBuilder<\n Occ,\n false,\n keyof InferSchemaOutputFromFMTable<Occ>,\n keyof InferSchemaOutputFromFMTable<Occ>,\n {}\n > {\n const builder = new RecordBuilder<Occ>({\n occurrence: this.occurrence,\n databaseName: this.databaseName,\n context: this.context,\n recordId: id,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n\n // Apply defaultSelect if occurrence exists\n if (this.occurrence) {\n // FMTable - access via helper functions\n const defaultSelectValue = getDefaultSelect(this.occurrence);\n const tableSchema = (this.occurrence as any)[FMTableClass.Symbol.Schema];\n let schema: Record<string, StandardSchemaV1> | undefined;\n\n if (tableSchema) {\n // Extract schema from StandardSchemaV1\n const zodSchema = tableSchema[\"~standard\"]?.schema;\n if (\n zodSchema &&\n typeof zodSchema === \"object\" &&\n \"shape\" in zodSchema\n ) {\n schema = zodSchema.shape as Record<string, StandardSchemaV1>;\n }\n }\n\n if (defaultSelectValue === \"schema\") {\n // Use getTableColumns to get all columns and select them\n // This is equivalent to select(getTableColumns(occurrence))\n // Use ExtractColumnsFromOcc to preserve the properly-typed column types\n const allColumns = getTableColumns(\n this.occurrence as any,\n ) as ExtractColumnsFromOcc<Occ>;\n const selectedBuilder = builder.select(allColumns);\n // Propagate navigation context if present\n if (\n this.isNavigateFromEntitySet &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n (selectedBuilder as any).navigation = {\n relation: this.navigateRelation,\n sourceTableName: this.navigateSourceTableName,\n basePath: this.navigateBasePath,\n };\n }\n return selectedBuilder as any;\n } else if (\n typeof defaultSelectValue === \"object\" &&\n defaultSelectValue !== null &&\n !Array.isArray(defaultSelectValue)\n ) {\n // defaultSelectValue is a select object (Record<string, Column>)\n // Use it directly with select()\n // Use ExtractColumnsFromOcc to preserve the properly-typed column types\n const selectedBuilder = builder.select(\n defaultSelectValue as ExtractColumnsFromOcc<Occ>,\n );\n // Propagate navigation context if present\n if (\n this.isNavigateFromEntitySet &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n (selectedBuilder as any).navigation = {\n relation: this.navigateRelation,\n sourceTableName: this.navigateSourceTableName,\n basePath: this.navigateBasePath,\n };\n }\n return selectedBuilder as any;\n }\n // If defaultSelect is \"all\", no changes needed (current behavior)\n }\n\n // Propagate navigation context if present\n if (\n this.isNavigateFromEntitySet &&\n this.navigateRelation &&\n this.navigateSourceTableName\n ) {\n (builder as any).navigation = {\n relation: this.navigateRelation,\n sourceTableName: this.navigateSourceTableName,\n basePath: this.navigateBasePath,\n };\n }\n return builder as any;\n }\n\n // Overload: when returnFullRecord is false\n insert(\n data: InsertDataFromFMTable<Occ>,\n options: { returnFullRecord: false },\n ): InsertBuilder<Occ, \"minimal\">;\n\n // Overload: when returnFullRecord is true or omitted (default)\n insert(\n data: InsertDataFromFMTable<Occ>,\n options?: { returnFullRecord?: true },\n ): InsertBuilder<Occ, \"representation\">;\n\n // Implementation\n insert(\n data: InsertDataFromFMTable<Occ>,\n options?: { returnFullRecord?: boolean },\n ): InsertBuilder<Occ, \"minimal\" | \"representation\"> {\n const returnPreference =\n options?.returnFullRecord === false ? \"minimal\" : \"representation\";\n\n return new InsertBuilder<Occ, typeof returnPreference>({\n occurrence: this.occurrence,\n databaseName: this.databaseName,\n context: this.context,\n data: data as any, // Input type is validated/transformed at runtime\n returnPreference: returnPreference as any,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n }\n\n // Overload: when returnFullRecord is explicitly true\n update(\n data: UpdateDataFromFMTable<Occ>,\n options: { returnFullRecord: true },\n ): UpdateBuilder<Occ, \"representation\">;\n\n // Overload: when returnFullRecord is false or omitted (default)\n update(\n data: UpdateDataFromFMTable<Occ>,\n options?: { returnFullRecord?: false },\n ): UpdateBuilder<Occ, \"minimal\">;\n\n // Implementation\n update(\n data: UpdateDataFromFMTable<Occ>,\n options?: { returnFullRecord?: boolean },\n ): UpdateBuilder<Occ, \"minimal\" | \"representation\"> {\n const returnPreference =\n options?.returnFullRecord === true ? \"representation\" : \"minimal\";\n\n return new UpdateBuilder<Occ, typeof returnPreference>({\n occurrence: this.occurrence,\n databaseName: this.databaseName,\n context: this.context,\n data: data as any, // Input type is validated/transformed at runtime\n returnPreference: returnPreference as any,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n }\n\n delete(): DeleteBuilder<Occ> {\n return new DeleteBuilder<Occ>({\n occurrence: this.occurrence,\n databaseName: this.databaseName,\n context: this.context,\n databaseUseEntityIds: this.databaseUseEntityIds,\n }) as any;\n }\n\n // Implementation\n navigate<TargetTable extends FMTable<any, any>>(\n targetTable: ValidExpandTarget<Occ, TargetTable>,\n ): EntitySet<TargetTable extends FMTable<any, any> ? TargetTable : never> {\n // Check if it's an FMTable object or a string\n let relationName: string;\n\n // FMTable object - extract name and validate\n relationName = getTableName(targetTable);\n\n // Runtime validation: Check if relation name is in navigationPaths\n if (\n this.occurrence &&\n FMTableClass.Symbol.NavigationPaths in this.occurrence\n ) {\n const navigationPaths = (this.occurrence as any)[\n FMTableClass.Symbol.NavigationPaths\n ] as readonly string[];\n if (navigationPaths && !navigationPaths.includes(relationName)) {\n console.warn(\n `Cannot navigate to \"${relationName}\". Valid navigation paths: ${navigationPaths.length > 0 ? navigationPaths.join(\", \") : \"none\"}`,\n );\n }\n }\n\n // Create EntitySet with target table\n const entitySet = new EntitySet<any>({\n occurrence: targetTable,\n databaseName: this.databaseName,\n context: this.context,\n database: this.database,\n });\n // Store the navigation info in the EntitySet\n (entitySet as any).isNavigateFromEntitySet = true;\n (entitySet as any).navigateRelation = relationName;\n\n // Build the full base path for chained navigations\n if (this.isNavigateFromEntitySet && this.navigateBasePath) {\n // Already have a base path from previous navigation - extend it with current relation\n (entitySet as any).navigateBasePath =\n `${this.navigateBasePath}/${this.navigateRelation}`;\n (entitySet as any).navigateSourceTableName = this.navigateSourceTableName;\n } else if (this.isNavigateFromEntitySet && this.navigateRelation) {\n // First chained navigation - create base path from source/relation\n (entitySet as any).navigateBasePath =\n `${this.navigateSourceTableName}/${this.navigateRelation}`;\n (entitySet as any).navigateSourceTableName = this.navigateSourceTableName;\n } else {\n // Initial navigation - source is just the table name\n (entitySet as any).navigateSourceTableName = getTableName(\n this.occurrence,\n );\n }\n return entitySet;\n }\n}\n"],"names":["FMTableClass"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FMODataErrorType } from '../errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Parses an error response and returns an appropriate error object.
|
|
4
|
+
* This helper is used by builder processResponse methods to handle error responses
|
|
5
|
+
* consistently, particularly important for batch operations where errors need to be
|
|
6
|
+
* properly parsed from the response body.
|
|
7
|
+
*
|
|
8
|
+
* @param response - The Response object (may be from batch or direct request)
|
|
9
|
+
* @param url - The URL that was requested (for error context)
|
|
10
|
+
* @returns An appropriate error object (ODataError, SchemaLockedError, or HTTPError)
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseErrorResponse(response: Response, url: string): Promise<FMODataErrorType>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { SchemaLockedError, ODataError, HTTPError } from "../errors.js";
|
|
2
|
+
import { safeJsonParse } from "./sanitize-json.js";
|
|
3
|
+
async function parseErrorResponse(response, url) {
|
|
4
|
+
var _a;
|
|
5
|
+
let errorBody;
|
|
6
|
+
try {
|
|
7
|
+
if ((_a = response.headers.get("content-type")) == null ? void 0 : _a.includes("application/json")) {
|
|
8
|
+
errorBody = await safeJsonParse(response);
|
|
9
|
+
}
|
|
10
|
+
} catch {
|
|
11
|
+
}
|
|
12
|
+
if (errorBody == null ? void 0 : errorBody.error) {
|
|
13
|
+
const errorCode = errorBody.error.code;
|
|
14
|
+
const errorMessage = errorBody.error.message || response.statusText;
|
|
15
|
+
if (errorCode === "303" || errorCode === 303) {
|
|
16
|
+
return new SchemaLockedError(url, errorMessage, errorBody.error);
|
|
17
|
+
}
|
|
18
|
+
return new ODataError(
|
|
19
|
+
url,
|
|
20
|
+
errorMessage,
|
|
21
|
+
String(errorCode),
|
|
22
|
+
errorBody.error
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
return new HTTPError(url, response.status, response.statusText, errorBody);
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
parseErrorResponse
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=error-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-parser.js","sources":["../../../src/client/error-parser.ts"],"sourcesContent":["import {\n HTTPError,\n ODataError,\n SchemaLockedError,\n FMODataErrorType,\n} from \"../errors\";\nimport { safeJsonParse } from \"./sanitize-json\";\n\n/**\n * Parses an error response and returns an appropriate error object.\n * This helper is used by builder processResponse methods to handle error responses\n * consistently, particularly important for batch operations where errors need to be\n * properly parsed from the response body.\n *\n * @param response - The Response object (may be from batch or direct request)\n * @param url - The URL that was requested (for error context)\n * @returns An appropriate error object (ODataError, SchemaLockedError, or HTTPError)\n */\nexport async function parseErrorResponse(\n response: Response,\n url: string,\n): Promise<FMODataErrorType> {\n // Try to parse error body if it's JSON\n let errorBody: { error?: { code?: string | number; message?: string } } | undefined;\n \n try {\n if (response.headers.get(\"content-type\")?.includes(\"application/json\")) {\n errorBody = await safeJsonParse<typeof errorBody>(response);\n }\n } catch {\n // Ignore JSON parse errors - we'll fall back to HTTPError\n }\n\n // Check if it's an OData error response\n if (errorBody?.error) {\n const errorCode = errorBody.error.code;\n const errorMessage = errorBody.error.message || response.statusText;\n\n // Check for schema locked error (code 303)\n if (errorCode === \"303\" || errorCode === 303) {\n return new SchemaLockedError(url, errorMessage, errorBody.error);\n }\n\n return new ODataError(\n url,\n errorMessage,\n String(errorCode),\n errorBody.error,\n );\n }\n\n // Fall back to generic HTTPError\n return new HTTPError(url, response.status, response.statusText, errorBody);\n}\n\n\n\n\n\n"],"names":[],"mappings":";;AAkBsB,eAAA,mBACpB,UACA,KAC2B;;AAEvB,MAAA;AAEA,MAAA;AACF,SAAI,cAAS,QAAQ,IAAI,cAAc,MAAnC,mBAAsC,SAAS,qBAAqB;AAC1D,kBAAA,MAAM,cAAgC,QAAQ;AAAA,IAAA;AAAA,EAC5D,QACM;AAAA,EAAA;AAKR,MAAI,uCAAW,OAAO;AACd,UAAA,YAAY,UAAU,MAAM;AAClC,UAAM,eAAe,UAAU,MAAM,WAAW,SAAS;AAGrD,QAAA,cAAc,SAAS,cAAc,KAAK;AAC5C,aAAO,IAAI,kBAAkB,KAAK,cAAc,UAAU,KAAK;AAAA,IAAA;AAGjE,WAAO,IAAI;AAAA,MACT;AAAA,MACA;AAAA,MACA,OAAO,SAAS;AAAA,MAChB,UAAU;AAAA,IACZ;AAAA,EAAA;AAIF,SAAO,IAAI,UAAU,KAAK,SAAS,QAAQ,SAAS,YAAY,SAAS;AAC3E;"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { FFetchOptions } from '@fetchkit/ffetch';
|
|
2
2
|
import { Auth, ExecutionContext, Result } from '../types.js';
|
|
3
3
|
import { Database } from './database.js';
|
|
4
|
-
import { TableOccurrence } from './table-occurrence.js';
|
|
5
4
|
export declare class FMServerConnection implements ExecutionContext {
|
|
6
5
|
private fetchClient;
|
|
7
6
|
private serverUrl;
|
|
@@ -33,10 +32,9 @@ export declare class FMServerConnection implements ExecutionContext {
|
|
|
33
32
|
_makeRequest<T>(url: string, options?: RequestInit & FFetchOptions & {
|
|
34
33
|
useEntityIds?: boolean;
|
|
35
34
|
}): Promise<Result<T>>;
|
|
36
|
-
database
|
|
37
|
-
occurrences?: Occurrences | undefined;
|
|
35
|
+
database(name: string, config?: {
|
|
38
36
|
useEntityIds?: boolean;
|
|
39
|
-
}): Database
|
|
37
|
+
}): Database;
|
|
40
38
|
/**
|
|
41
39
|
* Lists all available databases from the FileMaker OData service.
|
|
42
40
|
* @returns Promise resolving to an array of database names
|
|
@@ -74,11 +74,7 @@ class FMServerConnection {
|
|
|
74
74
|
...restOptions,
|
|
75
75
|
headers
|
|
76
76
|
};
|
|
77
|
-
const resp =
|
|
78
|
-
method: finalOptions.method,
|
|
79
|
-
headers: finalOptions.headers,
|
|
80
|
-
body: finalOptions.body
|
|
81
|
-
}) : await clientToUse(fullUrl, finalOptions);
|
|
77
|
+
const resp = await clientToUse(fullUrl, finalOptions);
|
|
82
78
|
if (!resp.ok) {
|
|
83
79
|
let errorBody;
|
|
84
80
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filemaker-odata.js","sources":["../../../src/client/filemaker-odata.ts"],"sourcesContent":["import createClient, {\n FFetchOptions,\n TimeoutError,\n AbortError,\n NetworkError,\n RetryLimitError,\n CircuitOpenError,\n} from \"@fetchkit/ffetch\";\nimport type { Auth, ExecutionContext, Result } from \"../types\";\nimport { getAcceptHeader } from \"../types\";\nimport {\n HTTPError,\n ODataError,\n SchemaLockedError,\n ResponseParseError,\n} from \"../errors\";\nimport { Database } from \"./database\";\nimport { TableOccurrence } from \"./table-occurrence\";\nimport { safeJsonParse } from \"./sanitize-json\";\nimport { get } from \"es-toolkit/compat\";\n\nexport class FMServerConnection implements ExecutionContext {\n private fetchClient: ReturnType<typeof createClient>;\n private serverUrl: string;\n private auth: Auth;\n private useEntityIds: boolean = false;\n constructor(config: {\n serverUrl: string;\n auth: Auth;\n fetchClientOptions?: FFetchOptions;\n }) {\n this.fetchClient = createClient({\n retries: 0,\n ...config.fetchClientOptions,\n });\n // Ensure the URL uses https://, is valid, and has no trailing slash\n const url = new URL(config.serverUrl);\n if (url.protocol !== \"https:\") {\n url.protocol = \"https:\";\n }\n // Remove any trailing slash from pathname\n url.pathname = url.pathname.replace(/\\/+$/, \"\");\n this.serverUrl = url.toString().replace(/\\/+$/, \"\");\n this.auth = config.auth;\n }\n\n /**\n * @internal\n * Sets whether to use FileMaker entity IDs (FMFID/FMTID) in requests\n */\n _setUseEntityIds(useEntityIds: boolean): void {\n this.useEntityIds = useEntityIds;\n }\n\n /**\n * @internal\n * Gets whether to use FileMaker entity IDs (FMFID/FMTID) in requests\n */\n _getUseEntityIds(): boolean {\n return this.useEntityIds;\n }\n\n /**\n * @internal\n * Gets the base URL for OData requests\n */\n _getBaseUrl(): string {\n return `${this.serverUrl}${\"apiKey\" in this.auth ? `/otto` : \"\"}/fmi/odata/v4`;\n }\n\n /**\n * @internal\n */\n async _makeRequest<T>(\n url: string,\n options?: RequestInit & FFetchOptions & { useEntityIds?: boolean },\n ): Promise<Result<T>> {\n const baseUrl = `${this.serverUrl}${\"apiKey\" in this.auth ? `/otto` : \"\"}/fmi/odata/v4`;\n const fullUrl = baseUrl + url;\n\n // Use per-request override if provided, otherwise use the database-level setting\n const useEntityIds = options?.useEntityIds ?? this.useEntityIds;\n\n // Get includeODataAnnotations from options (it's passed through from execute options)\n const includeODataAnnotations = (options as any)?.includeODataAnnotations;\n\n const headers = {\n Authorization:\n \"apiKey\" in this.auth\n ? `Bearer ${this.auth.apiKey}`\n : `Basic ${btoa(`${this.auth.username}:${this.auth.password}`)}`,\n \"Content-Type\": \"application/json\",\n Accept: getAcceptHeader(includeODataAnnotations),\n ...(useEntityIds ? { Prefer: \"fmodata.entity-ids\" } : {}),\n ...(options?.headers || {}),\n };\n\n // TEMPORARY WORKAROUND: Hopefully this feature will be fixed in the ffetch library\n // Extract fetchHandler and headers separately, only for tests where we're overriding the fetch handler per-request\n const fetchHandler = options?.fetchHandler;\n const {\n headers: _headers,\n fetchHandler: _fetchHandler,\n ...restOptions\n } = options || {};\n\n // If fetchHandler is provided, create a temporary client with it\n // Otherwise use the existing client\n const clientToUse = fetchHandler\n ? createClient({ retries: 0, fetchHandler })\n : this.fetchClient;\n\n try {\n const finalOptions = {\n ...restOptions,\n headers,\n };\n\n // For batch requests, use native fetch to avoid any potential serialization issues with ffetch\n const resp = url.includes(\"/$batch\")\n ? await fetch(fullUrl, {\n method: finalOptions.method,\n headers: finalOptions.headers,\n body: finalOptions.body,\n })\n : await clientToUse(fullUrl, finalOptions);\n\n // Handle HTTP errors\n if (!resp.ok) {\n // Try to parse error body if it's JSON\n let errorBody:\n | { error?: { code?: string | number; message?: string } }\n | undefined;\n try {\n if (resp.headers.get(\"content-type\")?.includes(\"application/json\")) {\n errorBody = await safeJsonParse<typeof errorBody>(resp);\n }\n } catch {\n // Ignore JSON parse errors\n }\n\n // Check if it's an OData error response\n if (errorBody?.error) {\n const errorCode = errorBody.error.code;\n const errorMessage = errorBody.error.message || resp.statusText;\n\n // Check for schema locked error (code 303)\n if (errorCode === \"303\" || errorCode === 303) {\n return {\n data: undefined,\n error: new SchemaLockedError(\n fullUrl,\n errorMessage,\n errorBody.error,\n ),\n };\n }\n\n return {\n data: undefined,\n error: new ODataError(\n fullUrl,\n errorMessage,\n String(errorCode),\n errorBody.error,\n ),\n };\n }\n\n return {\n data: undefined,\n error: new HTTPError(\n fullUrl,\n resp.status,\n resp.statusText,\n errorBody,\n ),\n };\n }\n\n // Check for affected rows header (for DELETE and bulk PATCH operations)\n // FileMaker may return this with 204 No Content or 200 OK\n const affectedRows = resp.headers.get(\"fmodata.affected_rows\");\n if (affectedRows !== null) {\n return { data: parseInt(affectedRows, 10) as T, error: undefined };\n }\n\n // Handle 204 No Content with no body\n if (resp.status === 204) {\n // Check for Location header (used for insert with return=minimal)\n // Use optional chaining for safety with mocks that might not have proper headers\n const locationHeader =\n resp.headers?.get?.(\"Location\") || resp.headers?.get?.(\"location\");\n if (locationHeader) {\n // Return the location header so InsertBuilder can extract ROWID\n return { data: { _location: locationHeader } as T, error: undefined };\n }\n return { data: 0 as T, error: undefined };\n }\n\n // Parse response\n if (resp.headers.get(\"content-type\")?.includes(\"application/json\")) {\n const data = await safeJsonParse<\n T & { error?: { code?: string | number; message?: string } }\n >(resp);\n\n // Check for embedded OData errors\n if (get(data, \"error\", null)) {\n const errorCode = get(data, \"error.code\", null);\n const errorMessage = get(\n data,\n \"error.message\",\n \"Unknown OData error\",\n );\n\n // Check for schema locked error (code 303)\n if (errorCode === \"303\" || errorCode === 303) {\n return {\n data: undefined,\n error: new SchemaLockedError(fullUrl, errorMessage, data.error),\n };\n }\n\n return {\n data: undefined,\n error: new ODataError(\n fullUrl,\n errorMessage,\n String(errorCode),\n data.error,\n ),\n };\n }\n\n return { data: data as T, error: undefined };\n }\n\n return { data: (await resp.text()) as T, error: undefined };\n } catch (err) {\n // Map ffetch errors - return them directly (no re-wrapping)\n if (\n err instanceof TimeoutError ||\n err instanceof AbortError ||\n err instanceof NetworkError ||\n err instanceof RetryLimitError ||\n err instanceof CircuitOpenError\n ) {\n return { data: undefined, error: err };\n }\n\n // Handle JSON parse errors (ResponseParseError from safeJsonParse)\n if (err instanceof ResponseParseError) {\n return { data: undefined, error: err };\n }\n\n // Unknown error - wrap it as NetworkError\n return {\n data: undefined,\n error: new NetworkError(fullUrl, err),\n };\n }\n }\n\n database<\n const Occurrences extends readonly TableOccurrence<any, any, any, any>[],\n >(\n name: string,\n config?: {\n occurrences?: Occurrences | undefined;\n useEntityIds?: boolean;\n },\n ): Database<Occurrences> {\n return new Database(name, this, config);\n }\n\n /**\n * Lists all available databases from the FileMaker OData service.\n * @returns Promise resolving to an array of database names\n */\n async listDatabaseNames(): Promise<string[]> {\n const result = await this._makeRequest<{\n value?: Array<{ name: string }>;\n }>(\"/\");\n if (result.error) {\n throw result.error;\n }\n if (result.data.value && Array.isArray(result.data.value)) {\n return result.data.value.map((item) => item.name);\n }\n return [];\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"filemaker-odata.js","sources":["../../../src/client/filemaker-odata.ts"],"sourcesContent":["import createClient, {\n FFetchOptions,\n TimeoutError,\n AbortError,\n NetworkError,\n RetryLimitError,\n CircuitOpenError,\n} from \"@fetchkit/ffetch\";\nimport type { Auth, ExecutionContext, Result } from \"../types\";\nimport { getAcceptHeader } from \"../types\";\nimport {\n HTTPError,\n ODataError,\n SchemaLockedError,\n ResponseParseError,\n} from \"../errors\";\nimport { Database } from \"./database\";\nimport { safeJsonParse } from \"./sanitize-json\";\nimport { get } from \"es-toolkit/compat\";\n\nexport class FMServerConnection implements ExecutionContext {\n private fetchClient: ReturnType<typeof createClient>;\n private serverUrl: string;\n private auth: Auth;\n private useEntityIds: boolean = false;\n constructor(config: {\n serverUrl: string;\n auth: Auth;\n fetchClientOptions?: FFetchOptions;\n }) {\n this.fetchClient = createClient({\n retries: 0,\n ...config.fetchClientOptions,\n });\n // Ensure the URL uses https://, is valid, and has no trailing slash\n const url = new URL(config.serverUrl);\n if (url.protocol !== \"https:\") {\n url.protocol = \"https:\";\n }\n // Remove any trailing slash from pathname\n url.pathname = url.pathname.replace(/\\/+$/, \"\");\n this.serverUrl = url.toString().replace(/\\/+$/, \"\");\n this.auth = config.auth;\n }\n\n /**\n * @internal\n * Sets whether to use FileMaker entity IDs (FMFID/FMTID) in requests\n */\n _setUseEntityIds(useEntityIds: boolean): void {\n this.useEntityIds = useEntityIds;\n }\n\n /**\n * @internal\n * Gets whether to use FileMaker entity IDs (FMFID/FMTID) in requests\n */\n _getUseEntityIds(): boolean {\n return this.useEntityIds;\n }\n\n /**\n * @internal\n * Gets the base URL for OData requests\n */\n _getBaseUrl(): string {\n return `${this.serverUrl}${\"apiKey\" in this.auth ? `/otto` : \"\"}/fmi/odata/v4`;\n }\n\n /**\n * @internal\n */\n async _makeRequest<T>(\n url: string,\n options?: RequestInit & FFetchOptions & { useEntityIds?: boolean },\n ): Promise<Result<T>> {\n const baseUrl = `${this.serverUrl}${\"apiKey\" in this.auth ? `/otto` : \"\"}/fmi/odata/v4`;\n const fullUrl = baseUrl + url;\n\n // Use per-request override if provided, otherwise use the database-level setting\n const useEntityIds = options?.useEntityIds ?? this.useEntityIds;\n\n // Get includeODataAnnotations from options (it's passed through from execute options)\n const includeODataAnnotations = (options as any)?.includeODataAnnotations;\n\n const headers = {\n Authorization:\n \"apiKey\" in this.auth\n ? `Bearer ${this.auth.apiKey}`\n : `Basic ${btoa(`${this.auth.username}:${this.auth.password}`)}`,\n \"Content-Type\": \"application/json\",\n Accept: getAcceptHeader(includeODataAnnotations),\n ...(useEntityIds ? { Prefer: \"fmodata.entity-ids\" } : {}),\n ...(options?.headers || {}),\n };\n\n // TEMPORARY WORKAROUND: Hopefully this feature will be fixed in the ffetch library\n // Extract fetchHandler and headers separately, only for tests where we're overriding the fetch handler per-request\n const fetchHandler = options?.fetchHandler;\n const {\n headers: _headers,\n fetchHandler: _fetchHandler,\n ...restOptions\n } = options || {};\n\n // If fetchHandler is provided, create a temporary client with it\n // Otherwise use the existing client\n const clientToUse = fetchHandler\n ? createClient({ retries: 0, fetchHandler })\n : this.fetchClient;\n\n try {\n const finalOptions = {\n ...restOptions,\n headers,\n };\n\n const resp = await clientToUse(fullUrl, finalOptions);\n\n // Handle HTTP errors\n if (!resp.ok) {\n // Try to parse error body if it's JSON\n let errorBody:\n | { error?: { code?: string | number; message?: string } }\n | undefined;\n try {\n if (resp.headers.get(\"content-type\")?.includes(\"application/json\")) {\n errorBody = await safeJsonParse<typeof errorBody>(resp);\n }\n } catch {\n // Ignore JSON parse errors\n }\n\n // Check if it's an OData error response\n if (errorBody?.error) {\n const errorCode = errorBody.error.code;\n const errorMessage = errorBody.error.message || resp.statusText;\n\n // Check for schema locked error (code 303)\n if (errorCode === \"303\" || errorCode === 303) {\n return {\n data: undefined,\n error: new SchemaLockedError(\n fullUrl,\n errorMessage,\n errorBody.error,\n ),\n };\n }\n\n return {\n data: undefined,\n error: new ODataError(\n fullUrl,\n errorMessage,\n String(errorCode),\n errorBody.error,\n ),\n };\n }\n\n return {\n data: undefined,\n error: new HTTPError(\n fullUrl,\n resp.status,\n resp.statusText,\n errorBody,\n ),\n };\n }\n\n // Check for affected rows header (for DELETE and bulk PATCH operations)\n // FileMaker may return this with 204 No Content or 200 OK\n const affectedRows = resp.headers.get(\"fmodata.affected_rows\");\n if (affectedRows !== null) {\n return { data: parseInt(affectedRows, 10) as T, error: undefined };\n }\n\n // Handle 204 No Content with no body\n if (resp.status === 204) {\n // Check for Location header (used for insert with return=minimal)\n // Use optional chaining for safety with mocks that might not have proper headers\n const locationHeader =\n resp.headers?.get?.(\"Location\") || resp.headers?.get?.(\"location\");\n if (locationHeader) {\n // Return the location header so InsertBuilder can extract ROWID\n return { data: { _location: locationHeader } as T, error: undefined };\n }\n return { data: 0 as T, error: undefined };\n }\n\n // Parse response\n if (resp.headers.get(\"content-type\")?.includes(\"application/json\")) {\n const data = await safeJsonParse<\n T & { error?: { code?: string | number; message?: string } }\n >(resp);\n\n // Check for embedded OData errors\n if (get(data, \"error\", null)) {\n const errorCode = get(data, \"error.code\", null);\n const errorMessage = get(\n data,\n \"error.message\",\n \"Unknown OData error\",\n );\n\n // Check for schema locked error (code 303)\n if (errorCode === \"303\" || errorCode === 303) {\n return {\n data: undefined,\n error: new SchemaLockedError(fullUrl, errorMessage, data.error),\n };\n }\n\n return {\n data: undefined,\n error: new ODataError(\n fullUrl,\n errorMessage,\n String(errorCode),\n data.error,\n ),\n };\n }\n\n return { data: data as T, error: undefined };\n }\n\n return { data: (await resp.text()) as T, error: undefined };\n } catch (err) {\n // Map ffetch errors - return them directly (no re-wrapping)\n if (\n err instanceof TimeoutError ||\n err instanceof AbortError ||\n err instanceof NetworkError ||\n err instanceof RetryLimitError ||\n err instanceof CircuitOpenError\n ) {\n return { data: undefined, error: err };\n }\n\n // Handle JSON parse errors (ResponseParseError from safeJsonParse)\n if (err instanceof ResponseParseError) {\n return { data: undefined, error: err };\n }\n\n // Unknown error - wrap it as NetworkError\n return {\n data: undefined,\n error: new NetworkError(fullUrl, err),\n };\n }\n }\n\n database(\n name: string,\n config?: {\n useEntityIds?: boolean;\n },\n ): Database {\n return new Database(name, this, config);\n }\n\n /**\n * Lists all available databases from the FileMaker OData service.\n * @returns Promise resolving to an array of database names\n */\n async listDatabaseNames(): Promise<string[]> {\n const result = await this._makeRequest<{\n value?: Array<{ name: string }>;\n }>(\"/\");\n if (result.error) {\n throw result.error;\n }\n if (result.data.value && Array.isArray(result.data.value)) {\n return result.data.value.map((item) => item.name);\n }\n return [];\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { ExecutionContext, ExecutableBuilder, Result, ExecuteOptions, ConditionallyWithODataAnnotations } from '../types.js';
|
|
2
|
-
import {
|
|
2
|
+
import { FMTable, InferSchemaOutputFromFMTable } from '../orm/table.js';
|
|
3
3
|
import { FFetchOptions } from '@fetchkit/ffetch';
|
|
4
4
|
export type InsertOptions = {
|
|
5
5
|
return?: "minimal" | "representation";
|
|
6
6
|
};
|
|
7
|
-
export declare class InsertBuilder<
|
|
7
|
+
export declare class InsertBuilder<Occ extends FMTable<any, any> | undefined = undefined, ReturnPreference extends "minimal" | "representation" = "representation"> implements ExecutableBuilder<ReturnPreference extends "minimal" ? {
|
|
8
8
|
ROWID: number;
|
|
9
|
-
} :
|
|
10
|
-
private
|
|
11
|
-
private tableName;
|
|
9
|
+
} : InferSchemaOutputFromFMTable<NonNullable<Occ>>> {
|
|
10
|
+
private table?;
|
|
12
11
|
private databaseName;
|
|
13
12
|
private context;
|
|
14
13
|
private data;
|
|
@@ -16,10 +15,9 @@ export declare class InsertBuilder<T extends Record<string, any>, Occ extends Ta
|
|
|
16
15
|
private databaseUseEntityIds;
|
|
17
16
|
constructor(config: {
|
|
18
17
|
occurrence?: Occ;
|
|
19
|
-
tableName: string;
|
|
20
18
|
databaseName: string;
|
|
21
19
|
context: ExecutionContext;
|
|
22
|
-
data: Partial<
|
|
20
|
+
data: Partial<InferSchemaOutputFromFMTable<NonNullable<Occ>>>;
|
|
23
21
|
returnPreference?: ReturnPreference;
|
|
24
22
|
databaseUseEntityIds?: boolean;
|
|
25
23
|
});
|
|
@@ -41,7 +39,7 @@ export declare class InsertBuilder<T extends Record<string, any>, Occ extends Ta
|
|
|
41
39
|
private getTableId;
|
|
42
40
|
execute<EO extends ExecuteOptions>(options?: RequestInit & FFetchOptions & EO): Promise<Result<ReturnPreference extends "minimal" ? {
|
|
43
41
|
ROWID: number;
|
|
44
|
-
} : ConditionallyWithODataAnnotations<
|
|
42
|
+
} : ConditionallyWithODataAnnotations<InferSchemaOutputFromFMTable<NonNullable<Occ>>, EO["includeODataAnnotations"] extends true ? true : false>>>;
|
|
45
43
|
getRequestConfig(): {
|
|
46
44
|
method: string;
|
|
47
45
|
url: string;
|
|
@@ -50,5 +48,5 @@ export declare class InsertBuilder<T extends Record<string, any>, Occ extends Ta
|
|
|
50
48
|
toRequest(baseUrl: string, options?: ExecuteOptions): Request;
|
|
51
49
|
processResponse(response: Response, options?: ExecuteOptions): Promise<Result<ReturnPreference extends "minimal" ? {
|
|
52
50
|
ROWID: number;
|
|
53
|
-
} :
|
|
51
|
+
} : InferSchemaOutputFromFMTable<NonNullable<Occ>>>>;
|
|
54
52
|
}
|