@proofkit/fmodata 0.1.0-alpha.7 → 0.1.0-alpha.8

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 CHANGED
@@ -26,8 +26,8 @@ Here's a minimal example to get you started:
26
26
  ```typescript
27
27
  import {
28
28
  FMServerConnection,
29
- BaseTable,
30
- TableOccurrence,
29
+ defineBaseTable,
30
+ defineTableOccurrence,
31
31
  } from "@proofkit/fmodata";
32
32
  import { z } from "zod/v4";
33
33
 
@@ -45,7 +45,7 @@ const connection = new FMServerConnection({
45
45
  });
46
46
 
47
47
  // 2. Define your table schema
48
- const usersBase = new BaseTable({
48
+ const usersBase = defineBaseTable({
49
49
  schema: {
50
50
  id: z.string(),
51
51
  username: z.string(),
@@ -56,7 +56,7 @@ const usersBase = new BaseTable({
56
56
  });
57
57
 
58
58
  // 3. Create a table occurrence
59
- const usersTO = new TableOccurrence({
59
+ const usersTO = defineTableOccurrence({
60
60
  name: "users",
61
61
  baseTable: usersBase,
62
62
  });
@@ -127,15 +127,21 @@ const connection = new FMServerConnection({
127
127
 
128
128
  ### Schema Definitions
129
129
 
130
- This library relies on a schema-first approach for good type-safety and optional runtime validation. These are absracted into BaseTable and TableOccurrence classes to match FileMaker concepts.
130
+ This library relies on a schema-first approach for good type-safety and optional runtime validation. These are abstracted into BaseTable and TableOccurrence classes to match FileMaker concepts.
131
+
132
+ **Helper Functions vs Constructors:**
133
+
134
+ - **`defineBaseTable()`** and **`defineTableOccurrence()`** - Recommended for better type inference, especially when using entity IDs (FMFID/FMTID). These functions provide improved TypeScript type inference for field names in queries.
135
+
136
+ - **`new BaseTable()`** and **`new TableOccurrence()`** - Still supported for backward compatibility, but may have slightly less precise type inference in some cases.
131
137
 
132
138
  A `BaseTable` defines the schema for your FileMaker table using Standard Schema. These examples show zod, but you can use any other validation library that supports Standard Schema.
133
139
 
134
140
  ```typescript
135
141
  import { z } from "zod/v4";
136
- import { BaseTable } from "@proofkit/fmodata";
142
+ import { defineBaseTable } from "@proofkit/fmodata";
137
143
 
138
- const contactsBase = new BaseTable({
144
+ const contactsBase = defineBaseTable({
139
145
  schema: {
140
146
  id: z.string(),
141
147
  name: z.string(),
@@ -151,10 +157,12 @@ const contactsBase = new BaseTable({
151
157
 
152
158
  A `TableOccurrence` is the actual entry point for the OData service on the FileMaker server. It's where you can define the relations between tables and also allows you to reference the same base table multiple times with different names.
153
159
 
160
+ **Recommended:** Use `defineTableOccurrence()` for better type inference. You can also use `new TableOccurrence()` directly.
161
+
154
162
  ```typescript
155
- import { TableOccurrence } from "@proofkit/fmodata";
163
+ import { defineTableOccurrence } from "@proofkit/fmodata";
156
164
 
157
- const contactsTO = new TableOccurrence({
165
+ const contactsTO = defineTableOccurrence({
158
166
  name: "contacts", // The table occurrence name in FileMaker
159
167
  baseTable: contactsBase,
160
168
  });
@@ -166,21 +174,21 @@ FileMaker will automatically return all non-container fields from a schema if yo
166
174
 
167
175
  ```typescript
168
176
  // Option 1 (default): "schema" - Select all fields from the schema (same as "all" but more explicit)
169
- const usersTO = new TableOccurrence({
177
+ const usersTO = defineTableOccurrence({
170
178
  name: "users",
171
179
  baseTable: usersBase,
172
180
  defaultSelect: "schema", // a $select parameter will be always be added to the query for only the fields you've defined in the BaseTable schema
173
181
  });
174
182
 
175
183
  // Option 2: "all" - Select all fields (default behavior)
176
- const usersTO = new TableOccurrence({
184
+ const usersTO = defineTableOccurrence({
177
185
  name: "users",
178
186
  baseTable: usersBase,
179
187
  defaultSelect: "all", // Don't always a $select parameter to the query; FileMaker will return all non-container fields from the table
180
188
  });
181
189
 
182
190
  // Option 3: Array of field names - Select only specific fields by default
183
- const usersTO = new TableOccurrence({
191
+ const usersTO = defineTableOccurrence({
184
192
  name: "users",
185
193
  baseTable: usersBase,
186
194
  defaultSelect: ["username", "email"], // Only select these fields by default
@@ -530,7 +538,7 @@ if (result.data) {
530
538
  Fields are automatically required for insert if their validator doesn't allow `null` or `undefined`. You can specify additional required fields:
531
539
 
532
540
  ```typescript
533
- const usersBase = new BaseTable({
541
+ const usersBase = defineBaseTable({
534
542
  schema: {
535
543
  id: z.string(), // Auto-required (not nullable), but excluded from insert (idField)
536
544
  username: z.string(), // Auto-required (not nullable)
@@ -635,7 +643,7 @@ const result = await db
635
643
  Define relationships between tables using the `navigation` option:
636
644
 
637
645
  ```typescript
638
- const contactsBase = new BaseTable({
646
+ const contactsBase = defineBaseTable({
639
647
  schema: {
640
648
  id: z.string(),
641
649
  name: z.string(),
@@ -644,7 +652,7 @@ const contactsBase = new BaseTable({
644
652
  idField: "id",
645
653
  });
646
654
 
647
- const usersBase = new BaseTable({
655
+ const usersBase = defineBaseTable({
648
656
  schema: {
649
657
  id: z.string(),
650
658
  username: z.string(),
@@ -654,20 +662,24 @@ const usersBase = new BaseTable({
654
662
  });
655
663
 
656
664
  // Define navigation using functions to handle circular dependencies
657
- const contactsTO = new TableOccurrence({
665
+ // Create base occurrences first, then add navigation
666
+ const _contactsTO = defineTableOccurrence({
658
667
  name: "contacts",
659
668
  baseTable: contactsBase,
660
- navigation: {
661
- users: () => usersTO, // Relationship to users table
662
- },
663
669
  });
664
670
 
665
- const usersTO = new TableOccurrence({
671
+ const _usersTO = defineTableOccurrence({
666
672
  name: "users",
667
673
  baseTable: usersBase,
668
- navigation: {
669
- contacts: () => contactsTO, // Relationship to contacts table
670
- },
674
+ });
675
+
676
+ // Then add navigation
677
+ const contactsTO = _contactsTO.addNavigation({
678
+ users: () => _usersTO,
679
+ });
680
+
681
+ const usersTO = _usersTO.addNavigation({
682
+ contacts: () => _contactsTO,
671
683
  });
672
684
 
673
685
  // You can also add navigation after creation
@@ -1140,7 +1152,7 @@ await db.schema.createIndex("users", "email");
1140
1152
  The library provides full TypeScript type inference:
1141
1153
 
1142
1154
  ```typescript
1143
- const usersBase = new BaseTable({
1155
+ const usersBase = defineBaseTable({
1144
1156
  schema: {
1145
1157
  id: z.string(),
1146
1158
  username: z.string(),
@@ -1149,7 +1161,7 @@ const usersBase = new BaseTable({
1149
1161
  idField: "id",
1150
1162
  });
1151
1163
 
1152
- const usersTO = new TableOccurrence({
1164
+ const usersTO = defineTableOccurrence({
1153
1165
  name: "users",
1154
1166
  baseTable: usersBase,
1155
1167
  });
@@ -1178,7 +1190,7 @@ db.from("users")
1178
1190
  The library automatically infers which fields are required based on whether their validator allows `null` or `undefined`:
1179
1191
 
1180
1192
  ```typescript
1181
- const usersBase = new BaseTable({
1193
+ const usersBase = defineBaseTable({
1182
1194
  schema: {
1183
1195
  id: z.string(), // Auto-required, auto-readOnly (idField)
1184
1196
  username: z.string(), // Auto-required (not nullable)
@@ -1222,7 +1234,7 @@ db.from("users")
1222
1234
 
1223
1235
  This library supports using FileMaker's internal field identifiers (FMFID) and table occurrence identifiers (FMTID) instead of names. This protects your integration from both field and table occurrence name changes.
1224
1236
 
1225
- To enable this feature, simply define your schema with the `BaseTableWithIds` and `TableOccurrenceWithIds` classes. Behind the scenes, the library will transform your request and the response back to the names you specify in these schemas. This is an all-or-nothing feature. For it to work properly, you must define all table occurrences passed to a `Database` with the `TableOccurrenceWithIds` class.
1237
+ To enable this feature, simply define your schema with entity IDs using the `defineBaseTable` and `defineTableOccurrence` functions. Behind the scenes, the library will transform your request and the response back to the names you specify in these schemas. This is an all-or-nothing feature. For it to work properly, you must define all table occurrences passed to a `Database` with entity IDs (both `fmfIds` on the base table and `fmtId` on the table occurrence).
1226
1238
 
1227
1239
  _Note for OttoFMS proxy: This feature requires version 4.14 or later of OttoFMS_
1228
1240
 
@@ -1231,11 +1243,11 @@ How do I find these ids? They can be found in the XML version of the `$metadata`
1231
1243
  #### Basic Usage
1232
1244
 
1233
1245
  ```typescript
1234
- import { BaseTableWithIds, TableOccurrenceWithIds } from "@proofkit/fmodata";
1246
+ import { defineBaseTable, defineTableOccurrence } from "@proofkit/fmodata";
1235
1247
  import { z } from "zod/v4";
1236
1248
 
1237
1249
  // Define a base table with FileMaker field IDs
1238
- const usersBase = new BaseTableWithIds({
1250
+ const usersBase = defineBaseTable({
1239
1251
  schema: {
1240
1252
  id: z.string(),
1241
1253
  username: z.string(),
@@ -1252,9 +1264,9 @@ const usersBase = new BaseTableWithIds({
1252
1264
  });
1253
1265
 
1254
1266
  // Create a table occurrence with a FileMaker table occurrence ID
1255
- const usersTO = new TableOccurrenceWithIds({
1267
+ const usersTO = defineTableOccurrence({
1256
1268
  name: "users",
1257
- baseTable: usersBase, // Must be a BaseTableWithIds
1269
+ baseTable: usersBase,
1258
1270
  fmtId: "FMTID:12432533",
1259
1271
  });
1260
1272
  ```
@@ -72,6 +72,7 @@ export declare class BaseTable<Schema extends Record<string, StandardSchemaV1> =
72
72
  idField?: IdField;
73
73
  required?: Required;
74
74
  readOnly?: ReadOnly;
75
+ fmfIds?: Record<string, `FMFID:${string}`>;
75
76
  });
76
77
  /**
77
78
  * Returns the FileMaker field ID (FMFID) for a given field name, or the field name itself if not using IDs.
@@ -91,40 +92,34 @@ export declare class BaseTable<Schema extends Record<string, StandardSchemaV1> =
91
92
  isUsingFieldIds(): boolean;
92
93
  }
93
94
  /**
94
- * BaseTableWithIds extends BaseTable to require FileMaker field IDs (fmfIds).
95
- * Use this class when you need to work with FileMaker's internal field identifiers.
95
+ * Creates a BaseTable with proper TypeScript type inference.
96
96
  *
97
- * @template Schema - Record of field names to StandardSchemaV1 validators
98
- * @template IdField - The name of the primary key field (optional, automatically read-only)
99
- * @template Required - Additional field names to require on insert (beyond auto-inferred required fields)
100
- * @template ReadOnly - Field names that cannot be modified via insert/update (idField is automatically read-only)
97
+ * This function should be used instead of `new BaseTable()` to ensure
98
+ * field names are properly typed throughout the library.
101
99
  *
102
- * @example
100
+ * @example Without entity IDs
103
101
  * ```ts
104
- * import { z } from "zod";
102
+ * const users = defineBaseTable({
103
+ * schema: { id: z.string(), name: z.string() },
104
+ * idField: "id",
105
+ * });
106
+ * ```
105
107
  *
106
- * const usersTableWithIds = new BaseTableWithIds({
107
- * schema: {
108
- * id: z.string(),
109
- * name: z.string(),
110
- * email: z.string().nullable(),
111
- * },
108
+ * @example With entity IDs (FileMaker field IDs)
109
+ * ```ts
110
+ * const products = defineBaseTable({
111
+ * schema: { id: z.string(), name: z.string() },
112
112
  * idField: "id",
113
- * fmfIds: {
114
- * id: "FMFID:1",
115
- * name: "FMFID:2",
116
- * email: "FMFID:3",
117
- * },
113
+ * fmfIds: { id: "FMFID:1", name: "FMFID:2" },
118
114
  * });
119
115
  * ```
120
116
  */
121
- export declare class BaseTableWithIds<Schema extends Record<string, StandardSchemaV1> = any, IdField extends keyof Schema | undefined = undefined, Required extends readonly (keyof Schema)[] = readonly [], ReadOnly extends readonly (keyof Schema)[] = readonly []> extends BaseTable<Schema, IdField, Required, ReadOnly> {
122
- readonly fmfIds: Record<keyof Schema, `FMFID:${string}`>;
123
- constructor(config: {
124
- schema: Schema;
125
- fmfIds: Record<keyof Schema, `FMFID:${string}`>;
126
- idField?: IdField;
127
- required?: Required;
128
- readOnly?: ReadOnly;
129
- });
130
- }
117
+ export declare function defineBaseTable<const Schema extends Record<string, StandardSchemaV1>, IdField extends keyof Schema | undefined = undefined, const Required extends readonly (keyof Schema)[] = readonly [], const ReadOnly extends readonly (keyof Schema)[] = readonly []>(config: {
118
+ schema: Schema;
119
+ idField?: IdField;
120
+ required?: Required;
121
+ readOnly?: ReadOnly;
122
+ fmfIds?: {
123
+ [K in keyof Schema]: `FMFID:${string}`;
124
+ };
125
+ }): BaseTable<Schema, IdField, Required, ReadOnly>;
@@ -12,6 +12,7 @@ class BaseTable {
12
12
  this.idField = config.idField;
13
13
  this.required = config.required;
14
14
  this.readOnly = config.readOnly;
15
+ this.fmfIds = config.fmfIds;
15
16
  }
16
17
  /**
17
18
  * Returns the FileMaker field ID (FMFID) for a given field name, or the field name itself if not using IDs.
@@ -46,15 +47,11 @@ class BaseTable {
46
47
  return this.fmfIds !== void 0;
47
48
  }
48
49
  }
49
- class BaseTableWithIds extends BaseTable {
50
- constructor(config) {
51
- super(config);
52
- __publicField(this, "fmfIds");
53
- this.fmfIds = config.fmfIds;
54
- }
50
+ function defineBaseTable(config) {
51
+ return new BaseTable(config);
55
52
  }
56
53
  export {
57
54
  BaseTable,
58
- BaseTableWithIds
55
+ defineBaseTable
59
56
  };
60
57
  //# sourceMappingURL=base-table.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"base-table.js","sources":["../../../src/client/base-table.ts"],"sourcesContent":["import { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * BaseTable defines the schema and configuration for a table.\n *\n * @template Schema - Record of field names to StandardSchemaV1 validators\n * @template IdField - The name of the primary key field (optional, automatically read-only)\n * @template Required - Additional field names to require on insert (beyond auto-inferred required fields)\n * @template ReadOnly - Field names that cannot be modified via insert/update (idField is automatically read-only)\n *\n * @example Basic table with auto-inferred required fields\n * ```ts\n * import { z } from \"zod\";\n *\n * const usersTable = new BaseTable({\n * schema: {\n * id: z.string(), // Auto-required (not nullable), auto-readOnly (idField)\n * name: z.string(), // Auto-required (not nullable)\n * email: z.string().nullable(), // Optional (nullable)\n * },\n * idField: \"id\",\n * });\n * // On insert: name is required, email is optional (id is excluded - readOnly)\n * // On update: name and email available (id is excluded - readOnly)\n * ```\n *\n * @example Table with additional required and readOnly fields\n * ```ts\n * import { z } from \"zod\";\n *\n * const usersTable = new BaseTable({\n * schema: {\n * id: z.string(), // Auto-required, auto-readOnly (idField)\n * createdAt: z.string(), // Read-only system field\n * name: z.string(), // Auto-required\n * email: z.string().nullable(), // Optional by default...\n * legacyField: z.string().nullable(), // Optional by default...\n * },\n * idField: \"id\",\n * required: [\"legacyField\"], // Make legacyField required for new inserts\n * readOnly: [\"createdAt\"], // Exclude from insert/update\n * });\n * // On insert: name and legacyField required; email optional (id and createdAt excluded)\n * // On update: all fields optional (id and createdAt excluded)\n * ```\n *\n * @example Table with multiple read-only fields\n * ```ts\n * import { z } from \"zod\";\n *\n * const usersTable = new BaseTable({\n * schema: {\n * id: z.string(),\n * createdAt: z.string(),\n * modifiedAt: z.string(),\n * createdBy: z.string(),\n * notes: z.string().nullable(),\n * },\n * idField: \"id\",\n * readOnly: [\"createdAt\", \"modifiedAt\", \"createdBy\"],\n * });\n * // On insert/update: only notes is available (id and system fields excluded)\n * ```\n */\nexport class BaseTable<\n Schema extends Record<string, StandardSchemaV1> = any,\n IdField extends keyof Schema | undefined = undefined,\n Required extends readonly (keyof Schema)[] = readonly [],\n ReadOnly extends readonly (keyof Schema)[] = readonly [],\n> {\n public readonly schema: Schema;\n public readonly idField?: IdField;\n public readonly required?: Required;\n public readonly readOnly?: ReadOnly;\n public readonly fmfIds?: Record<keyof Schema, `FMFID:${string}`>;\n\n constructor(config: {\n schema: Schema;\n idField?: IdField;\n required?: Required;\n readOnly?: ReadOnly;\n }) {\n this.schema = config.schema;\n this.idField = config.idField;\n this.required = config.required;\n this.readOnly = config.readOnly;\n }\n\n /**\n * Returns the FileMaker field ID (FMFID) for a given field name, or the field name itself if not using IDs.\n * @param fieldName - The field name to get the ID for\n * @returns The FMFID string or the original field name\n */\n getFieldId(fieldName: keyof Schema): string {\n if (this.fmfIds && fieldName in this.fmfIds) {\n return this.fmfIds[fieldName];\n }\n return String(fieldName);\n }\n\n /**\n * Returns the field name for a given FileMaker field ID (FMFID), or the ID itself if not found.\n * @param fieldId - The FMFID to get the field name for\n * @returns The field name or the original ID\n */\n getFieldName(fieldId: string): string {\n if (this.fmfIds) {\n // Search for the field name that corresponds to this FMFID\n for (const [fieldName, fmfId] of Object.entries(this.fmfIds)) {\n if (fmfId === fieldId) {\n return fieldName;\n }\n }\n }\n return fieldId;\n }\n\n /**\n * Returns true if this BaseTable is using FileMaker field IDs.\n */\n isUsingFieldIds(): boolean {\n return this.fmfIds !== undefined;\n }\n}\n\n/**\n * BaseTableWithIds extends BaseTable to require FileMaker field IDs (fmfIds).\n * Use this class when you need to work with FileMaker's internal field identifiers.\n *\n * @template Schema - Record of field names to StandardSchemaV1 validators\n * @template IdField - The name of the primary key field (optional, automatically read-only)\n * @template Required - Additional field names to require on insert (beyond auto-inferred required fields)\n * @template ReadOnly - Field names that cannot be modified via insert/update (idField is automatically read-only)\n *\n * @example\n * ```ts\n * import { z } from \"zod\";\n *\n * const usersTableWithIds = new BaseTableWithIds({\n * schema: {\n * id: z.string(),\n * name: z.string(),\n * email: z.string().nullable(),\n * },\n * idField: \"id\",\n * fmfIds: {\n * id: \"FMFID:1\",\n * name: \"FMFID:2\",\n * email: \"FMFID:3\",\n * },\n * });\n * ```\n */\nexport class BaseTableWithIds<\n Schema extends Record<string, StandardSchemaV1> = any,\n IdField extends keyof Schema | undefined = undefined,\n Required extends readonly (keyof Schema)[] = readonly [],\n ReadOnly extends readonly (keyof Schema)[] = readonly [],\n> extends BaseTable<Schema, IdField, Required, ReadOnly> {\n public override readonly fmfIds: Record<keyof Schema, `FMFID:${string}`>;\n\n constructor(config: {\n schema: Schema;\n fmfIds: Record<keyof Schema, `FMFID:${string}`>;\n idField?: IdField;\n required?: Required;\n readOnly?: ReadOnly;\n }) {\n super(config);\n this.fmfIds = config.fmfIds;\n }\n}\n"],"names":[],"mappings":";;;AAgEO,MAAM,UAKX;AAAA,EAOA,YAAY,QAKT;AAXa;AACA;AACA;AACA;AACA;AAQd,SAAK,SAAS,OAAO;AACrB,SAAK,UAAU,OAAO;AACtB,SAAK,WAAW,OAAO;AACvB,SAAK,WAAW,OAAO;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQzB,WAAW,WAAiC;AAC1C,QAAI,KAAK,UAAU,aAAa,KAAK,QAAQ;AACpC,aAAA,KAAK,OAAO,SAAS;AAAA,IAAA;AAE9B,WAAO,OAAO,SAAS;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQzB,aAAa,SAAyB;AACpC,QAAI,KAAK,QAAQ;AAEJ,iBAAA,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,KAAK,MAAM,GAAG;AAC5D,YAAI,UAAU,SAAS;AACd,iBAAA;AAAA,QAAA;AAAA,MACT;AAAA,IACF;AAEK,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMT,kBAA2B;AACzB,WAAO,KAAK,WAAW;AAAA,EAAA;AAE3B;AA8BO,MAAM,yBAKH,UAA+C;AAAA,EAGvD,YAAY,QAMT;AACD,UAAM,MAAM;AATW;AAUvB,SAAK,SAAS,OAAO;AAAA,EAAA;AAEzB;"}
1
+ {"version":3,"file":"base-table.js","sources":["../../../src/client/base-table.ts"],"sourcesContent":["import { StandardSchemaV1 } from \"@standard-schema/spec\";\n\n/**\n * BaseTable defines the schema and configuration for a table.\n *\n * @template Schema - Record of field names to StandardSchemaV1 validators\n * @template IdField - The name of the primary key field (optional, automatically read-only)\n * @template Required - Additional field names to require on insert (beyond auto-inferred required fields)\n * @template ReadOnly - Field names that cannot be modified via insert/update (idField is automatically read-only)\n *\n * @example Basic table with auto-inferred required fields\n * ```ts\n * import { z } from \"zod\";\n *\n * const usersTable = new BaseTable({\n * schema: {\n * id: z.string(), // Auto-required (not nullable), auto-readOnly (idField)\n * name: z.string(), // Auto-required (not nullable)\n * email: z.string().nullable(), // Optional (nullable)\n * },\n * idField: \"id\",\n * });\n * // On insert: name is required, email is optional (id is excluded - readOnly)\n * // On update: name and email available (id is excluded - readOnly)\n * ```\n *\n * @example Table with additional required and readOnly fields\n * ```ts\n * import { z } from \"zod\";\n *\n * const usersTable = new BaseTable({\n * schema: {\n * id: z.string(), // Auto-required, auto-readOnly (idField)\n * createdAt: z.string(), // Read-only system field\n * name: z.string(), // Auto-required\n * email: z.string().nullable(), // Optional by default...\n * legacyField: z.string().nullable(), // Optional by default...\n * },\n * idField: \"id\",\n * required: [\"legacyField\"], // Make legacyField required for new inserts\n * readOnly: [\"createdAt\"], // Exclude from insert/update\n * });\n * // On insert: name and legacyField required; email optional (id and createdAt excluded)\n * // On update: all fields optional (id and createdAt excluded)\n * ```\n *\n * @example Table with multiple read-only fields\n * ```ts\n * import { z } from \"zod\";\n *\n * const usersTable = new BaseTable({\n * schema: {\n * id: z.string(),\n * createdAt: z.string(),\n * modifiedAt: z.string(),\n * createdBy: z.string(),\n * notes: z.string().nullable(),\n * },\n * idField: \"id\",\n * readOnly: [\"createdAt\", \"modifiedAt\", \"createdBy\"],\n * });\n * // On insert/update: only notes is available (id and system fields excluded)\n * ```\n */\nexport class BaseTable<\n Schema extends Record<string, StandardSchemaV1> = any,\n IdField extends keyof Schema | undefined = undefined,\n Required extends readonly (keyof Schema)[] = readonly [],\n ReadOnly extends readonly (keyof Schema)[] = readonly [],\n> {\n public readonly schema: Schema;\n public readonly idField?: IdField;\n public readonly required?: Required;\n public readonly readOnly?: ReadOnly;\n public readonly fmfIds?: Record<keyof Schema, `FMFID:${string}`>;\n\n constructor(config: {\n schema: Schema;\n idField?: IdField;\n required?: Required;\n readOnly?: ReadOnly;\n fmfIds?: Record<string, `FMFID:${string}`>;\n }) {\n this.schema = config.schema;\n this.idField = config.idField;\n this.required = config.required;\n this.readOnly = config.readOnly;\n this.fmfIds = config.fmfIds as\n | Record<keyof Schema, `FMFID:${string}`>\n | undefined;\n }\n\n /**\n * Returns the FileMaker field ID (FMFID) for a given field name, or the field name itself if not using IDs.\n * @param fieldName - The field name to get the ID for\n * @returns The FMFID string or the original field name\n */\n getFieldId(fieldName: keyof Schema): string {\n if (this.fmfIds && fieldName in this.fmfIds) {\n return this.fmfIds[fieldName];\n }\n return String(fieldName);\n }\n\n /**\n * Returns the field name for a given FileMaker field ID (FMFID), or the ID itself if not found.\n * @param fieldId - The FMFID to get the field name for\n * @returns The field name or the original ID\n */\n getFieldName(fieldId: string): string {\n if (this.fmfIds) {\n // Search for the field name that corresponds to this FMFID\n for (const [fieldName, fmfId] of Object.entries(this.fmfIds)) {\n if (fmfId === fieldId) {\n return fieldName;\n }\n }\n }\n return fieldId;\n }\n\n /**\n * Returns true if this BaseTable is using FileMaker field IDs.\n */\n isUsingFieldIds(): boolean {\n return this.fmfIds !== undefined;\n }\n}\n\n/**\n * Creates a BaseTable with proper TypeScript type inference.\n *\n * This function should be used instead of `new BaseTable()` to ensure\n * field names are properly typed throughout the library.\n *\n * @example Without entity IDs\n * ```ts\n * const users = defineBaseTable({\n * schema: { id: z.string(), name: z.string() },\n * idField: \"id\",\n * });\n * ```\n *\n * @example With entity IDs (FileMaker field IDs)\n * ```ts\n * const products = defineBaseTable({\n * schema: { id: z.string(), name: z.string() },\n * idField: \"id\",\n * fmfIds: { id: \"FMFID:1\", name: \"FMFID:2\" },\n * });\n * ```\n */\nexport function defineBaseTable<\n const Schema extends Record<string, StandardSchemaV1>,\n IdField extends keyof Schema | undefined = undefined,\n const Required extends readonly (keyof Schema)[] = readonly [],\n const ReadOnly extends readonly (keyof Schema)[] = readonly [],\n>(config: {\n schema: Schema;\n idField?: IdField;\n required?: Required;\n readOnly?: ReadOnly;\n fmfIds?: { [K in keyof Schema]: `FMFID:${string}` };\n}): BaseTable<Schema, IdField, Required, ReadOnly> {\n return new BaseTable(config);\n}\n"],"names":[],"mappings":";;;AAgEO,MAAM,UAKX;AAAA,EAOA,YAAY,QAMT;AAZa;AACA;AACA;AACA;AACA;AASd,SAAK,SAAS,OAAO;AACrB,SAAK,UAAU,OAAO;AACtB,SAAK,WAAW,OAAO;AACvB,SAAK,WAAW,OAAO;AACvB,SAAK,SAAS,OAAO;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUvB,WAAW,WAAiC;AAC1C,QAAI,KAAK,UAAU,aAAa,KAAK,QAAQ;AACpC,aAAA,KAAK,OAAO,SAAS;AAAA,IAAA;AAE9B,WAAO,OAAO,SAAS;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQzB,aAAa,SAAyB;AACpC,QAAI,KAAK,QAAQ;AAEJ,iBAAA,CAAC,WAAW,KAAK,KAAK,OAAO,QAAQ,KAAK,MAAM,GAAG;AAC5D,YAAI,UAAU,SAAS;AACd,iBAAA;AAAA,QAAA;AAAA,MACT;AAAA,IACF;AAEK,WAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA,EAMT,kBAA2B;AACzB,WAAO,KAAK,WAAW;AAAA,EAAA;AAE3B;AAyBO,SAAS,gBAKd,QAMiD;AAC1C,SAAA,IAAI,UAAU,MAAM;AAC7B;"}
@@ -5,7 +5,7 @@ import { TableOccurrence } from './table-occurrence.js';
5
5
  import { EntitySet } from './entity-set.js';
6
6
  import { BatchBuilder } from './batch-builder.js';
7
7
  import { SchemaManager } from './schema-manager.js';
8
- type ExtractSchemaFromOccurrence<O> = O extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<infer S, any> ? S : never : never;
8
+ type ExtractSchemaFromOccurrence<O> = O extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<infer S, any, any, any> ? S : never : never;
9
9
  type FindOccurrenceByName<Occurrences extends readonly TableOccurrence<any, any, any, any>[], Name extends string> = Occurrences extends readonly [
10
10
  infer First,
11
11
  ...infer Rest extends readonly TableOccurrence<any, any, any, any>[]
@@ -1 +1 @@
1
- {"version":3,"file":"database.js","sources":["../../../src/client/database.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { ExecutionContext, ExecutableBuilder, Metadata } from \"../types\";\nimport type { BaseTable } from \"./base-table\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport { EntitySet } from \"./entity-set\";\nimport { BatchBuilder } from \"./batch-builder\";\nimport { SchemaManager } from \"./schema-manager\";\n\n// Helper type to extract schema from a TableOccurrence\ntype ExtractSchemaFromOccurrence<O> =\n O extends TableOccurrence<infer BT, any, any, any>\n ? BT extends BaseTable<infer S, any>\n ? S\n : never\n : never;\n\n// Helper type to find an occurrence by name in the occurrences tuple\ntype FindOccurrenceByName<\n Occurrences extends readonly TableOccurrence<any, any, any, any>[],\n Name extends string,\n> = Occurrences extends readonly [\n infer First,\n ...infer Rest extends readonly TableOccurrence<any, any, any, any>[],\n]\n ? First extends TableOccurrence<any, any, any, any>\n ? First[\"name\"] extends Name\n ? First\n : FindOccurrenceByName<Rest, Name>\n : never\n : never;\n\n// Helper type to extract all occurrence names from the tuple\ntype ExtractOccurrenceNames<\n Occurrences extends readonly TableOccurrence<any, any, any, any>[],\n> = Occurrences extends readonly []\n ? string // If no occurrences, allow any string\n : Occurrences[number][\"name\"]; // Otherwise, extract union of names\n\nexport class Database<\n Occurrences extends readonly TableOccurrence<\n any,\n any,\n any,\n any\n >[] = readonly [],\n> {\n private occurrenceMap: Map<string, TableOccurrence<any, any, any, any>>;\n private _useEntityIds: boolean = false;\n public readonly schema: SchemaManager;\n\n constructor(\n private readonly databaseName: string,\n private readonly context: ExecutionContext,\n config?: {\n occurrences?: Occurrences | undefined;\n /**\n * Whether to use entity IDs instead of field names in the actual requests to the server\n * Defaults to true if all occurrences use entity IDs, false otherwise\n * If set to false but some occurrences do not use entity IDs, an error will be thrown\n */\n useEntityIds?: boolean;\n },\n ) {\n this.occurrenceMap = new Map();\n if (config?.occurrences) {\n // Validate consistency: either all occurrences use entity IDs or none do\n const occurrencesWithIds: string[] = [];\n const occurrencesWithoutIds: string[] = [];\n\n for (const occ of config.occurrences) {\n this.occurrenceMap.set(occ.name, occ);\n\n const hasTableId = occ.isUsingTableId();\n const hasFieldIds = occ.baseTable.isUsingFieldIds();\n\n // An occurrence uses entity IDs if it has both fmtId and fmfIds\n if (hasTableId && hasFieldIds) {\n occurrencesWithIds.push(occ.name);\n } else if (!hasTableId && !hasFieldIds) {\n occurrencesWithoutIds.push(occ.name);\n } else {\n // Partial entity ID usage (only one of fmtId or fmfIds) - this is an error\n throw new Error(\n `TableOccurrence \"${occ.name}\" has inconsistent entity ID configuration. ` +\n `Both fmtId (${hasTableId ? \"present\" : \"missing\"}) and fmfIds (${hasFieldIds ? \"present\" : \"missing\"}) must be defined together.`,\n );\n }\n }\n\n // Determine default value: true if all occurrences use entity IDs, false otherwise\n const allOccurrencesUseEntityIds =\n occurrencesWithIds.length > 0 && occurrencesWithoutIds.length === 0;\n const hasMixedUsage =\n occurrencesWithIds.length > 0 && occurrencesWithoutIds.length > 0;\n\n // Handle explicit useEntityIds config\n if (config.useEntityIds !== undefined) {\n if (config.useEntityIds === false) {\n // If explicitly set to false, allow mixed usage and use false\n this._useEntityIds = false;\n } else if (config.useEntityIds === true) {\n // If explicitly set to true, validate that all occurrences use entity IDs\n if (hasMixedUsage || occurrencesWithoutIds.length > 0) {\n throw new Error(\n `useEntityIds is set to true but some occurrences do not use entity IDs. ` +\n `Occurrences without entity IDs: [${occurrencesWithoutIds.join(\", \")}]. ` +\n `Either set useEntityIds to false or configure all occurrences with entity IDs.`,\n );\n }\n this._useEntityIds = true;\n }\n } else {\n // Default: true if all occurrences use entity IDs, false otherwise\n // But throw error if there's mixed usage when using defaults\n if (hasMixedUsage) {\n throw new Error(\n `Cannot mix TableOccurrence instances with and without entity IDs in the same database. ` +\n `Occurrences with entity IDs: [${occurrencesWithIds.join(\", \")}]. ` +\n `Occurrences without entity IDs: [${occurrencesWithoutIds.join(\", \")}]. ` +\n `Either all table occurrences must use entity IDs (fmtId + fmfIds), none should, or explicitly set useEntityIds to false.`,\n );\n }\n this._useEntityIds = allOccurrencesUseEntityIds;\n }\n } else {\n // No occurrences provided, use explicit config or default to false\n this._useEntityIds = config?.useEntityIds ?? false;\n }\n\n // Inform the execution context whether to use entity IDs\n if (this.context._setUseEntityIds) {\n this.context._setUseEntityIds(this._useEntityIds);\n }\n\n // Initialize schema manager\n this.schema = new SchemaManager(this.databaseName, this.context);\n }\n\n /**\n * Returns true if any table occurrence in this database is using entity IDs.\n */\n isUsingEntityIds(): boolean {\n return this._useEntityIds;\n }\n\n /**\n * Gets a table occurrence by name.\n * @internal\n */\n getOccurrence(name: string): TableOccurrence<any, any, any, any> | undefined {\n return this.occurrenceMap.get(name);\n }\n\n from<Name extends ExtractOccurrenceNames<Occurrences> | (string & {})>(\n name: Name,\n ): Occurrences extends readonly []\n ? EntitySet<Record<string, StandardSchemaV1>, undefined>\n : Name extends ExtractOccurrenceNames<Occurrences>\n ? EntitySet<\n ExtractSchemaFromOccurrence<FindOccurrenceByName<Occurrences, Name>>,\n FindOccurrenceByName<Occurrences, Name>\n >\n : EntitySet<Record<string, StandardSchemaV1>, undefined> {\n const occurrence = this.occurrenceMap.get(name as string);\n\n if (occurrence) {\n // Use EntitySet.create to preserve types better\n type OccType = FindOccurrenceByName<Occurrences, Name>;\n type SchemaType = ExtractSchemaFromOccurrence<OccType>;\n\n return EntitySet.create<SchemaType, OccType>({\n occurrence: occurrence as any,\n tableName: name as string,\n databaseName: this.databaseName,\n context: this.context,\n database: this as any,\n }) as any;\n } else {\n // Return untyped EntitySet for dynamic table access\n return new EntitySet<Record<string, StandardSchemaV1>, undefined>({\n tableName: name as string,\n databaseName: this.databaseName,\n context: this.context,\n database: this as any,\n }) as any;\n }\n }\n\n /**\n * Retrieves the OData metadata for this database.\n * @param args Optional configuration object\n * @param args.format The format to retrieve metadata in. Defaults to \"json\".\n * @returns The metadata in the specified format\n */\n async getMetadata(args: { format: \"xml\" }): Promise<string>;\n async getMetadata(args?: { format?: \"json\" }): Promise<Metadata>;\n async getMetadata(args?: {\n format?: \"xml\" | \"json\";\n }): Promise<string | Metadata> {\n const result = await this.context._makeRequest<\n Record<string, Metadata> | string\n >(`/${this.databaseName}/$metadata`, {\n headers: {\n Accept: args?.format === \"xml\" ? \"application/xml\" : \"application/json\",\n },\n });\n if (result.error) {\n throw result.error;\n }\n\n if (args?.format === \"json\") {\n const data = result.data as Record<string, Metadata>;\n const metadata = data[this.databaseName];\n if (!metadata) {\n throw new Error(\n `Metadata for database \"${this.databaseName}\" not found in response`,\n );\n }\n return metadata;\n }\n return result.data as string;\n }\n\n /**\n * Lists all available tables (entity sets) in this database.\n * @returns Promise resolving to an array of table names\n */\n async listTableNames(): Promise<string[]> {\n const result = await this.context._makeRequest<{\n value?: Array<{ name: string }>;\n }>(`/${this.databaseName}`);\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 /**\n * Executes a FileMaker script.\n * @param scriptName - The name of the script to execute (must be valid according to OData rules)\n * @param options - Optional script parameter and result schema\n * @returns Promise resolving to script execution result\n */\n async runScript<ResultSchema extends StandardSchemaV1<string, any> = never>(\n scriptName: string,\n options?: {\n scriptParam?: string | number | Record<string, any>;\n resultSchema?: ResultSchema;\n },\n ): Promise<\n [ResultSchema] extends [never]\n ? { resultCode: number; result?: string }\n : ResultSchema extends StandardSchemaV1<string, infer Output>\n ? { resultCode: number; result: Output }\n : { resultCode: number; result?: string }\n > {\n const body: { scriptParameterValue?: unknown } = {};\n if (options?.scriptParam !== undefined) {\n body.scriptParameterValue = options.scriptParam;\n }\n\n const result = await this.context._makeRequest<{\n scriptResult: {\n code: number;\n resultParameter?: string;\n };\n }>(`/${this.databaseName}/Script.${scriptName}`, {\n method: \"POST\",\n body: Object.keys(body).length > 0 ? JSON.stringify(body) : undefined,\n });\n\n if (result.error) {\n throw result.error;\n }\n\n const response = result.data;\n\n // If resultSchema is provided, validate the result through it\n if (options?.resultSchema && response.scriptResult !== undefined) {\n const validationResult = options.resultSchema[\"~standard\"].validate(\n response.scriptResult.resultParameter,\n );\n // Handle both sync and async validation\n const result =\n validationResult instanceof Promise\n ? await validationResult\n : validationResult;\n\n if (result.issues) {\n throw new Error(\n `Script result validation failed: ${JSON.stringify(result.issues)}`,\n );\n }\n\n return {\n resultCode: response.scriptResult.code,\n result: result.value,\n } as any;\n }\n\n return {\n resultCode: response.scriptResult.code,\n result: response.scriptResult.resultParameter,\n } as any;\n }\n\n /**\n * Create a batch operation builder that allows multiple queries to be executed together\n * in a single atomic request. All operations succeed or fail together (transactional).\n *\n * @param builders - Array of executable query builders to batch\n * @returns A BatchBuilder that can be executed\n * @example\n * ```ts\n * const result = await db.batch([\n * db.from('contacts').list().top(5),\n * db.from('users').list().top(5),\n * db.from('contacts').insert({ name: 'John' })\n * ]).execute();\n *\n * if (result.data) {\n * const [contacts, users, insertResult] = result.data;\n * }\n * ```\n */\n batch<const Builders extends readonly ExecutableBuilder<any>[]>(\n builders: Builders,\n ): BatchBuilder<Builders> {\n return new BatchBuilder(builders, this.databaseName, this.context);\n }\n}\n"],"names":["result"],"mappings":"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"}
1
+ {"version":3,"file":"database.js","sources":["../../../src/client/database.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { ExecutionContext, ExecutableBuilder, Metadata } from \"../types\";\nimport type { BaseTable } from \"./base-table\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport { EntitySet } from \"./entity-set\";\nimport { BatchBuilder } from \"./batch-builder\";\nimport { SchemaManager } from \"./schema-manager\";\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 find an occurrence by name in the occurrences tuple\ntype FindOccurrenceByName<\n Occurrences extends readonly TableOccurrence<any, any, any, any>[],\n Name extends string,\n> = Occurrences extends readonly [\n infer First,\n ...infer Rest extends readonly TableOccurrence<any, any, any, any>[],\n]\n ? First extends TableOccurrence<any, any, any, any>\n ? First[\"name\"] extends Name\n ? First\n : FindOccurrenceByName<Rest, Name>\n : never\n : never;\n\n// Helper type to extract all occurrence names from the tuple\ntype ExtractOccurrenceNames<\n Occurrences extends readonly TableOccurrence<any, any, any, any>[],\n> = Occurrences extends readonly []\n ? string // If no occurrences, allow any string\n : Occurrences[number][\"name\"]; // Otherwise, extract union of names\n\nexport class Database<\n Occurrences extends readonly TableOccurrence<\n any,\n any,\n any,\n any\n >[] = readonly [],\n> {\n private occurrenceMap: Map<string, TableOccurrence<any, any, any, any>>;\n private _useEntityIds: boolean = false;\n public readonly schema: SchemaManager;\n\n constructor(\n private readonly databaseName: string,\n private readonly context: ExecutionContext,\n config?: {\n occurrences?: Occurrences | undefined;\n /**\n * Whether to use entity IDs instead of field names in the actual requests to the server\n * Defaults to true if all occurrences use entity IDs, false otherwise\n * If set to false but some occurrences do not use entity IDs, an error will be thrown\n */\n useEntityIds?: boolean;\n },\n ) {\n this.occurrenceMap = new Map();\n if (config?.occurrences) {\n // Validate consistency: either all occurrences use entity IDs or none do\n const occurrencesWithIds: string[] = [];\n const occurrencesWithoutIds: string[] = [];\n\n for (const occ of config.occurrences) {\n this.occurrenceMap.set(occ.name, occ);\n\n const hasTableId = occ.isUsingTableId();\n const hasFieldIds = occ.baseTable.isUsingFieldIds();\n\n // An occurrence uses entity IDs if it has both fmtId and fmfIds\n if (hasTableId && hasFieldIds) {\n occurrencesWithIds.push(occ.name);\n } else if (!hasTableId && !hasFieldIds) {\n occurrencesWithoutIds.push(occ.name);\n } else {\n // Partial entity ID usage (only one of fmtId or fmfIds) - this is an error\n throw new Error(\n `TableOccurrence \"${occ.name}\" has inconsistent entity ID configuration. ` +\n `Both fmtId (${hasTableId ? \"present\" : \"missing\"}) and fmfIds (${hasFieldIds ? \"present\" : \"missing\"}) must be defined together.`,\n );\n }\n }\n\n // Determine default value: true if all occurrences use entity IDs, false otherwise\n const allOccurrencesUseEntityIds =\n occurrencesWithIds.length > 0 && occurrencesWithoutIds.length === 0;\n const hasMixedUsage =\n occurrencesWithIds.length > 0 && occurrencesWithoutIds.length > 0;\n\n // Handle explicit useEntityIds config\n if (config.useEntityIds !== undefined) {\n if (config.useEntityIds === false) {\n // If explicitly set to false, allow mixed usage and use false\n this._useEntityIds = false;\n } else if (config.useEntityIds === true) {\n // If explicitly set to true, validate that all occurrences use entity IDs\n if (hasMixedUsage || occurrencesWithoutIds.length > 0) {\n throw new Error(\n `useEntityIds is set to true but some occurrences do not use entity IDs. ` +\n `Occurrences without entity IDs: [${occurrencesWithoutIds.join(\", \")}]. ` +\n `Either set useEntityIds to false or configure all occurrences with entity IDs.`,\n );\n }\n this._useEntityIds = true;\n }\n } else {\n // Default: true if all occurrences use entity IDs, false otherwise\n // But throw error if there's mixed usage when using defaults\n if (hasMixedUsage) {\n throw new Error(\n `Cannot mix TableOccurrence instances with and without entity IDs in the same database. ` +\n `Occurrences with entity IDs: [${occurrencesWithIds.join(\", \")}]. ` +\n `Occurrences without entity IDs: [${occurrencesWithoutIds.join(\", \")}]. ` +\n `Either all table occurrences must use entity IDs (fmtId + fmfIds), none should, or explicitly set useEntityIds to false.`,\n );\n }\n this._useEntityIds = allOccurrencesUseEntityIds;\n }\n } else {\n // No occurrences provided, use explicit config or default to false\n this._useEntityIds = config?.useEntityIds ?? false;\n }\n\n // Inform the execution context whether to use entity IDs\n if (this.context._setUseEntityIds) {\n this.context._setUseEntityIds(this._useEntityIds);\n }\n\n // Initialize schema manager\n this.schema = new SchemaManager(this.databaseName, this.context);\n }\n\n /**\n * Returns true if any table occurrence in this database is using entity IDs.\n */\n isUsingEntityIds(): boolean {\n return this._useEntityIds;\n }\n\n /**\n * Gets a table occurrence by name.\n * @internal\n */\n getOccurrence(name: string): TableOccurrence<any, any, any, any> | undefined {\n return this.occurrenceMap.get(name);\n }\n\n from<Name extends ExtractOccurrenceNames<Occurrences> | (string & {})>(\n name: Name,\n ): Occurrences extends readonly []\n ? EntitySet<Record<string, StandardSchemaV1>, undefined>\n : Name extends ExtractOccurrenceNames<Occurrences>\n ? EntitySet<\n ExtractSchemaFromOccurrence<FindOccurrenceByName<Occurrences, Name>>,\n FindOccurrenceByName<Occurrences, Name>\n >\n : EntitySet<Record<string, StandardSchemaV1>, undefined> {\n const occurrence = this.occurrenceMap.get(name as string);\n\n if (occurrence) {\n // Use EntitySet.create to preserve types better\n type OccType = FindOccurrenceByName<Occurrences, Name>;\n type SchemaType = ExtractSchemaFromOccurrence<OccType>;\n\n return EntitySet.create<SchemaType, OccType>({\n occurrence: occurrence as OccType,\n tableName: name as string,\n databaseName: this.databaseName,\n context: this.context,\n database: this,\n }) as any;\n } else {\n // Return untyped EntitySet for dynamic table access\n return new EntitySet<Record<string, StandardSchemaV1>, undefined>({\n tableName: name as string,\n databaseName: this.databaseName,\n context: this.context,\n database: this,\n }) as any;\n }\n }\n\n /**\n * Retrieves the OData metadata for this database.\n * @param args Optional configuration object\n * @param args.format The format to retrieve metadata in. Defaults to \"json\".\n * @returns The metadata in the specified format\n */\n async getMetadata(args: { format: \"xml\" }): Promise<string>;\n async getMetadata(args?: { format?: \"json\" }): Promise<Metadata>;\n async getMetadata(args?: {\n format?: \"xml\" | \"json\";\n }): Promise<string | Metadata> {\n const result = await this.context._makeRequest<\n Record<string, Metadata> | string\n >(`/${this.databaseName}/$metadata`, {\n headers: {\n Accept: args?.format === \"xml\" ? \"application/xml\" : \"application/json\",\n },\n });\n if (result.error) {\n throw result.error;\n }\n\n if (args?.format === \"json\") {\n const data = result.data as Record<string, Metadata>;\n const metadata = data[this.databaseName];\n if (!metadata) {\n throw new Error(\n `Metadata for database \"${this.databaseName}\" not found in response`,\n );\n }\n return metadata;\n }\n return result.data as string;\n }\n\n /**\n * Lists all available tables (entity sets) in this database.\n * @returns Promise resolving to an array of table names\n */\n async listTableNames(): Promise<string[]> {\n const result = await this.context._makeRequest<{\n value?: Array<{ name: string }>;\n }>(`/${this.databaseName}`);\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 /**\n * Executes a FileMaker script.\n * @param scriptName - The name of the script to execute (must be valid according to OData rules)\n * @param options - Optional script parameter and result schema\n * @returns Promise resolving to script execution result\n */\n async runScript<ResultSchema extends StandardSchemaV1<string, any> = never>(\n scriptName: string,\n options?: {\n scriptParam?: string | number | Record<string, any>;\n resultSchema?: ResultSchema;\n },\n ): Promise<\n [ResultSchema] extends [never]\n ? { resultCode: number; result?: string }\n : ResultSchema extends StandardSchemaV1<string, infer Output>\n ? { resultCode: number; result: Output }\n : { resultCode: number; result?: string }\n > {\n const body: { scriptParameterValue?: unknown } = {};\n if (options?.scriptParam !== undefined) {\n body.scriptParameterValue = options.scriptParam;\n }\n\n const result = await this.context._makeRequest<{\n scriptResult: {\n code: number;\n resultParameter?: string;\n };\n }>(`/${this.databaseName}/Script.${scriptName}`, {\n method: \"POST\",\n body: Object.keys(body).length > 0 ? JSON.stringify(body) : undefined,\n });\n\n if (result.error) {\n throw result.error;\n }\n\n const response = result.data;\n\n // If resultSchema is provided, validate the result through it\n if (options?.resultSchema && response.scriptResult !== undefined) {\n const validationResult = options.resultSchema[\"~standard\"].validate(\n response.scriptResult.resultParameter,\n );\n // Handle both sync and async validation\n const result =\n validationResult instanceof Promise\n ? await validationResult\n : validationResult;\n\n if (result.issues) {\n throw new Error(\n `Script result validation failed: ${JSON.stringify(result.issues)}`,\n );\n }\n\n return {\n resultCode: response.scriptResult.code,\n result: result.value,\n } as any;\n }\n\n return {\n resultCode: response.scriptResult.code,\n result: response.scriptResult.resultParameter,\n } as any;\n }\n\n /**\n * Create a batch operation builder that allows multiple queries to be executed together\n * in a single atomic request. All operations succeed or fail together (transactional).\n *\n * @param builders - Array of executable query builders to batch\n * @returns A BatchBuilder that can be executed\n * @example\n * ```ts\n * const result = await db.batch([\n * db.from('contacts').list().top(5),\n * db.from('users').list().top(5),\n * db.from('contacts').insert({ name: 'John' })\n * ]).execute();\n *\n * if (result.data) {\n * const [contacts, users, insertResult] = result.data;\n * }\n * ```\n */\n batch<const Builders extends readonly ExecutableBuilder<any>[]>(\n builders: Builders,\n ): BatchBuilder<Builders> {\n return new BatchBuilder(builders, this.databaseName, this.context);\n }\n}\n"],"names":["result"],"mappings":"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"}
@@ -9,8 +9,8 @@ import { DeleteBuilder } from './delete-builder.js';
9
9
  import { UpdateBuilder } from './update-builder.js';
10
10
  import { Database } from './database.js';
11
11
  type ExtractNavigationNames<O extends TableOccurrence<any, any, any, any> | undefined> = O extends TableOccurrence<any, any, infer Nav, any> ? Nav extends Record<string, any> ? keyof Nav & string : never : never;
12
- type ExtractSchemaFromOccurrence<O> = O extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<infer S, any> ? S : never : never;
13
- type ExtractDefaultSelect<O> = O extends TableOccurrence<infer BT, any, any, infer DefSelect> ? BT extends BaseTable<infer S, any> ? DefSelect extends "all" ? keyof S : DefSelect extends "schema" ? keyof S : DefSelect extends readonly (infer K)[] ? K & keyof S : keyof S : never : never;
12
+ type ExtractSchemaFromOccurrence<O> = O extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<infer S, any, any, any> ? S : never : never;
13
+ type ExtractDefaultSelect<O> = O extends TableOccurrence<infer BT, any, any, infer DefSelect> ? BT extends BaseTable<infer S, any, any, any> ? DefSelect extends "all" ? keyof S : DefSelect extends "schema" ? keyof S : DefSelect extends readonly (infer K)[] ? K & keyof S : keyof S : never : never;
14
14
  type ResolveNavigationItem<T> = T extends () => infer R ? R : T;
15
15
  type FindNavigationTarget<O extends TableOccurrence<any, any, any, any> | undefined, Name extends string> = O extends TableOccurrence<any, any, infer Nav, any> ? Nav extends Record<string, any> ? Name extends keyof Nav ? ResolveNavigationItem<Nav[Name]> : TableOccurrence<BaseTable<Record<string, StandardSchemaV1>, any, any, any>, any, any, any> : TableOccurrence<BaseTable<Record<string, StandardSchemaV1>, any, any, any>, any, any, any> : TableOccurrence<BaseTable<Record<string, StandardSchemaV1>, any, any, any>, any, any, any>;
16
16
  export declare class EntitySet<Schema extends Record<string, StandardSchemaV1> = any, Occ extends TableOccurrence<any, any, any, any> | undefined = undefined> {
@@ -48,12 +48,12 @@ class EntitySet {
48
48
  const schema = this.occurrence.baseTable.schema;
49
49
  const fields = Object.keys(schema);
50
50
  const uniqueFields = [...new Set(fields)];
51
- return builder.select(...uniqueFields);
51
+ return builder.select(...uniqueFields).top(1e3);
52
52
  } else if (Array.isArray(defaultSelect)) {
53
53
  const uniqueFields = [
54
54
  ...new Set(defaultSelect)
55
55
  ];
56
- return builder.select(...uniqueFields);
56
+ return builder.select(...uniqueFields).top(1e3);
57
57
  }
58
58
  }
59
59
  if (this.isNavigateFromEntitySet) {
@@ -61,7 +61,7 @@ class EntitySet {
61
61
  builder.navigateRelation = this.navigateRelation;
62
62
  builder.navigateSourceTableName = this.navigateSourceTableName;
63
63
  }
64
- return builder;
64
+ return builder.top(1e3);
65
65
  }
66
66
  get(id) {
67
67
  var _a;
@@ -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>\n ? S\n : never\n : never;\n\n// Helper type to extract defaultSelect from a TableOccurrence\ntype ExtractDefaultSelect<O> =\n O extends TableOccurrence<infer BT, any, any, infer DefSelect>\n ? BT extends BaseTable<infer S, any>\n ? DefSelect extends \"all\"\n ? keyof S\n : DefSelect extends \"schema\"\n ? keyof S\n : DefSelect extends readonly (infer K)[]\n ? K & keyof S\n : keyof S\n : never\n : never;\n\n// Helper type to resolve a navigation item (handles both direct and lazy-loaded)\ntype ResolveNavigationItem<T> = T extends () => infer R ? R : T;\n\n// Helper type to find target occurrence by relation name\ntype FindNavigationTarget<\n O extends TableOccurrence<any, any, any, any> | undefined,\n Name extends string,\n> =\n O extends TableOccurrence<any, any, infer Nav, any>\n ? Nav extends Record<string, any>\n ? Name extends keyof Nav\n ? ResolveNavigationItem<Nav[Name]>\n : TableOccurrence<\n BaseTable<Record<string, 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>]\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\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);\n } else if (Array.isArray(defaultSelect)) {\n // Use the provided field names, deduplicated\n const uniqueFields = [\n ...new Set(defaultSelect),\n ] as (keyof InferSchemaType<Schema>)[];\n return builder.select(...uniqueFields);\n }\n // If defaultSelect is \"all\", no changes needed (current behavior)\n }\n\n // Propagate navigation context if present\n if (this.isNavigateFromEntitySet) {\n (builder as any).isNavigate = true;\n (builder as any).navigateRelation = this.navigateRelation;\n (builder as any).navigateSourceTableName = this.navigateSourceTableName;\n // navigateRecordId is intentionally not set (undefined) to indicate navigation from EntitySet\n }\n return builder;\n }\n\n get(\n id: string | number,\n ): RecordBuilder<\n InferSchemaType<Schema>,\n false,\n keyof InferSchemaType<Schema>,\n Occ\n > {\n const builder = new RecordBuilder<\n InferSchemaType<Schema>,\n false,\n keyof InferSchemaType<Schema>,\n Occ\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n recordId: id,\n databaseUseEntityIds: this.database?.isUsingEntityIds() ?? false,\n });\n // Propagate navigation context if present\n if (this.isNavigateFromEntitySet) {\n (builder as any).isNavigateFromEntitySet = true;\n (builder as any).navigateRelation = this.navigateRelation;\n (builder as any).navigateSourceTableName = this.navigateSourceTableName;\n }\n return builder;\n }\n\n // 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 (entitySet as any).navigateSourceTableName = this.tableName;\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 {\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 resolve a navigation item (handles both direct and lazy-loaded)\ntype ResolveNavigationItem<T> = T extends () => infer R ? R : T;\n\n// Helper type to find target occurrence by relation name\ntype FindNavigationTarget<\n O extends TableOccurrence<any, any, any, any> | undefined,\n Name extends string,\n> =\n O extends TableOccurrence<any, any, infer Nav, any>\n ? Nav extends Record<string, any>\n ? Name extends keyof Nav\n ? ResolveNavigationItem<Nav[Name]>\n : TableOccurrence<\n BaseTable<Record<string, 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\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 // 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 > {\n const builder = new RecordBuilder<\n InferSchemaType<Schema>,\n false,\n keyof InferSchemaType<Schema>,\n Occ\n >({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n recordId: id,\n databaseUseEntityIds: this.database?.isUsingEntityIds() ?? false,\n });\n // Propagate navigation context if present\n if (this.isNavigateFromEntitySet) {\n (builder as any).isNavigateFromEntitySet = true;\n (builder as any).navigateRelation = this.navigateRelation;\n (builder as any).navigateSourceTableName = this.navigateSourceTableName;\n }\n return builder;\n }\n\n // 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 (entitySet as any).navigateSourceTableName = this.tableName;\n return entitySet;\n }\n}\n"],"names":[],"mappings":";;;;;;;;AA8FO,MAAM,UAGX;AAAA,EAUA,YAAY,QAMT;AAfK;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AASN,SAAK,aAAa,OAAO;AACzB,SAAK,YAAY,OAAO;AACxB,SAAK,eAAe,OAAO;AAC3B,SAAK,UAAU,OAAO;AACtB,SAAK,WAAW,OAAO;AAAA,EAAA;AAAA;AAAA,EAIzB,OAAO,OAUL,QAMmC;AACnC,WAAO,IAAI,UAAiC;AAAA,MAC1C,YAAY,OAAO;AAAA,MACnB,WAAW,OAAO;AAAA,MAClB,cAAc,OAAO;AAAA,MACrB,SAAS,OAAO;AAAA,MAChB,UAAU,OAAO;AAAA,IAAA,CAClB;AAAA,EAAA;AAAA,EAGH,OAQE;;AACM,UAAA,UAAU,IAAI,aAQlB;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,wBAAsB,UAAK,aAAL,mBAAe,uBAAsB;AAAA,IAAA,CAC5D;AAGD,QAAI,KAAK,YAAY;AACb,YAAA,gBAAgB,KAAK,WAAW;AAEtC,UAAI,kBAAkB,UAAU;AAExB,cAAA,SAAS,KAAK,WAAW,UAAU;AACnC,cAAA,SAAS,OAAO,KAAK,MAAM;AAEjC,cAAM,eAAe,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC;AACxC,eAAO,QAAQ,OAAO,GAAG,YAAY,EAAE,IAAI,GAAI;AAAA,MACtC,WAAA,MAAM,QAAQ,aAAa,GAAG;AAEvC,cAAM,eAAe;AAAA,UACnB,GAAG,IAAI,IAAI,aAAa;AAAA,QAC1B;AACA,eAAO,QAAQ,OAAO,GAAG,YAAY,EAAE,IAAI,GAAI;AAAA,MAAA;AAAA,IACjD;AAKF,QAAI,KAAK,yBAAyB;AAC/B,cAAgB,aAAa;AAC7B,cAAgB,mBAAmB,KAAK;AACxC,cAAgB,0BAA0B,KAAK;AAAA,IAAA;AAM3C,WAAA,QAAQ,IAAI,GAAI;AAAA,EAAA;AAAA,EAGzB,IACE,IAMA;;AACM,UAAA,UAAU,IAAI,cAKlB;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,UAAU;AAAA,MACV,wBAAsB,UAAK,aAAL,mBAAe,uBAAsB;AAAA,IAAA,CAC5D;AAED,QAAI,KAAK,yBAAyB;AAC/B,cAAgB,0BAA0B;AAC1C,cAAgB,mBAAmB,KAAK;AACxC,cAAgB,0BAA0B,KAAK;AAAA,IAAA;AAE3C,WAAA;AAAA,EAAA;AAAA;AAAA,EAwBT,OACE,MAKA,SAC2E;;AAC3E,UAAM,cACJ,mCAAS,sBAAqB,QAAQ,YAAY;AACpD,WAAO,IAAI,cAA+D;AAAA,MACxE,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd;AAAA,MACA,kBAAkB;AAAA,MAClB,wBAAsB,UAAK,aAAL,mBAAe,uBAAsB;AAAA,IAAA,CAC5D;AAAA,EAAA;AAAA;AAAA,EAwCH,OACE,MAKA,SASA;;AACA,UAAM,cACJ,mCAAS,sBAAqB,OAAO,mBAAmB;AAC1D,WAAO,IAAI,cAQT;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd;AAAA,MACA,kBAAkB;AAAA,MAClB,wBAAsB,UAAK,aAAL,mBAAe,uBAAsB;AAAA,IAAA,CAC5D;AAAA,EAAA;AAAA,EAGH,SAAiD;;AAC/C,WAAO,IAAI,cAAuC;AAAA,MAChD,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,MACd,wBAAsB,UAAK,aAAL,mBAAe,uBAAsB;AAAA,IAAA,CAC5D;AAAA,EAAA;AAAA;AAAA,EAmBH,SAAS,cAA2C;;AAGlD,UAAM,oBAAmB,UAAK,eAAL,mBAAiB,WAAW;AAC/C,UAAA,YAAY,IAAI,UAAoB;AAAA,MACxC,YAAY;AAAA,MACZ,YAAW,qDAAkB,SAAQ;AAAA,MACrC,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAAA,CACf;AAGA,cAAkB,0BAA0B;AAC5C,cAAkB,mBAAmB;AACrC,cAAkB,0BAA0B,KAAK;AAC3C,WAAA;AAAA,EAAA;AAEX;"}
@@ -10,7 +10,7 @@ type ResolveNavigationItem<T> = T extends () => infer R ? R : T;
10
10
  type FindNavigationTarget<O extends TableOccurrence<any, any, any, any> | undefined, Name extends string> = O extends TableOccurrence<any, any, infer Nav, any> ? Nav extends Record<string, any> ? Name extends keyof Nav ? ResolveNavigationItem<Nav[Name]> : TableOccurrence<BaseTable<Record<string, StandardSchemaV1>, any, any, any>, any, any, any> : TableOccurrence<BaseTable<Record<string, StandardSchemaV1>, any, any, any>, any, any, any> : TableOccurrence<BaseTable<Record<string, StandardSchemaV1>, any, any, any>, any, any, any>;
11
11
  type GetTargetSchemaType<O extends TableOccurrence<any, any, any, any> | undefined, Rel extends string> = [FindNavigationTarget<O, Rel>] extends [
12
12
  TableOccurrence<infer BT, any, any, any>
13
- ] ? [BT] extends [BaseTable<infer S, any>] ? [S] extends [Record<string, StandardSchemaV1>] ? InferSchemaType<S> : Record<string, any> : Record<string, any> : Record<string, any>;
13
+ ] ? [BT] extends [BaseTable<infer S, any, any, any>] ? [S] extends [Record<string, StandardSchemaV1>] ? InferSchemaType<S> : Record<string, any> : Record<string, any> : Record<string, any>;
14
14
  export type ExpandedRelations = Record<string, {
15
15
  schema: any;
16
16
  selected: any;
@@ -186,10 +186,6 @@ class QueryBuilder {
186
186
  }
187
187
  top(count) {
188
188
  this.queryOptions.top = count;
189
- console.log("top method", {
190
- count,
191
- databaseUseEntityIds: this.databaseUseEntityIds
192
- });
193
189
  return this;
194
190
  }
195
191
  skip(count) {
@@ -684,11 +680,13 @@ class QueryBuilder {
684
680
  }
685
681
  }
686
682
  getQueryString() {
683
+ var _a;
687
684
  const queryOptionsWithoutExpand = { ...this.queryOptions };
688
685
  delete queryOptionsWithoutExpand.expand;
689
686
  if (queryOptionsWithoutExpand.select) {
690
687
  queryOptionsWithoutExpand.select = this.formatSelectFields(
691
- queryOptionsWithoutExpand.select
688
+ queryOptionsWithoutExpand.select,
689
+ (_a = this.occurrence) == null ? void 0 : _a.baseTable
692
690
  );
693
691
  }
694
692
  let queryParams = buildQuery(queryOptionsWithoutExpand);
@@ -721,11 +719,13 @@ class QueryBuilder {
721
719
  return `/${this.tableName}${queryParams}`;
722
720
  }
723
721
  getRequestConfig() {
722
+ var _a;
724
723
  const queryOptionsWithoutExpand = { ...this.queryOptions };
725
724
  delete queryOptionsWithoutExpand.expand;
726
725
  if (queryOptionsWithoutExpand.select) {
727
726
  queryOptionsWithoutExpand.select = this.formatSelectFields(
728
- queryOptionsWithoutExpand.select
727
+ queryOptionsWithoutExpand.select,
728
+ (_a = this.occurrence) == null ? void 0 : _a.baseTable
729
729
  );
730
730
  }
731
731
  let queryString = buildQuery(queryOptionsWithoutExpand);