@proofkit/fmodata 0.1.0-alpha.9 → 0.1.0-beta.24

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.
Files changed (163) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +655 -453
  3. package/dist/esm/client/batch-builder.d.ts +10 -9
  4. package/dist/esm/client/batch-builder.js +119 -56
  5. package/dist/esm/client/batch-builder.js.map +1 -1
  6. package/dist/esm/client/batch-request.js +16 -21
  7. package/dist/esm/client/batch-request.js.map +1 -1
  8. package/dist/esm/client/builders/default-select.d.ts +10 -0
  9. package/dist/esm/client/builders/default-select.js +41 -0
  10. package/dist/esm/client/builders/default-select.js.map +1 -0
  11. package/dist/esm/client/builders/expand-builder.d.ts +45 -0
  12. package/dist/esm/client/builders/expand-builder.js +185 -0
  13. package/dist/esm/client/builders/expand-builder.js.map +1 -0
  14. package/dist/esm/client/builders/index.d.ts +9 -0
  15. package/dist/esm/client/builders/query-string-builder.d.ts +18 -0
  16. package/dist/esm/client/builders/query-string-builder.js +21 -0
  17. package/dist/esm/client/builders/query-string-builder.js.map +1 -0
  18. package/dist/esm/client/builders/response-processor.d.ts +43 -0
  19. package/dist/esm/client/builders/response-processor.js +175 -0
  20. package/dist/esm/client/builders/response-processor.js.map +1 -0
  21. package/dist/esm/client/builders/select-mixin.d.ts +25 -0
  22. package/dist/esm/client/builders/select-mixin.js +28 -0
  23. package/dist/esm/client/builders/select-mixin.js.map +1 -0
  24. package/dist/esm/client/builders/select-utils.d.ts +18 -0
  25. package/dist/esm/client/builders/select-utils.js +30 -0
  26. package/dist/esm/client/builders/select-utils.js.map +1 -0
  27. package/dist/esm/client/builders/shared-types.d.ts +40 -0
  28. package/dist/esm/client/builders/table-utils.d.ts +35 -0
  29. package/dist/esm/client/builders/table-utils.js +44 -0
  30. package/dist/esm/client/builders/table-utils.js.map +1 -0
  31. package/dist/esm/client/database.d.ts +34 -22
  32. package/dist/esm/client/database.js +48 -84
  33. package/dist/esm/client/database.js.map +1 -1
  34. package/dist/esm/client/delete-builder.d.ts +25 -30
  35. package/dist/esm/client/delete-builder.js +45 -30
  36. package/dist/esm/client/delete-builder.js.map +1 -1
  37. package/dist/esm/client/entity-set.d.ts +35 -43
  38. package/dist/esm/client/entity-set.js +126 -52
  39. package/dist/esm/client/entity-set.js.map +1 -1
  40. package/dist/esm/client/error-parser.d.ts +12 -0
  41. package/dist/esm/client/error-parser.js +25 -0
  42. package/dist/esm/client/error-parser.js.map +1 -0
  43. package/dist/esm/client/filemaker-odata.d.ts +26 -7
  44. package/dist/esm/client/filemaker-odata.js +65 -42
  45. package/dist/esm/client/filemaker-odata.js.map +1 -1
  46. package/dist/esm/client/insert-builder.d.ts +19 -24
  47. package/dist/esm/client/insert-builder.js +94 -58
  48. package/dist/esm/client/insert-builder.js.map +1 -1
  49. package/dist/esm/client/query/expand-builder.d.ts +35 -0
  50. package/dist/esm/client/query/index.d.ts +4 -0
  51. package/dist/esm/client/query/query-builder.d.ts +132 -0
  52. package/dist/esm/client/query/query-builder.js +456 -0
  53. package/dist/esm/client/query/query-builder.js.map +1 -0
  54. package/dist/esm/client/query/response-processor.d.ts +25 -0
  55. package/dist/esm/client/query/types.d.ts +77 -0
  56. package/dist/esm/client/query/url-builder.d.ts +71 -0
  57. package/dist/esm/client/query/url-builder.js +100 -0
  58. package/dist/esm/client/query/url-builder.js.map +1 -0
  59. package/dist/esm/client/query-builder.d.ts +2 -115
  60. package/dist/esm/client/record-builder.d.ts +108 -36
  61. package/dist/esm/client/record-builder.js +284 -119
  62. package/dist/esm/client/record-builder.js.map +1 -1
  63. package/dist/esm/client/response-processor.d.ts +4 -9
  64. package/dist/esm/client/sanitize-json.d.ts +35 -0
  65. package/dist/esm/client/sanitize-json.js +27 -0
  66. package/dist/esm/client/sanitize-json.js.map +1 -0
  67. package/dist/esm/client/schema-manager.d.ts +5 -5
  68. package/dist/esm/client/schema-manager.js +45 -31
  69. package/dist/esm/client/schema-manager.js.map +1 -1
  70. package/dist/esm/client/update-builder.d.ts +34 -40
  71. package/dist/esm/client/update-builder.js +99 -58
  72. package/dist/esm/client/update-builder.js.map +1 -1
  73. package/dist/esm/client/webhook-builder.d.ts +126 -0
  74. package/dist/esm/client/webhook-builder.js +189 -0
  75. package/dist/esm/client/webhook-builder.js.map +1 -0
  76. package/dist/esm/errors.d.ts +19 -2
  77. package/dist/esm/errors.js +39 -4
  78. package/dist/esm/errors.js.map +1 -1
  79. package/dist/esm/index.d.ts +10 -8
  80. package/dist/esm/index.js +40 -10
  81. package/dist/esm/index.js.map +1 -1
  82. package/dist/esm/logger.d.ts +47 -0
  83. package/dist/esm/logger.js +69 -0
  84. package/dist/esm/logger.js.map +1 -0
  85. package/dist/esm/logger.test.d.ts +1 -0
  86. package/dist/esm/orm/column.d.ts +62 -0
  87. package/dist/esm/orm/column.js +63 -0
  88. package/dist/esm/orm/column.js.map +1 -0
  89. package/dist/esm/orm/field-builders.d.ts +164 -0
  90. package/dist/esm/orm/field-builders.js +158 -0
  91. package/dist/esm/orm/field-builders.js.map +1 -0
  92. package/dist/esm/orm/index.d.ts +5 -0
  93. package/dist/esm/orm/operators.d.ts +173 -0
  94. package/dist/esm/orm/operators.js +260 -0
  95. package/dist/esm/orm/operators.js.map +1 -0
  96. package/dist/esm/orm/table.d.ts +355 -0
  97. package/dist/esm/orm/table.js +202 -0
  98. package/dist/esm/orm/table.js.map +1 -0
  99. package/dist/esm/transform.d.ts +20 -21
  100. package/dist/esm/transform.js +44 -45
  101. package/dist/esm/transform.js.map +1 -1
  102. package/dist/esm/types.d.ts +96 -30
  103. package/dist/esm/types.js +7 -0
  104. package/dist/esm/types.js.map +1 -0
  105. package/dist/esm/validation.d.ts +22 -12
  106. package/dist/esm/validation.js +132 -85
  107. package/dist/esm/validation.js.map +1 -1
  108. package/package.json +34 -29
  109. package/src/client/batch-builder.ts +153 -89
  110. package/src/client/batch-request.ts +25 -41
  111. package/src/client/builders/default-select.ts +75 -0
  112. package/src/client/builders/expand-builder.ts +246 -0
  113. package/src/client/builders/index.ts +11 -0
  114. package/src/client/builders/query-string-builder.ts +46 -0
  115. package/src/client/builders/response-processor.ts +279 -0
  116. package/src/client/builders/select-mixin.ts +65 -0
  117. package/src/client/builders/select-utils.ts +59 -0
  118. package/src/client/builders/shared-types.ts +45 -0
  119. package/src/client/builders/table-utils.ts +83 -0
  120. package/src/client/database.ts +89 -183
  121. package/src/client/delete-builder.ts +74 -84
  122. package/src/client/entity-set.ts +286 -293
  123. package/src/client/error-parser.ts +41 -0
  124. package/src/client/filemaker-odata.ts +98 -66
  125. package/src/client/insert-builder.ts +157 -118
  126. package/src/client/query/expand-builder.ts +160 -0
  127. package/src/client/query/index.ts +14 -0
  128. package/src/client/query/query-builder.ts +729 -0
  129. package/src/client/query/response-processor.ts +226 -0
  130. package/src/client/query/types.ts +126 -0
  131. package/src/client/query/url-builder.ts +151 -0
  132. package/src/client/query-builder.ts +10 -1455
  133. package/src/client/record-builder.ts +575 -240
  134. package/src/client/response-processor.ts +15 -42
  135. package/src/client/sanitize-json.ts +64 -0
  136. package/src/client/schema-manager.ts +61 -76
  137. package/src/client/update-builder.ts +161 -143
  138. package/src/client/webhook-builder.ts +265 -0
  139. package/src/errors.ts +49 -16
  140. package/src/index.ts +99 -54
  141. package/src/logger.test.ts +34 -0
  142. package/src/logger.ts +116 -0
  143. package/src/orm/column.ts +106 -0
  144. package/src/orm/field-builders.ts +250 -0
  145. package/src/orm/index.ts +61 -0
  146. package/src/orm/operators.ts +473 -0
  147. package/src/orm/table.ts +741 -0
  148. package/src/transform.ts +90 -70
  149. package/src/types.ts +154 -113
  150. package/src/validation.ts +200 -115
  151. package/dist/esm/client/base-table.d.ts +0 -125
  152. package/dist/esm/client/base-table.js +0 -57
  153. package/dist/esm/client/base-table.js.map +0 -1
  154. package/dist/esm/client/query-builder.js +0 -896
  155. package/dist/esm/client/query-builder.js.map +0 -1
  156. package/dist/esm/client/table-occurrence.d.ts +0 -72
  157. package/dist/esm/client/table-occurrence.js +0 -74
  158. package/dist/esm/client/table-occurrence.js.map +0 -1
  159. package/dist/esm/filter-types.d.ts +0 -76
  160. package/src/client/base-table.ts +0 -175
  161. package/src/client/query-builder.ts.bak +0 -1457
  162. package/src/client/table-occurrence.ts +0 -175
  163. package/src/filter-types.ts +0 -97
@@ -1,28 +1,29 @@
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";
5
- import { getTableIdentifiers } from "../transform.js";
4
+ import { isUsingEntityIds, getTableName, getTableId } from "../orm/table.js";
5
+ import { getAcceptHeader } from "../types.js";
6
+ import { parseErrorResponse } from "./error-parser.js";
7
+ import { QueryBuilder } from "./query/query-builder.js";
6
8
  class DeleteBuilder {
7
9
  constructor(config) {
8
- __publicField(this, "tableName");
9
10
  __publicField(this, "databaseName");
10
11
  __publicField(this, "context");
11
- __publicField(this, "occurrence");
12
+ __publicField(this, "table");
12
13
  __publicField(this, "databaseUseEntityIds");
13
- this.occurrence = config.occurrence;
14
- this.tableName = config.tableName;
14
+ __publicField(this, "databaseIncludeSpecialColumns");
15
+ this.table = config.occurrence;
15
16
  this.databaseName = config.databaseName;
16
17
  this.context = config.context;
17
18
  this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;
19
+ this.databaseIncludeSpecialColumns = config.databaseIncludeSpecialColumns ?? false;
18
20
  }
19
21
  /**
20
22
  * Delete a single record by ID
21
23
  */
22
24
  byId(id) {
23
25
  return new ExecutableDeleteBuilder({
24
- occurrence: this.occurrence,
25
- tableName: this.tableName,
26
+ occurrence: this.table,
26
27
  databaseName: this.databaseName,
27
28
  context: this.context,
28
29
  mode: "byId",
@@ -36,15 +37,13 @@ class DeleteBuilder {
36
37
  */
37
38
  where(fn) {
38
39
  const queryBuilder = new QueryBuilder({
39
- occurrence: void 0,
40
- tableName: this.tableName,
40
+ occurrence: this.table,
41
41
  databaseName: this.databaseName,
42
42
  context: this.context
43
43
  });
44
44
  const configuredBuilder = fn(queryBuilder);
45
45
  return new ExecutableDeleteBuilder({
46
- occurrence: this.occurrence,
47
- tableName: this.tableName,
46
+ occurrence: this.table,
48
47
  databaseName: this.databaseName,
49
48
  context: this.context,
50
49
  mode: "byFilter",
@@ -55,16 +54,14 @@ class DeleteBuilder {
55
54
  }
56
55
  class ExecutableDeleteBuilder {
57
56
  constructor(config) {
58
- __publicField(this, "tableName");
59
57
  __publicField(this, "databaseName");
60
58
  __publicField(this, "context");
61
- __publicField(this, "occurrence");
59
+ __publicField(this, "table");
62
60
  __publicField(this, "mode");
63
61
  __publicField(this, "recordId");
64
62
  __publicField(this, "queryBuilder");
65
63
  __publicField(this, "databaseUseEntityIds");
66
- this.occurrence = config.occurrence;
67
- this.tableName = config.tableName;
64
+ this.table = config.occurrence;
68
65
  this.databaseName = config.databaseName;
69
66
  this.context = config.context;
70
67
  this.mode = config.mode;
@@ -87,21 +84,17 @@ class ExecutableDeleteBuilder {
87
84
  */
88
85
  getTableId(useEntityIds) {
89
86
  var _a, _b;
90
- if (!this.occurrence) {
91
- return this.tableName;
92
- }
93
87
  const contextDefault = ((_b = (_a = this.context)._getUseEntityIds) == null ? void 0 : _b.call(_a)) ?? false;
94
88
  const shouldUseIds = useEntityIds ?? contextDefault;
95
89
  if (shouldUseIds) {
96
- const identifiers = getTableIdentifiers(this.occurrence);
97
- if (!identifiers.id) {
90
+ if (!isUsingEntityIds(this.table)) {
98
91
  throw new Error(
99
- `useEntityIds is true but TableOccurrence "${identifiers.name}" does not have an fmtId defined`
92
+ `useEntityIds is true but table "${getTableName(this.table)}" does not have entity IDs configured`
100
93
  );
101
94
  }
102
- return identifiers.id;
95
+ return getTableId(this.table);
103
96
  }
104
- return this.occurrence.getTableName();
97
+ return getTableName(this.table);
105
98
  }
106
99
  async execute(options) {
107
100
  const mergedOptions = this.mergeExecuteOptions(options);
@@ -114,7 +107,15 @@ class ExecutableDeleteBuilder {
114
107
  throw new Error("Query builder is required for filter-based delete");
115
108
  }
116
109
  const queryString = this.queryBuilder.getQueryString();
117
- const queryParams = queryString.startsWith(`/${tableId}`) ? queryString.slice(`/${tableId}`.length) : queryString.startsWith(`/${this.tableName}`) ? queryString.slice(`/${this.tableName}`.length) : queryString;
110
+ const tableName = getTableName(this.table);
111
+ let queryParams;
112
+ if (queryString.startsWith(`/${tableId}`)) {
113
+ queryParams = queryString.slice(`/${tableId}`.length);
114
+ } else if (queryString.startsWith(`/${tableName}`)) {
115
+ queryParams = queryString.slice(`/${tableName}`.length);
116
+ } else {
117
+ queryParams = queryString;
118
+ }
118
119
  url = `/${this.databaseName}/${tableId}${queryParams}`;
119
120
  }
120
121
  const result = await this.context._makeRequest(url, {
@@ -133,6 +134,7 @@ class ExecutableDeleteBuilder {
133
134
  }
134
135
  return { data: { deletedCount }, error: void 0 };
135
136
  }
137
+ // biome-ignore lint/suspicious/noExplicitAny: Request body can be any JSON-serializable value
136
138
  getRequestConfig() {
137
139
  const tableId = this.getTableId(this.databaseUseEntityIds);
138
140
  let url;
@@ -143,7 +145,15 @@ class ExecutableDeleteBuilder {
143
145
  throw new Error("Query builder is required for filter-based delete");
144
146
  }
145
147
  const queryString = this.queryBuilder.getQueryString();
146
- const queryParams = queryString.startsWith(`/${tableId}`) ? queryString.slice(`/${tableId}`.length) : queryString.startsWith(`/${this.tableName}`) ? queryString.slice(`/${this.tableName}`.length) : queryString;
148
+ const tableName = getTableName(this.table);
149
+ let queryParams;
150
+ if (queryString.startsWith(`/${tableId}`)) {
151
+ queryParams = queryString.slice(`/${tableId}`.length);
152
+ } else if (queryString.startsWith(`/${tableName}`)) {
153
+ queryParams = queryString.slice(`/${tableName}`.length);
154
+ } else {
155
+ queryParams = queryString;
156
+ }
147
157
  url = `/${this.databaseName}/${tableId}${queryParams}`;
148
158
  }
149
159
  return {
@@ -151,21 +161,26 @@ class ExecutableDeleteBuilder {
151
161
  url
152
162
  };
153
163
  }
154
- toRequest(baseUrl) {
164
+ toRequest(baseUrl, options) {
155
165
  const config = this.getRequestConfig();
156
166
  const fullUrl = `${baseUrl}${config.url}`;
157
167
  return new Request(fullUrl, {
158
168
  method: config.method,
159
169
  headers: {
160
- Accept: "application/json"
170
+ Accept: getAcceptHeader(options == null ? void 0 : options.includeODataAnnotations)
161
171
  }
162
172
  });
163
173
  }
164
- async processResponse(response, options) {
174
+ async processResponse(response, _options) {
175
+ if (!response.ok) {
176
+ const tableName = getTableName(this.table);
177
+ const error = await parseErrorResponse(response, response.url || `/${this.databaseName}/${tableName}`);
178
+ return { data: void 0, error };
179
+ }
165
180
  const text = await response.text();
166
181
  if (!text || text.trim() === "") {
167
182
  const affectedRows = response.headers.get("fmodata.affected_rows");
168
- const deletedCount2 = affectedRows ? parseInt(affectedRows, 10) : 1;
183
+ const deletedCount2 = affectedRows ? Number.parseInt(affectedRows, 10) : 1;
169
184
  return { data: { deletedCount: deletedCount2 }, error: void 0 };
170
185
  }
171
186
  const rawResponse = JSON.parse(text);
@@ -1 +1 @@
1
- {"version":3,"file":"delete-builder.js","sources":["../../../src/client/delete-builder.ts"],"sourcesContent":["import type {\n ExecutionContext,\n ExecutableBuilder,\n Result,\n WithSystemFields,\n ExecuteOptions,\n} from \"../types\";\nimport type { TableOccurrence } from \"./table-occurrence\";\nimport { QueryBuilder } from \"./query-builder\";\nimport { type FFetchOptions } from \"@fetchkit/ffetch\";\nimport { getTableIdentifiers } from \"../transform\";\n\n/**\n * Initial delete builder returned from EntitySet.delete()\n * Requires calling .byId() or .where() before .execute() is available\n */\nexport class DeleteBuilder<T extends Record<string, any>> {\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private occurrence?: TableOccurrence<any, any, any, any>;\n private databaseUseEntityIds: boolean;\n\n constructor(config: {\n occurrence?: TableOccurrence<any, any, any, any>;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n databaseUseEntityIds?: boolean;\n }) {\n this.occurrence = config.occurrence;\n this.tableName = config.tableName;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;\n }\n\n /**\n * Delete a single record by ID\n */\n byId(id: string | number): ExecutableDeleteBuilder<T> {\n return new ExecutableDeleteBuilder<T>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n mode: \"byId\",\n recordId: id,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n }\n\n /**\n * Delete records matching a filter query\n * @param fn Callback that receives a QueryBuilder for building the filter\n */\n where(\n fn: (\n q: QueryBuilder<WithSystemFields<T>>,\n ) => QueryBuilder<WithSystemFields<T>>,\n ): ExecutableDeleteBuilder<T> {\n // Create a QueryBuilder for the user to configure\n const queryBuilder = new QueryBuilder<\n WithSystemFields<T>,\n keyof WithSystemFields<T>,\n false,\n false,\n undefined\n >({\n occurrence: undefined,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n });\n\n // Let the user configure it\n const configuredBuilder = fn(queryBuilder);\n\n return new ExecutableDeleteBuilder<T>({\n occurrence: this.occurrence,\n tableName: this.tableName,\n databaseName: this.databaseName,\n context: this.context,\n mode: \"byFilter\",\n queryBuilder: configuredBuilder,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n }\n}\n\n/**\n * Executable delete builder - has execute() method\n * Returned after calling .byId() or .where()\n */\nexport class ExecutableDeleteBuilder<T extends Record<string, any>>\n implements ExecutableBuilder<{ deletedCount: number }>\n{\n private tableName: string;\n private databaseName: string;\n private context: ExecutionContext;\n private occurrence?: TableOccurrence<any, any, any, any>;\n private mode: \"byId\" | \"byFilter\";\n private recordId?: string | number;\n private queryBuilder?: QueryBuilder<any>;\n private databaseUseEntityIds: boolean;\n\n constructor(config: {\n occurrence?: TableOccurrence<any, any, any, any>;\n tableName: string;\n databaseName: string;\n context: ExecutionContext;\n mode: \"byId\" | \"byFilter\";\n recordId?: string | number;\n queryBuilder?: QueryBuilder<any>;\n databaseUseEntityIds?: boolean;\n }) {\n this.occurrence = config.occurrence;\n this.tableName = config.tableName;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.mode = config.mode;\n this.recordId = config.recordId;\n this.queryBuilder = config.queryBuilder;\n this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;\n }\n\n /**\n * Helper to merge database-level useEntityIds with per-request options\n */\n private mergeExecuteOptions(\n options?: RequestInit & FFetchOptions & ExecuteOptions,\n ): RequestInit & FFetchOptions & { useEntityIds?: boolean } {\n // If useEntityIds is not set in options, use the database-level setting\n return {\n ...options,\n useEntityIds: options?.useEntityIds ?? this.databaseUseEntityIds,\n };\n }\n\n /**\n * Gets the table ID (FMTID) if using entity IDs, otherwise returns the table name\n * @param useEntityIds - Optional override for entity ID usage\n */\n private getTableId(useEntityIds?: boolean): string {\n if (!this.occurrence) {\n return this.tableName;\n }\n\n const contextDefault = this.context._getUseEntityIds?.() ?? false;\n const shouldUseIds = useEntityIds ?? contextDefault;\n\n if (shouldUseIds) {\n const identifiers = getTableIdentifiers(this.occurrence);\n if (!identifiers.id) {\n throw new Error(\n `useEntityIds is true but TableOccurrence \"${identifiers.name}\" does not have an fmtId defined`,\n );\n }\n return identifiers.id;\n }\n\n return this.occurrence.getTableName();\n }\n\n async execute(\n options?: RequestInit & FFetchOptions & { useEntityIds?: boolean },\n ): Promise<Result<{ deletedCount: number }>> {\n // Merge database-level useEntityIds with per-request options\n const mergedOptions = this.mergeExecuteOptions(options);\n\n // Get table identifier with override support\n const tableId = this.getTableId(mergedOptions.useEntityIds);\n\n let url: string;\n\n if (this.mode === \"byId\") {\n // Delete single record by ID: DELETE /{database}/{table}('id')\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n } else {\n // Delete by filter: DELETE /{database}/{table}?$filter=...\n if (!this.queryBuilder) {\n throw new Error(\"Query builder is required for filter-based delete\");\n }\n\n // Get the query string from the configured QueryBuilder\n const queryString = this.queryBuilder.getQueryString();\n // Remove the leading \"/\" and table name from the query string as we'll build our own URL\n const queryParams = queryString.startsWith(`/${tableId}`)\n ? queryString.slice(`/${tableId}`.length)\n : queryString.startsWith(`/${this.tableName}`)\n ? queryString.slice(`/${this.tableName}`.length)\n : queryString;\n\n url = `/${this.databaseName}/${tableId}${queryParams}`;\n }\n\n // Make DELETE request\n const result = await this.context._makeRequest(url, {\n method: \"DELETE\",\n ...mergedOptions,\n });\n\n if (result.error) {\n return { data: undefined, error: result.error };\n }\n\n const response = result.data;\n\n // OData returns 204 No Content with fmodata.affected_rows header\n // The _makeRequest should handle extracting the header value\n // For now, we'll check if response contains the count\n let deletedCount = 0;\n\n if (typeof response === \"number\") {\n deletedCount = response;\n } else if (response && typeof response === \"object\") {\n // Check if the response has a count property (fallback)\n deletedCount = (response as any).deletedCount || 0;\n }\n\n return { data: { deletedCount }, error: undefined };\n }\n\n getRequestConfig(): { method: string; url: string; body?: any } {\n // For batch operations, use database-level setting (no per-request override available here)\n const tableId = this.getTableId(this.databaseUseEntityIds);\n\n let url: string;\n\n if (this.mode === \"byId\") {\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n } else {\n if (!this.queryBuilder) {\n throw new Error(\"Query builder is required for filter-based delete\");\n }\n\n const queryString = this.queryBuilder.getQueryString();\n const queryParams = queryString.startsWith(`/${tableId}`)\n ? queryString.slice(`/${tableId}`.length)\n : queryString.startsWith(`/${this.tableName}`)\n ? queryString.slice(`/${this.tableName}`.length)\n : queryString;\n\n url = `/${this.databaseName}/${tableId}${queryParams}`;\n }\n\n return {\n method: \"DELETE\",\n url,\n };\n }\n\n toRequest(baseUrl: string): Request {\n const config = this.getRequestConfig();\n const fullUrl = `${baseUrl}${config.url}`;\n\n return new Request(fullUrl, {\n method: config.method,\n headers: {\n Accept: \"application/json\",\n },\n });\n }\n\n async processResponse(\n response: Response,\n options?: ExecuteOptions,\n ): Promise<Result<{ deletedCount: number }>> {\n // Check for empty response (204 No Content)\n const text = await response.text();\n if (!text || text.trim() === \"\") {\n // For 204 No Content, check the fmodata.affected_rows header\n const affectedRows = response.headers.get(\"fmodata.affected_rows\");\n const deletedCount = affectedRows ? parseInt(affectedRows, 10) : 1;\n return { data: { deletedCount }, error: undefined };\n }\n\n const rawResponse = JSON.parse(text);\n\n // OData returns 204 No Content with fmodata.affected_rows header\n // The _makeRequest should handle extracting the header value\n // For now, we'll check if response contains the count\n let deletedCount = 0;\n\n if (typeof rawResponse === \"number\") {\n deletedCount = rawResponse;\n } else if (rawResponse && typeof rawResponse === \"object\") {\n // Check if the response has a count property (fallback)\n deletedCount = (rawResponse as any).deletedCount || 0;\n }\n\n return { data: { deletedCount }, error: undefined };\n }\n}\n"],"names":["deletedCount"],"mappings":"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"}
1
+ {"version":3,"file":"delete-builder.js","sources":["../../../src/client/delete-builder.ts"],"sourcesContent":["import type { FFetchOptions } from \"@fetchkit/ffetch\";\nimport type { FMTable } from \"../orm/table\";\nimport { getTableId as getTableIdHelper, getTableName, isUsingEntityIds } from \"../orm/table\";\nimport type { ExecutableBuilder, ExecuteMethodOptions, ExecuteOptions, ExecutionContext, Result } from \"../types\";\nimport { getAcceptHeader } from \"../types\";\nimport { parseErrorResponse } from \"./error-parser\";\nimport { QueryBuilder } from \"./query-builder\";\n\n/**\n * Initial delete builder returned from EntitySet.delete()\n * Requires calling .byId() or .where() before .execute() is available\n */\n// biome-ignore lint/suspicious/noExplicitAny: Accepts any FMTable configuration\nexport class DeleteBuilder<Occ extends FMTable<any, any>> {\n private readonly databaseName: string;\n private readonly context: ExecutionContext;\n private readonly table: Occ;\n private readonly databaseUseEntityIds: boolean;\n private readonly databaseIncludeSpecialColumns: boolean;\n\n constructor(config: {\n occurrence: Occ;\n databaseName: string;\n context: ExecutionContext;\n databaseUseEntityIds?: boolean;\n databaseIncludeSpecialColumns?: boolean;\n }) {\n this.table = config.occurrence;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;\n this.databaseIncludeSpecialColumns = config.databaseIncludeSpecialColumns ?? false;\n }\n\n /**\n * Delete a single record by ID\n */\n byId(id: string | number): ExecutableDeleteBuilder<Occ> {\n return new ExecutableDeleteBuilder<Occ>({\n occurrence: this.table,\n databaseName: this.databaseName,\n context: this.context,\n mode: \"byId\",\n recordId: id,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n }\n\n /**\n * Delete records matching a filter query\n * @param fn Callback that receives a QueryBuilder for building the filter\n */\n where(fn: (q: QueryBuilder<Occ>) => QueryBuilder<Occ>): ExecutableDeleteBuilder<Occ> {\n // Create a QueryBuilder for the user to configure\n const queryBuilder = new QueryBuilder<Occ>({\n occurrence: this.table,\n databaseName: this.databaseName,\n context: this.context,\n });\n\n // Let the user configure it\n const configuredBuilder = fn(queryBuilder);\n\n return new ExecutableDeleteBuilder<Occ>({\n occurrence: this.table,\n databaseName: this.databaseName,\n context: this.context,\n mode: \"byFilter\",\n queryBuilder: configuredBuilder,\n databaseUseEntityIds: this.databaseUseEntityIds,\n });\n }\n}\n\n/**\n * Executable delete builder - has execute() method\n * Returned after calling .byId() or .where()\n */\n// biome-ignore lint/suspicious/noExplicitAny: Accepts any FMTable configuration\nexport class ExecutableDeleteBuilder<Occ extends FMTable<any, any>>\n implements ExecutableBuilder<{ deletedCount: number }>\n{\n private readonly databaseName: string;\n private readonly context: ExecutionContext;\n private readonly table: Occ;\n private readonly mode: \"byId\" | \"byFilter\";\n private readonly recordId?: string | number;\n private readonly queryBuilder?: QueryBuilder<Occ>;\n private readonly databaseUseEntityIds: boolean;\n\n constructor(config: {\n occurrence: Occ;\n databaseName: string;\n context: ExecutionContext;\n mode: \"byId\" | \"byFilter\";\n recordId?: string | number;\n queryBuilder?: QueryBuilder<Occ>;\n databaseUseEntityIds?: boolean;\n }) {\n this.table = config.occurrence;\n this.databaseName = config.databaseName;\n this.context = config.context;\n this.mode = config.mode;\n this.recordId = config.recordId;\n this.queryBuilder = config.queryBuilder;\n this.databaseUseEntityIds = config.databaseUseEntityIds ?? false;\n }\n\n /**\n * Helper to merge database-level useEntityIds with per-request options\n */\n private mergeExecuteOptions(\n options?: RequestInit & FFetchOptions & ExecuteOptions,\n ): RequestInit & FFetchOptions & { useEntityIds?: boolean } {\n // If useEntityIds is not set in options, use the database-level setting\n return {\n ...options,\n useEntityIds: options?.useEntityIds ?? this.databaseUseEntityIds,\n };\n }\n\n /**\n * Gets the table ID (FMTID) if using entity IDs, otherwise returns the table name\n * @param useEntityIds - Optional override for entity ID usage\n */\n private getTableId(useEntityIds?: boolean): string {\n const contextDefault = this.context._getUseEntityIds?.() ?? false;\n const shouldUseIds = useEntityIds ?? contextDefault;\n\n if (shouldUseIds) {\n if (!isUsingEntityIds(this.table)) {\n throw new Error(\n `useEntityIds is true but table \"${getTableName(this.table)}\" does not have entity IDs configured`,\n );\n }\n return getTableIdHelper(this.table);\n }\n\n return getTableName(this.table);\n }\n\n async execute(options?: ExecuteMethodOptions<ExecuteOptions>): Promise<Result<{ deletedCount: number }>> {\n // Merge database-level useEntityIds with per-request options\n const mergedOptions = this.mergeExecuteOptions(options);\n\n // Get table identifier with override support\n const tableId = this.getTableId(mergedOptions.useEntityIds);\n\n let url: string;\n\n if (this.mode === \"byId\") {\n // Delete single record by ID: DELETE /{database}/{table}('id')\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n } else {\n // Delete by filter: DELETE /{database}/{table}?$filter=...\n if (!this.queryBuilder) {\n throw new Error(\"Query builder is required for filter-based delete\");\n }\n\n // Get the query string from the configured QueryBuilder\n const queryString = this.queryBuilder.getQueryString();\n // Remove the leading \"/\" and table name from the query string as we'll build our own URL\n const tableName = getTableName(this.table);\n let queryParams: string;\n if (queryString.startsWith(`/${tableId}`)) {\n queryParams = queryString.slice(`/${tableId}`.length);\n } else if (queryString.startsWith(`/${tableName}`)) {\n queryParams = queryString.slice(`/${tableName}`.length);\n } else {\n queryParams = queryString;\n }\n\n url = `/${this.databaseName}/${tableId}${queryParams}`;\n }\n\n // Make DELETE request\n const result = await this.context._makeRequest(url, {\n method: \"DELETE\",\n ...mergedOptions,\n });\n\n if (result.error) {\n return { data: undefined, error: result.error };\n }\n\n const response = result.data;\n\n // OData returns 204 No Content with fmodata.affected_rows header\n // The _makeRequest should handle extracting the header value\n // For now, we'll check if response contains the count\n let deletedCount = 0;\n\n if (typeof response === \"number\") {\n deletedCount = response;\n } else if (response && typeof response === \"object\") {\n // Check if the response has a count property (fallback)\n // biome-ignore lint/suspicious/noExplicitAny: Dynamic response type from OData API\n deletedCount = (response as any).deletedCount || 0;\n }\n\n return { data: { deletedCount }, error: undefined };\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: Request body can be any JSON-serializable value\n getRequestConfig(): { method: string; url: string; body?: any } {\n // For batch operations, use database-level setting (no per-request override available here)\n const tableId = this.getTableId(this.databaseUseEntityIds);\n\n let url: string;\n\n if (this.mode === \"byId\") {\n url = `/${this.databaseName}/${tableId}('${this.recordId}')`;\n } else {\n if (!this.queryBuilder) {\n throw new Error(\"Query builder is required for filter-based delete\");\n }\n\n const queryString = this.queryBuilder.getQueryString();\n const tableName = getTableName(this.table);\n let queryParams: string;\n if (queryString.startsWith(`/${tableId}`)) {\n queryParams = queryString.slice(`/${tableId}`.length);\n } else if (queryString.startsWith(`/${tableName}`)) {\n queryParams = queryString.slice(`/${tableName}`.length);\n } else {\n queryParams = queryString;\n }\n\n url = `/${this.databaseName}/${tableId}${queryParams}`;\n }\n\n return {\n method: \"DELETE\",\n url,\n };\n }\n\n toRequest(baseUrl: string, options?: ExecuteOptions): Request {\n const config = this.getRequestConfig();\n const fullUrl = `${baseUrl}${config.url}`;\n\n return new Request(fullUrl, {\n method: config.method,\n headers: {\n Accept: getAcceptHeader(options?.includeODataAnnotations),\n },\n });\n }\n\n async processResponse(response: Response, _options?: ExecuteOptions): Promise<Result<{ deletedCount: number }>> {\n // Check for error responses (important for batch operations)\n if (!response.ok) {\n const tableName = getTableName(this.table);\n const error = await parseErrorResponse(response, response.url || `/${this.databaseName}/${tableName}`);\n return { data: undefined, error };\n }\n\n // Check for empty response (204 No Content)\n const text = await response.text();\n if (!text || text.trim() === \"\") {\n // For 204 No Content, check the fmodata.affected_rows header\n const affectedRows = response.headers.get(\"fmodata.affected_rows\");\n const deletedCount = affectedRows ? Number.parseInt(affectedRows, 10) : 1;\n return { data: { deletedCount }, error: undefined };\n }\n\n const rawResponse = JSON.parse(text);\n\n // OData returns 204 No Content with fmodata.affected_rows header\n // The _makeRequest should handle extracting the header value\n // For now, we'll check if response contains the count\n let deletedCount = 0;\n\n if (typeof rawResponse === \"number\") {\n deletedCount = rawResponse;\n } else if (rawResponse && typeof rawResponse === \"object\") {\n // Check if the response has a count property (fallback)\n // biome-ignore lint/suspicious/noExplicitAny: Dynamic response type from OData API\n deletedCount = (rawResponse as any).deletedCount || 0;\n }\n\n return { data: { deletedCount }, error: undefined };\n }\n}\n"],"names":["getTableIdHelper","deletedCount"],"mappings":"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"}
@@ -1,57 +1,49 @@
1
- import { ExecutionContext, InferSchemaType, InsertData, UpdateData } from '../types.js';
2
- import { StandardSchemaV1 } from '@standard-schema/spec';
3
- import { BaseTable } from './base-table.js';
4
- import { TableOccurrence } from './table-occurrence.js';
5
- import { QueryBuilder } from './query-builder.js';
6
- import { RecordBuilder } from './record-builder.js';
7
- import { InsertBuilder } from './insert-builder.js';
1
+ import { FMTable, InferSchemaOutputFromFMTable, InsertDataFromFMTable, UpdateDataFromFMTable, ValidExpandTarget } from '../orm/table.js';
2
+ import { ExecutionContext } from '../types.js';
3
+ import { Database } from './database.js';
8
4
  import { DeleteBuilder } from './delete-builder.js';
5
+ import { InsertBuilder } from './insert-builder.js';
6
+ import { QueryBuilder } from './query/index.js';
7
+ import { RecordBuilder } from './record-builder.js';
9
8
  import { UpdateBuilder } from './update-builder.js';
10
- import { Database } from './database.js';
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, 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
- type ResolveNavigationItem<T> = T extends () => infer R ? R : T;
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
- export declare class EntitySet<Schema extends Record<string, StandardSchemaV1> = any, Occ extends TableOccurrence<any, any, any, any> | undefined = undefined> {
17
- private occurrence?;
18
- private tableName;
19
- private databaseName;
20
- private context;
21
- private database;
22
- private isNavigateFromEntitySet?;
23
- private navigateRelation?;
24
- private navigateSourceTableName?;
9
+ export declare class EntitySet<Occ extends FMTable<any, any>, DatabaseIncludeSpecialColumns extends boolean = false> {
10
+ private readonly occurrence;
11
+ private readonly databaseName;
12
+ private readonly context;
13
+ private readonly database;
14
+ private readonly isNavigateFromEntitySet?;
15
+ private readonly navigateRelation?;
16
+ private readonly navigateSourceTableName?;
17
+ private readonly navigateBasePath?;
18
+ private readonly databaseUseEntityIds;
19
+ private readonly databaseIncludeSpecialColumns;
20
+ private readonly logger;
25
21
  constructor(config: {
26
- occurrence?: Occ;
27
- tableName: string;
22
+ occurrence: Occ;
28
23
  databaseName: string;
29
24
  context: ExecutionContext;
30
25
  database?: any;
31
26
  });
32
- static create<OccurrenceSchema extends Record<string, StandardSchemaV1>, Occ extends TableOccurrence<BaseTable<OccurrenceSchema, any, any, any>, any, any, any> | undefined = undefined>(config: {
33
- occurrence?: Occ;
34
- tableName: string;
27
+ static create<Occ extends FMTable<any, any>, DatabaseIncludeSpecialColumns extends boolean = false>(config: {
28
+ occurrence: Occ;
35
29
  databaseName: string;
36
30
  context: ExecutionContext;
37
- database: Database<any>;
38
- }): EntitySet<OccurrenceSchema, Occ>;
39
- list(): QueryBuilder<InferSchemaType<Schema>, Occ extends TableOccurrence<any, any, any, any> ? ExtractDefaultSelect<Occ> : keyof InferSchemaType<Schema>, false, false, Occ>;
40
- get(id: string | number): RecordBuilder<InferSchemaType<Schema>, false, keyof InferSchemaType<Schema>, Occ>;
41
- insert(data: Occ extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<any, any, any, any> ? InsertData<BT> : Partial<InferSchemaType<Schema>> : Partial<InferSchemaType<Schema>>, options: {
31
+ database: Database<DatabaseIncludeSpecialColumns>;
32
+ }): EntitySet<Occ, DatabaseIncludeSpecialColumns>;
33
+ list(): QueryBuilder<Occ, keyof InferSchemaOutputFromFMTable<Occ>, false, false, {}, DatabaseIncludeSpecialColumns>;
34
+ get(id: string | number): RecordBuilder<Occ, false, undefined, keyof InferSchemaOutputFromFMTable<Occ>, {}, DatabaseIncludeSpecialColumns>;
35
+ insert(data: InsertDataFromFMTable<Occ>, options: {
42
36
  returnFullRecord: false;
43
- }): InsertBuilder<InferSchemaType<Schema>, Occ, "minimal">;
44
- insert(data: Occ extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<any, any, any, any> ? InsertData<BT> : Partial<InferSchemaType<Schema>> : Partial<InferSchemaType<Schema>>, options?: {
37
+ }): InsertBuilder<Occ, "minimal">;
38
+ insert(data: InsertDataFromFMTable<Occ>, options?: {
45
39
  returnFullRecord?: true;
46
- }): InsertBuilder<InferSchemaType<Schema>, Occ, "representation">;
47
- update(data: Occ extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<any, any, any, any> ? UpdateData<BT> : Partial<InferSchemaType<Schema>> : Partial<InferSchemaType<Schema>>, options: {
40
+ }): InsertBuilder<Occ, "representation">;
41
+ update(data: UpdateDataFromFMTable<Occ>, options: {
48
42
  returnFullRecord: true;
49
- }): UpdateBuilder<InferSchemaType<Schema>, Occ extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<any, any, any, any> ? BT : BaseTable<Schema, any, any, any> : BaseTable<Schema, any, any, any>, "representation">;
50
- update(data: Occ extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<any, any, any, any> ? UpdateData<BT> : Partial<InferSchemaType<Schema>> : Partial<InferSchemaType<Schema>>, options?: {
43
+ }): UpdateBuilder<Occ, "representation">;
44
+ update(data: UpdateDataFromFMTable<Occ>, options?: {
51
45
  returnFullRecord?: false;
52
- }): UpdateBuilder<InferSchemaType<Schema>, Occ extends TableOccurrence<infer BT, any, any, any> ? BT extends BaseTable<any, any, any, any> ? BT : BaseTable<Schema, any, any, any> : BaseTable<Schema, any, any, any>, "minimal">;
53
- delete(): DeleteBuilder<InferSchemaType<Schema>>;
54
- navigate<RelationName extends ExtractNavigationNames<Occ>>(relationName: RelationName): EntitySet<ExtractSchemaFromOccurrence<FindNavigationTarget<Occ, RelationName>> extends Record<string, StandardSchemaV1> ? ExtractSchemaFromOccurrence<FindNavigationTarget<Occ, RelationName>> : Record<string, StandardSchemaV1>, FindNavigationTarget<Occ, RelationName>>;
55
- navigate(relationName: string): EntitySet<Record<string, StandardSchemaV1>, undefined>;
46
+ }): UpdateBuilder<Occ, "minimal">;
47
+ delete(): DeleteBuilder<Occ>;
48
+ navigate<TargetTable extends FMTable<any, any>>(targetTable: ValidExpandTarget<Occ, TargetTable>): EntitySet<TargetTable extends FMTable<any, any> ? TargetTable : never, DatabaseIncludeSpecialColumns>;
56
49
  }
57
- export {};
@@ -1,15 +1,16 @@
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";
5
- import { RecordBuilder } from "./record-builder.js";
6
- import { InsertBuilder } from "./insert-builder.js";
4
+ import { createLogger } from "../logger.js";
5
+ import { getDefaultSelect, getTableSchema, getTableColumns, getTableName, FMTable } from "../orm/table.js";
7
6
  import { DeleteBuilder } from "./delete-builder.js";
7
+ import { InsertBuilder } from "./insert-builder.js";
8
+ import { QueryBuilder } from "./query/query-builder.js";
9
+ import { RecordBuilder } from "./record-builder.js";
8
10
  import { UpdateBuilder } from "./update-builder.js";
9
11
  class EntitySet {
10
12
  constructor(config) {
11
13
  __publicField(this, "occurrence");
12
- __publicField(this, "tableName");
13
14
  __publicField(this, "databaseName");
14
15
  __publicField(this, "context");
15
16
  __publicField(this, "database");
@@ -17,120 +18,193 @@ class EntitySet {
17
18
  __publicField(this, "isNavigateFromEntitySet");
18
19
  __publicField(this, "navigateRelation");
19
20
  __publicField(this, "navigateSourceTableName");
21
+ __publicField(this, "navigateBasePath");
22
+ // Full base path for chained navigations
23
+ __publicField(this, "databaseUseEntityIds");
24
+ __publicField(this, "databaseIncludeSpecialColumns");
25
+ __publicField(this, "logger");
26
+ var _a, _b, _c, _d;
20
27
  this.occurrence = config.occurrence;
21
- this.tableName = config.tableName;
22
28
  this.databaseName = config.databaseName;
23
29
  this.context = config.context;
24
30
  this.database = config.database;
31
+ this.databaseUseEntityIds = ((_a = config.database) == null ? void 0 : _a._getUseEntityIds) ?? false;
32
+ this.databaseIncludeSpecialColumns = ((_b = config.database) == null ? void 0 : _b._getIncludeSpecialColumns) ?? false;
33
+ this.logger = ((_d = (_c = config.context) == null ? void 0 : _c._getLogger) == null ? void 0 : _d.call(_c)) ?? createLogger();
25
34
  }
26
- // Type-only method to help TypeScript infer the schema from occurrence
35
+ // Type-only method to help TypeScript infer the schema from table
36
+ // biome-ignore lint/suspicious/noExplicitAny: Accepts any FMTable configuration
27
37
  static create(config) {
28
38
  return new EntitySet({
29
39
  occurrence: config.occurrence,
30
- tableName: config.tableName,
31
40
  databaseName: config.databaseName,
32
41
  context: config.context,
33
42
  database: config.database
34
43
  });
35
44
  }
45
+ // biome-ignore lint/complexity/noBannedTypes: Empty object type represents no expands by default
36
46
  list() {
37
- var _a;
38
47
  const builder = new QueryBuilder({
39
48
  occurrence: this.occurrence,
40
- tableName: this.tableName,
41
49
  databaseName: this.databaseName,
42
50
  context: this.context,
43
- databaseUseEntityIds: ((_a = this.database) == null ? void 0 : _a.isUsingEntityIds()) ?? false
51
+ databaseUseEntityIds: this.databaseUseEntityIds,
52
+ databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns
44
53
  });
45
54
  if (this.occurrence) {
46
- const defaultSelect = this.occurrence.defaultSelect;
47
- if (defaultSelect === "schema") {
48
- const schema = this.occurrence.baseTable.schema;
49
- const fields = Object.keys(schema);
50
- const uniqueFields = [...new Set(fields)];
51
- return builder.select(...uniqueFields).top(1e3);
52
- } else if (Array.isArray(defaultSelect)) {
53
- const uniqueFields = [
54
- ...new Set(defaultSelect)
55
- ];
56
- return builder.select(...uniqueFields).top(1e3);
55
+ const defaultSelectValue = getDefaultSelect(this.occurrence);
56
+ getTableSchema(this.occurrence);
57
+ if (defaultSelectValue === "schema") {
58
+ const allColumns = getTableColumns(this.occurrence);
59
+ const systemColumns = this.databaseIncludeSpecialColumns ? { ROWID: true, ROWMODID: true } : void 0;
60
+ const selectedBuilder = builder.select(allColumns, systemColumns).top(1e3);
61
+ if (this.isNavigateFromEntitySet && this.navigateRelation && this.navigateSourceTableName) {
62
+ selectedBuilder.navigation = {
63
+ relation: this.navigateRelation,
64
+ sourceTableName: this.navigateSourceTableName,
65
+ basePath: this.navigateBasePath
66
+ };
67
+ }
68
+ return selectedBuilder;
69
+ }
70
+ if (typeof defaultSelectValue === "object") {
71
+ const selectedBuilder = builder.select(defaultSelectValue).top(1e3);
72
+ if (this.isNavigateFromEntitySet && this.navigateRelation && this.navigateSourceTableName) {
73
+ selectedBuilder.navigation = {
74
+ relation: this.navigateRelation,
75
+ sourceTableName: this.navigateSourceTableName,
76
+ basePath: this.navigateBasePath
77
+ };
78
+ }
79
+ return selectedBuilder;
57
80
  }
58
81
  }
59
- if (this.isNavigateFromEntitySet) {
60
- builder.isNavigate = true;
61
- builder.navigateRelation = this.navigateRelation;
62
- builder.navigateSourceTableName = this.navigateSourceTableName;
82
+ if (this.isNavigateFromEntitySet && this.navigateRelation && this.navigateSourceTableName) {
83
+ builder.navigation = {
84
+ relation: this.navigateRelation,
85
+ sourceTableName: this.navigateSourceTableName,
86
+ basePath: this.navigateBasePath
87
+ // recordId is intentionally not set (undefined) to indicate navigation from EntitySet
88
+ };
63
89
  }
64
90
  return builder.top(1e3);
65
91
  }
66
92
  get(id) {
67
- var _a;
68
93
  const builder = new RecordBuilder({
69
94
  occurrence: this.occurrence,
70
- tableName: this.tableName,
71
95
  databaseName: this.databaseName,
72
96
  context: this.context,
73
97
  recordId: id,
74
- databaseUseEntityIds: ((_a = this.database) == null ? void 0 : _a.isUsingEntityIds()) ?? false
98
+ databaseUseEntityIds: this.databaseUseEntityIds,
99
+ databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns
75
100
  });
76
- if (this.isNavigateFromEntitySet) {
77
- builder.isNavigateFromEntitySet = true;
78
- builder.navigateRelation = this.navigateRelation;
79
- builder.navigateSourceTableName = this.navigateSourceTableName;
101
+ if (this.occurrence) {
102
+ const defaultSelectValue = getDefaultSelect(this.occurrence);
103
+ getTableSchema(this.occurrence);
104
+ if (defaultSelectValue === "schema") {
105
+ const allColumns = getTableColumns(this.occurrence);
106
+ const systemColumns = this.databaseIncludeSpecialColumns ? { ROWID: true, ROWMODID: true } : void 0;
107
+ const selectedBuilder = builder.select(allColumns, systemColumns);
108
+ if (this.isNavigateFromEntitySet && this.navigateRelation && this.navigateSourceTableName) {
109
+ selectedBuilder.navigation = {
110
+ relation: this.navigateRelation,
111
+ sourceTableName: this.navigateSourceTableName,
112
+ basePath: this.navigateBasePath
113
+ };
114
+ }
115
+ return selectedBuilder;
116
+ }
117
+ if (typeof defaultSelectValue === "object" && defaultSelectValue !== null && !Array.isArray(defaultSelectValue)) {
118
+ const selectedBuilder = builder.select(defaultSelectValue);
119
+ if (this.isNavigateFromEntitySet && this.navigateRelation && this.navigateSourceTableName) {
120
+ selectedBuilder.navigation = {
121
+ relation: this.navigateRelation,
122
+ sourceTableName: this.navigateSourceTableName,
123
+ basePath: this.navigateBasePath
124
+ };
125
+ }
126
+ return selectedBuilder;
127
+ }
128
+ }
129
+ if (this.isNavigateFromEntitySet && this.navigateRelation && this.navigateSourceTableName) {
130
+ builder.navigation = {
131
+ relation: this.navigateRelation,
132
+ sourceTableName: this.navigateSourceTableName,
133
+ basePath: this.navigateBasePath
134
+ };
80
135
  }
81
136
  return builder;
82
137
  }
83
138
  // Implementation
84
139
  insert(data, options) {
85
- var _a;
86
- const returnPref = (options == null ? void 0 : options.returnFullRecord) === false ? "minimal" : "representation";
140
+ const returnPreference = (options == null ? void 0 : options.returnFullRecord) === false ? "minimal" : "representation";
87
141
  return new InsertBuilder({
88
142
  occurrence: this.occurrence,
89
- tableName: this.tableName,
90
143
  databaseName: this.databaseName,
91
144
  context: this.context,
145
+ // biome-ignore lint/suspicious/noExplicitAny: Input type is validated/transformed at runtime
92
146
  data,
93
- returnPreference: returnPref,
94
- databaseUseEntityIds: ((_a = this.database) == null ? void 0 : _a.isUsingEntityIds()) ?? false
147
+ // biome-ignore lint/suspicious/noExplicitAny: Type assertion for generic type parameter
148
+ returnPreference,
149
+ databaseUseEntityIds: this.databaseUseEntityIds,
150
+ databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns
95
151
  });
96
152
  }
97
153
  // Implementation
98
154
  update(data, options) {
99
- var _a;
100
- const returnPref = (options == null ? void 0 : options.returnFullRecord) === true ? "representation" : "minimal";
155
+ const returnPreference = (options == null ? void 0 : options.returnFullRecord) === true ? "representation" : "minimal";
101
156
  return new UpdateBuilder({
102
157
  occurrence: this.occurrence,
103
- tableName: this.tableName,
104
158
  databaseName: this.databaseName,
105
159
  context: this.context,
160
+ // biome-ignore lint/suspicious/noExplicitAny: Input type is validated/transformed at runtime
106
161
  data,
107
- returnPreference: returnPref,
108
- databaseUseEntityIds: ((_a = this.database) == null ? void 0 : _a.isUsingEntityIds()) ?? false
162
+ // biome-ignore lint/suspicious/noExplicitAny: Type assertion for generic type parameter
163
+ returnPreference,
164
+ databaseUseEntityIds: this.databaseUseEntityIds,
165
+ databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns
109
166
  });
110
167
  }
111
168
  delete() {
112
- var _a;
113
169
  return new DeleteBuilder({
114
170
  occurrence: this.occurrence,
115
- tableName: this.tableName,
116
171
  databaseName: this.databaseName,
117
172
  context: this.context,
118
- databaseUseEntityIds: ((_a = this.database) == null ? void 0 : _a.isUsingEntityIds()) ?? false
173
+ databaseUseEntityIds: this.databaseUseEntityIds,
174
+ databaseIncludeSpecialColumns: this.databaseIncludeSpecialColumns
175
+ // biome-ignore lint/suspicious/noExplicitAny: Type assertion for complex generic return type
119
176
  });
120
177
  }
121
178
  // Implementation
122
- navigate(relationName) {
123
- var _a;
124
- const targetOccurrence = (_a = this.occurrence) == null ? void 0 : _a.navigation[relationName];
179
+ // biome-ignore lint/suspicious/noExplicitAny: Accepts any FMTable configuration
180
+ navigate(targetTable) {
181
+ let relationName;
182
+ relationName = getTableName(targetTable);
183
+ if (this.occurrence && FMTable.Symbol.NavigationPaths in this.occurrence) {
184
+ const navigationPaths = this.occurrence[FMTable.Symbol.NavigationPaths];
185
+ if (navigationPaths && !navigationPaths.includes(relationName)) {
186
+ this.logger.warn(
187
+ `Cannot navigate to "${relationName}". Valid navigation paths: ${navigationPaths.length > 0 ? navigationPaths.join(", ") : "none"}`
188
+ );
189
+ }
190
+ }
125
191
  const entitySet = new EntitySet({
126
- occurrence: targetOccurrence,
127
- tableName: (targetOccurrence == null ? void 0 : targetOccurrence.name) ?? relationName,
192
+ occurrence: targetTable,
128
193
  databaseName: this.databaseName,
129
- context: this.context
194
+ context: this.context,
195
+ database: this.database
130
196
  });
131
197
  entitySet.isNavigateFromEntitySet = true;
132
198
  entitySet.navigateRelation = relationName;
133
- entitySet.navigateSourceTableName = this.tableName;
199
+ if (this.isNavigateFromEntitySet && this.navigateBasePath) {
200
+ entitySet.navigateBasePath = `${this.navigateBasePath}/${this.navigateRelation}`;
201
+ entitySet.navigateSourceTableName = this.navigateSourceTableName;
202
+ } else if (this.isNavigateFromEntitySet && this.navigateRelation) {
203
+ entitySet.navigateBasePath = `${this.navigateSourceTableName}/${this.navigateRelation}`;
204
+ entitySet.navigateSourceTableName = this.navigateSourceTableName;
205
+ } else {
206
+ entitySet.navigateSourceTableName = getTableName(this.occurrence);
207
+ }
134
208
  return entitySet;
135
209
  }
136
210
  }