@proofkit/fmodata 0.1.0-alpha.8 → 0.1.0-beta.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +651 -449
  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 +110 -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 +28 -20
  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 +266 -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 -166
  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,5 +1,6 @@
1
1
  import { FFetchOptions } from '@fetchkit/ffetch';
2
2
  import { StandardSchemaV1 } from '@standard-schema/spec';
3
+ import { InternalLogger } from './logger.js';
3
4
  export type Auth = {
4
5
  username: string;
5
6
  password: string;
@@ -16,9 +17,10 @@ export interface ExecutableBuilder<T> {
16
17
  /**
17
18
  * Convert this builder to a native Request object for batch processing.
18
19
  * @param baseUrl - The base URL for the OData service
20
+ * @param options - Optional execution options (e.g., includeODataAnnotations)
19
21
  * @returns A native Request object
20
22
  */
21
- toRequest(baseUrl: string): Request;
23
+ toRequest(baseUrl: string, options?: ExecuteOptions): Request;
22
24
  /**
23
25
  * Process a raw Response object into a typed Result.
24
26
  * This allows builders to apply their own validation and transformation logic.
@@ -31,35 +33,38 @@ export interface ExecutableBuilder<T> {
31
33
  export interface ExecutionContext {
32
34
  _makeRequest<T>(url: string, options?: RequestInit & FFetchOptions & {
33
35
  useEntityIds?: boolean;
36
+ includeSpecialColumns?: boolean;
34
37
  }): Promise<Result<T>>;
35
38
  _setUseEntityIds?(useEntityIds: boolean): void;
36
39
  _getUseEntityIds?(): boolean;
40
+ _setIncludeSpecialColumns?(includeSpecialColumns: boolean): void;
41
+ _getIncludeSpecialColumns?(): boolean;
37
42
  _getBaseUrl?(): string;
43
+ _getLogger?(): InternalLogger;
38
44
  }
39
45
  export type InferSchemaType<Schema extends Record<string, StandardSchemaV1>> = {
40
46
  [K in keyof Schema]: Schema[K] extends StandardSchemaV1<any, infer Output> ? Output : never;
41
47
  };
42
- export type WithSystemFields<T> = T extends Record<string, any> ? T & {
48
+ export type WithSpecialColumns<T> = T extends Record<string, any> ? T & {
43
49
  ROWID: number;
44
50
  ROWMODID: number;
45
51
  } : never;
46
52
  export type ExcludeSystemFields<T extends keyof any> = Exclude<T, "ROWID" | "ROWMODID">;
47
- export type OmitSystemFields<T> = Omit<T, "ROWID" | "ROWMODID">;
48
- export type ODataRecordMetadata = {
53
+ export interface ODataRecordMetadata {
49
54
  "@id": string;
50
55
  "@editLink": string;
51
- };
52
- export type ODataListResponse<T> = {
56
+ }
57
+ export interface ODataListResponse<T> {
53
58
  "@context": string;
54
59
  value: (T & ODataRecordMetadata)[];
55
- };
60
+ }
56
61
  export type ODataSingleResponse<T> = T & ODataRecordMetadata & {
57
62
  "@context": string;
58
63
  };
59
- export type ODataFieldResponse<T> = {
64
+ export interface ODataFieldResponse<T> {
60
65
  "@context": string;
61
66
  value: T;
62
- };
67
+ }
63
68
  export type Result<T, E = import('./errors.js').FMODataErrorType> = {
64
69
  data: T;
65
70
  error: undefined;
@@ -67,48 +72,110 @@ export type Result<T, E = import('./errors.js').FMODataErrorType> = {
67
72
  data: undefined;
68
73
  error: E;
69
74
  };
75
+ export interface BatchItemResult<T> {
76
+ data: T | undefined;
77
+ error: import('./errors.js').FMODataErrorType | undefined;
78
+ status: number;
79
+ }
80
+ export interface BatchResult<T extends readonly any[]> {
81
+ results: {
82
+ [K in keyof T]: BatchItemResult<T[K]>;
83
+ };
84
+ successCount: number;
85
+ errorCount: number;
86
+ truncated: boolean;
87
+ firstErrorIndex: number | null;
88
+ }
70
89
  export type MakeFieldsRequired<T, Keys extends keyof T> = Partial<T> & Required<Pick<T, Keys>>;
71
90
  export type AutoRequiredKeys<Schema extends Record<string, StandardSchemaV1>> = {
72
91
  [K in keyof Schema]: Extract<StandardSchemaV1.InferOutput<Schema[K]>, null | undefined> extends never ? K : never;
73
92
  }[keyof Schema];
74
93
  export type ExcludedFields<IdField extends keyof any | undefined, ReadOnly extends readonly any[]> = IdField extends keyof any ? IdField | ReadOnly[number] : ReadOnly[number];
75
- type ComputeInsertData<Schema extends Record<string, StandardSchemaV1>, IdField extends keyof Schema | undefined, Required extends readonly any[], ReadOnly extends readonly any[]> = [Required[number]] extends [keyof InferSchemaType<Schema>] ? Required extends readonly (keyof InferSchemaType<Schema>)[] ? MakeFieldsRequired<Omit<InferSchemaType<Schema>, ExcludedFields<IdField, ReadOnly>>, Exclude<AutoRequiredKeys<Schema> | Required[number], ExcludedFields<IdField, ReadOnly>>> : MakeFieldsRequired<Omit<InferSchemaType<Schema>, ExcludedFields<IdField, ReadOnly>>, Exclude<AutoRequiredKeys<Schema>, ExcludedFields<IdField, ReadOnly>>> : MakeFieldsRequired<Omit<InferSchemaType<Schema>, ExcludedFields<IdField, ReadOnly>>, Exclude<AutoRequiredKeys<Schema>, ExcludedFields<IdField, ReadOnly>>>;
76
- export type InsertData<BT> = BT extends import('./client/base-table.js').BaseTable<any, any, any, any> ? BT extends {
77
- schema: infer Schema;
78
- idField?: infer IdField;
79
- required?: infer Required;
80
- readOnly?: infer ReadOnly;
81
- } ? Schema extends Record<string, StandardSchemaV1> ? IdField extends keyof Schema | undefined ? Required extends readonly any[] ? ReadOnly extends readonly any[] ? ComputeInsertData<Schema, Extract<IdField, keyof Schema | undefined>, Required, ReadOnly> : Partial<Record<string, any>> : Partial<Record<string, any>> : Partial<Record<string, any>> : Partial<Record<string, any>> : Partial<Record<string, any>> : Partial<Record<string, any>>;
82
- export type UpdateData<BT> = BT extends import('./client/base-table.js').BaseTable<any, any, any, any> ? BT extends {
83
- schema: infer Schema;
84
- idField?: infer IdField;
85
- readOnly?: infer ReadOnly;
86
- } ? Schema extends Record<string, StandardSchemaV1> ? IdField extends keyof Schema | undefined ? ReadOnly extends readonly any[] ? Partial<Omit<InferSchemaType<Schema>, ExcludedFields<Extract<IdField, keyof Schema | undefined>, ReadOnly>>> : Partial<Record<string, any>> : Partial<Record<string, any>> : Partial<Record<string, any>> : Partial<Record<string, any>> : Partial<Record<string, any>>;
87
- export type ExecuteOptions = {
94
+ export interface ExecuteOptions {
88
95
  includeODataAnnotations?: boolean;
89
96
  skipValidation?: boolean;
90
97
  /**
91
98
  * Overrides the default behavior of the database to use entity IDs (rather than field names) in THIS REQUEST ONLY
92
99
  */
93
100
  useEntityIds?: boolean;
94
- };
101
+ /**
102
+ * Overrides the default behavior of the database to include special columns (ROWID and ROWMODID) in THIS REQUEST ONLY.
103
+ * Note: Special columns are only included when there is no $select query.
104
+ */
105
+ includeSpecialColumns?: boolean;
106
+ }
107
+ /**
108
+ * Type for the fetchHandler callback function.
109
+ * This is a convenience type export that matches the fetchHandler signature in FFetchOptions.
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * import type { FetchHandler } from '@proofkit/fmodata';
114
+ *
115
+ * const myFetchHandler: FetchHandler = (input, init) => {
116
+ * console.log('Custom fetch:', input);
117
+ * return fetch(input, init);
118
+ * };
119
+ *
120
+ * await query.execute({
121
+ * fetchHandler: myFetchHandler
122
+ * });
123
+ * ```
124
+ */
125
+ export type FetchHandler = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;
126
+ /**
127
+ * Combined type for execute() method options.
128
+ *
129
+ * Uses FFetchOptions from @fetchkit/ffetch to ensure proper type inference.
130
+ * FFetchOptions is re-exported in the package to ensure type availability in consuming packages.
131
+ */
132
+ export type ExecuteMethodOptions<EO extends ExecuteOptions = ExecuteOptions> = RequestInit & FFetchOptions & ExecuteOptions & EO;
133
+ /**
134
+ * Get the Accept header value based on includeODataAnnotations option
135
+ * @param includeODataAnnotations - Whether to include OData annotations
136
+ * @returns Accept header value
137
+ */
138
+ export declare function getAcceptHeader(includeODataAnnotations?: boolean): string;
95
139
  export type ConditionallyWithODataAnnotations<T, IncludeODataAnnotations extends boolean> = IncludeODataAnnotations extends true ? T & {
96
140
  "@id": string;
97
141
  "@editLink": string;
98
142
  } : T;
143
+ /**
144
+ * Normalizes includeSpecialColumns with a database-level default.
145
+ * Uses distributive conditional types to handle unions correctly.
146
+ * @template IncludeSpecialColumns - The includeSpecialColumns value from execute options
147
+ * @template DatabaseDefault - The database-level includeSpecialColumns setting (defaults to false)
148
+ */
149
+ export type NormalizeIncludeSpecialColumns<IncludeSpecialColumns extends boolean | undefined, DatabaseDefault extends boolean = false> = [IncludeSpecialColumns] extends [true] ? true : [IncludeSpecialColumns] extends [false] ? false : DatabaseDefault;
150
+ /**
151
+ * Conditionally adds ROWID and ROWMODID special columns to a type.
152
+ * Special columns are only included when:
153
+ * - includeSpecialColumns is true AND
154
+ * - hasSelect is false (no $select query was applied) AND
155
+ * - T is an object type (not a primitive like string or number)
156
+ *
157
+ * Handles both single objects and arrays of objects.
158
+ */
159
+ export type ConditionallyWithSpecialColumns<T, IncludeSpecialColumns extends boolean, HasSelect extends boolean> = IncludeSpecialColumns extends true ? HasSelect extends false ? T extends readonly (infer U)[] ? U extends Record<string, any> ? (U & {
160
+ ROWID: number;
161
+ ROWMODID: number;
162
+ })[] : T : T extends Record<string, any> ? T & {
163
+ ROWID: number;
164
+ ROWMODID: number;
165
+ } : T : T : T;
99
166
  export type ExtractSchemaFromOccurrence<Occ> = Occ extends {
100
167
  baseTable: {
101
168
  schema: infer S;
102
169
  };
103
170
  } ? S extends Record<string, StandardSchemaV1> ? S : Record<string, StandardSchemaV1> : Record<string, StandardSchemaV1>;
104
- export type GenericFieldMetadata = {
171
+ export interface GenericFieldMetadata {
105
172
  $Nullable?: boolean;
106
173
  "@Index"?: boolean;
107
174
  "@Calculation"?: boolean;
108
175
  "@Summary"?: boolean;
109
176
  "@Global"?: boolean;
110
177
  "@Org.OData.Core.V1.Permissions"?: "Org.OData.Core.V1.Permission@Read";
111
- };
178
+ }
112
179
  export type StringFieldMetadata = GenericFieldMetadata & {
113
180
  $Type: "Edm.String";
114
181
  $DefaultValue?: "USER" | "USERNAME" | "CURRENT_USER";
@@ -131,21 +198,20 @@ export type DateTimeOffsetFieldMetadata = GenericFieldMetadata & {
131
198
  $DefaultValue?: "CURTIMESTAMP" | "CURRENT_TIMESTAMP";
132
199
  "@VersionId"?: boolean;
133
200
  };
134
- export type StreamFieldMetadata = {
201
+ export interface StreamFieldMetadata {
135
202
  $Type: "Edm.Stream";
136
203
  $Nullable?: boolean;
137
204
  "@EnclosedPath": string;
138
205
  "@ExternalOpenPath": string;
139
206
  "@ExternalSecurePath"?: string;
140
- };
207
+ }
141
208
  export type FieldMetadata = StringFieldMetadata | DecimalFieldMetadata | DateFieldMetadata | TimeOfDayFieldMetadata | DateTimeOffsetFieldMetadata | StreamFieldMetadata;
142
209
  export type EntityType = {
143
210
  $Kind: "EntityType";
144
211
  $Key: string[];
145
212
  } & Record<string, FieldMetadata>;
146
- export type EntitySet = {
213
+ export interface EntitySet {
147
214
  $Kind: "EntitySet";
148
215
  $Type: string;
149
- };
216
+ }
150
217
  export type Metadata = Record<string, EntityType | EntitySet>;
151
- export {};
@@ -0,0 +1,7 @@
1
+ function getAcceptHeader(includeODataAnnotations) {
2
+ return includeODataAnnotations === true ? "application/json" : "application/json;odata.metadata=none";
3
+ }
4
+ export {
5
+ getAcceptHeader
6
+ };
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sources":["../../src/types.ts"],"sourcesContent":["import type { FFetchOptions } from \"@fetchkit/ffetch\";\nimport type { StandardSchemaV1 } from \"@standard-schema/spec\";\nimport type { InternalLogger } from \"./logger\";\n\nexport type Auth = { username: string; password: string } | { apiKey: string };\n\nexport interface ExecutableBuilder<T> {\n execute(): Promise<Result<T>>;\n // biome-ignore lint/suspicious/noExplicitAny: Request body can be any JSON-serializable value\n getRequestConfig(): { method: string; url: string; body?: any };\n\n /**\n * Convert this builder to a native Request object for batch processing.\n * @param baseUrl - The base URL for the OData service\n * @param options - Optional execution options (e.g., includeODataAnnotations)\n * @returns A native Request object\n */\n toRequest(baseUrl: string, options?: ExecuteOptions): Request;\n\n /**\n * Process a raw Response object into a typed Result.\n * This allows builders to apply their own validation and transformation logic.\n * @param response - The native Response object from the batch operation\n * @param options - Optional execution options (e.g., skipValidation, includeODataAnnotations)\n * @returns A typed Result with the builder's expected return type\n */\n processResponse(response: Response, options?: ExecuteOptions): Promise<Result<T>>;\n}\n\nexport interface ExecutionContext {\n _makeRequest<T>(\n url: string,\n options?: RequestInit &\n FFetchOptions & {\n useEntityIds?: boolean;\n includeSpecialColumns?: boolean;\n },\n ): Promise<Result<T>>;\n _setUseEntityIds?(useEntityIds: boolean): void;\n _getUseEntityIds?(): boolean;\n _setIncludeSpecialColumns?(includeSpecialColumns: boolean): void;\n _getIncludeSpecialColumns?(): boolean;\n _getBaseUrl?(): string;\n _getLogger?(): InternalLogger;\n}\n\nexport type InferSchemaType<Schema extends Record<string, StandardSchemaV1>> = {\n // biome-ignore lint/suspicious/noExplicitAny: Required for type inference with infer\n [K in keyof Schema]: Schema[K] extends StandardSchemaV1<any, infer Output> ? Output : never;\n};\n\nexport type WithSpecialColumns<T> =\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any record shape\n T extends Record<string, any>\n ? T & {\n ROWID: number;\n ROWMODID: number;\n }\n : never;\n\n// Helper type to exclude special columns from a union of keys\n// biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any key type\nexport type ExcludeSystemFields<T extends keyof any> = Exclude<T, \"ROWID\" | \"ROWMODID\">;\n\n// OData record metadata fields (present on each record)\nexport interface ODataRecordMetadata {\n \"@id\": string;\n \"@editLink\": string;\n}\n\n// OData response wrapper (top-level, internal use only)\nexport interface ODataListResponse<T> {\n \"@context\": string;\n value: (T & ODataRecordMetadata)[];\n}\n\nexport type ODataSingleResponse<T> = T &\n ODataRecordMetadata & {\n \"@context\": string;\n };\n\n// OData response for single field values\nexport interface ODataFieldResponse<T> {\n \"@context\": string;\n value: T;\n}\n\n// Result pattern for execute responses\nexport type Result<T, E = import(\"./errors\").FMODataErrorType> =\n | { data: T; error: undefined }\n | { data: undefined; error: E };\n\n// Batch operation result types\nexport interface BatchItemResult<T> {\n data: T | undefined;\n error: import(\"./errors\").FMODataErrorType | undefined;\n status: number; // HTTP status code (0 for truncated)\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any tuple type\nexport interface BatchResult<T extends readonly any[]> {\n results: { [K in keyof T]: BatchItemResult<T[K]> };\n successCount: number;\n errorCount: number;\n truncated: boolean;\n firstErrorIndex: number | null;\n}\n\n// Make specific keys required, rest optional\nexport type MakeFieldsRequired<T, Keys extends keyof T> = Partial<T> & Required<Pick<T, Keys>>;\n\n// Extract keys from schema where validator doesn't allow null/undefined (auto-required fields)\nexport type AutoRequiredKeys<Schema extends Record<string, StandardSchemaV1>> = {\n [K in keyof Schema]: Extract<StandardSchemaV1.InferOutput<Schema[K]>, null | undefined> extends never ? K : never;\n}[keyof Schema];\n\n// Helper type to compute excluded fields (readOnly fields + idField)\nexport type ExcludedFields<\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any key type\n IdField extends keyof any | undefined,\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any array type\n ReadOnly extends readonly any[],\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any key type\n> = IdField extends keyof any ? IdField | ReadOnly[number] : ReadOnly[number];\n\n// Helper type for InsertData computation\ntype _ComputeInsertData<\n Schema extends Record<string, StandardSchemaV1>,\n IdField extends keyof Schema | undefined,\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any array type\n Required extends readonly any[],\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any array type\n ReadOnly extends readonly any[],\n> = [Required[number]] extends [keyof InferSchemaType<Schema>]\n ? Required extends readonly (keyof InferSchemaType<Schema>)[]\n ? MakeFieldsRequired<\n Omit<InferSchemaType<Schema>, ExcludedFields<IdField, ReadOnly>>,\n Exclude<AutoRequiredKeys<Schema> | Required[number], ExcludedFields<IdField, ReadOnly>>\n >\n : MakeFieldsRequired<\n Omit<InferSchemaType<Schema>, ExcludedFields<IdField, ReadOnly>>,\n Exclude<AutoRequiredKeys<Schema>, ExcludedFields<IdField, ReadOnly>>\n >\n : MakeFieldsRequired<\n Omit<InferSchemaType<Schema>, ExcludedFields<IdField, ReadOnly>>,\n Exclude<AutoRequiredKeys<Schema>, ExcludedFields<IdField, ReadOnly>>\n >;\n\nexport interface ExecuteOptions {\n includeODataAnnotations?: boolean;\n skipValidation?: boolean;\n /**\n * Overrides the default behavior of the database to use entity IDs (rather than field names) in THIS REQUEST ONLY\n */\n useEntityIds?: boolean;\n /**\n * Overrides the default behavior of the database to include special columns (ROWID and ROWMODID) in THIS REQUEST ONLY.\n * Note: Special columns are only included when there is no $select query.\n */\n includeSpecialColumns?: boolean;\n}\n\n/**\n * Type for the fetchHandler callback function.\n * This is a convenience type export that matches the fetchHandler signature in FFetchOptions.\n *\n * @example\n * ```typescript\n * import type { FetchHandler } from '@proofkit/fmodata';\n *\n * const myFetchHandler: FetchHandler = (input, init) => {\n * console.log('Custom fetch:', input);\n * return fetch(input, init);\n * };\n *\n * await query.execute({\n * fetchHandler: myFetchHandler\n * });\n * ```\n */\nexport type FetchHandler = (input: RequestInfo | URL, init?: RequestInit) => Promise<Response>;\n\n/**\n * Combined type for execute() method options.\n *\n * Uses FFetchOptions from @fetchkit/ffetch to ensure proper type inference.\n * FFetchOptions is re-exported in the package to ensure type availability in consuming packages.\n */\nexport type ExecuteMethodOptions<EO extends ExecuteOptions = ExecuteOptions> = RequestInit &\n FFetchOptions &\n ExecuteOptions &\n EO;\n\n/**\n * Get the Accept header value based on includeODataAnnotations option\n * @param includeODataAnnotations - Whether to include OData annotations\n * @returns Accept header value\n */\nexport function getAcceptHeader(includeODataAnnotations?: boolean): string {\n return includeODataAnnotations === true ? \"application/json\" : \"application/json;odata.metadata=none\";\n}\n\nexport type ConditionallyWithODataAnnotations<\n T,\n IncludeODataAnnotations extends boolean,\n> = IncludeODataAnnotations extends true\n ? T & {\n \"@id\": string;\n \"@editLink\": string;\n }\n : T;\n\n/**\n * Normalizes includeSpecialColumns with a database-level default.\n * Uses distributive conditional types to handle unions correctly.\n * @template IncludeSpecialColumns - The includeSpecialColumns value from execute options\n * @template DatabaseDefault - The database-level includeSpecialColumns setting (defaults to false)\n */\nexport type NormalizeIncludeSpecialColumns<\n IncludeSpecialColumns extends boolean | undefined,\n DatabaseDefault extends boolean = false,\n> = [IncludeSpecialColumns] extends [true] ? true : [IncludeSpecialColumns] extends [false] ? false : DatabaseDefault; // When undefined, use database-level default\n\n/**\n * Conditionally adds ROWID and ROWMODID special columns to a type.\n * Special columns are only included when:\n * - includeSpecialColumns is true AND\n * - hasSelect is false (no $select query was applied) AND\n * - T is an object type (not a primitive like string or number)\n *\n * Handles both single objects and arrays of objects.\n */\nexport type ConditionallyWithSpecialColumns<\n T,\n IncludeSpecialColumns extends boolean,\n HasSelect extends boolean,\n> = IncludeSpecialColumns extends true\n ? HasSelect extends false\n ? // Handle array types\n T extends readonly (infer U)[]\n ? // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any record shape\n U extends Record<string, any>\n ? (U & {\n ROWID: number;\n ROWMODID: number;\n })[]\n : T\n : // Handle single object types\n // biome-ignore lint/suspicious/noExplicitAny: Generic constraint accepting any record shape\n T extends Record<string, any>\n ? T & {\n ROWID: number;\n ROWMODID: number;\n }\n : T // Don't add special columns to primitives (e.g., single field queries)\n : T\n : T;\n\n// Helper type to extract schema from a FMTable\nexport type ExtractSchemaFromOccurrence<Occ> = Occ extends {\n baseTable: { schema: infer S };\n}\n ? S extends Record<string, StandardSchemaV1>\n ? S\n : Record<string, StandardSchemaV1>\n : Record<string, StandardSchemaV1>;\n\nexport interface GenericFieldMetadata {\n $Nullable?: boolean;\n \"@Index\"?: boolean;\n \"@Calculation\"?: boolean;\n \"@Summary\"?: boolean;\n \"@Global\"?: boolean;\n \"@Org.OData.Core.V1.Permissions\"?: \"Org.OData.Core.V1.Permission@Read\";\n}\n\nexport type StringFieldMetadata = GenericFieldMetadata & {\n $Type: \"Edm.String\";\n $DefaultValue?: \"USER\" | \"USERNAME\" | \"CURRENT_USER\";\n $MaxLength?: number;\n};\n\nexport type DecimalFieldMetadata = GenericFieldMetadata & {\n $Type: \"Edm.Decimal\";\n \"@AutoGenerated\"?: boolean;\n};\n\nexport type DateFieldMetadata = GenericFieldMetadata & {\n $Type: \"Edm.Date\";\n $DefaultValue?: \"CURDATE\" | \"CURRENT_DATE\";\n};\n\nexport type TimeOfDayFieldMetadata = GenericFieldMetadata & {\n $Type: \"Edm.TimeOfDay\";\n $DefaultValue?: \"CURTIME\" | \"CURRENT_TIME\";\n};\n\nexport type DateTimeOffsetFieldMetadata = GenericFieldMetadata & {\n $Type: \"Edm.Date\";\n $DefaultValue?: \"CURTIMESTAMP\" | \"CURRENT_TIMESTAMP\";\n \"@VersionId\"?: boolean;\n};\n\nexport interface StreamFieldMetadata {\n $Type: \"Edm.Stream\";\n $Nullable?: boolean;\n \"@EnclosedPath\": string;\n \"@ExternalOpenPath\": string;\n \"@ExternalSecurePath\"?: string;\n}\n\nexport type FieldMetadata =\n | StringFieldMetadata\n | DecimalFieldMetadata\n | DateFieldMetadata\n | TimeOfDayFieldMetadata\n | DateTimeOffsetFieldMetadata\n | StreamFieldMetadata;\n\nexport type EntityType = {\n $Kind: \"EntityType\";\n $Key: string[];\n} & Record<string, FieldMetadata>;\n\nexport interface EntitySet {\n $Kind: \"EntitySet\";\n $Type: string;\n}\n\nexport type Metadata = Record<string, EntityType | EntitySet>;\n"],"names":[],"mappings":"AAsMO,SAAS,gBAAgB,yBAA2C;AAClE,SAAA,4BAA4B,OAAO,qBAAqB;AACjE;"}
@@ -1,21 +1,31 @@
1
- import { ODataRecordMetadata } from './types.js';
2
1
  import { StandardSchemaV1 } from '@standard-schema/spec';
3
- import { TableOccurrence } from './client/table-occurrence.js';
4
- import { ValidationError, ResponseStructureError, RecordCountMismatchError } from './errors.js';
5
- export type ExpandValidationConfig = {
2
+ import { RecordCountMismatchError, ResponseStructureError, ValidationError } from './errors.js';
3
+ import { FMTable } from './orm/table.js';
4
+ import { ODataRecordMetadata } from './types.js';
5
+ /**
6
+ * Validates and transforms input data for insert/update operations.
7
+ * Applies input validators (writeValidators) to transform user input to database format.
8
+ * Fields without input validators are passed through unchanged.
9
+ *
10
+ * @param data - The input data to validate and transform
11
+ * @param inputSchema - Optional schema containing input validators for each field
12
+ * @returns Transformed data ready to send to the server
13
+ * @throws ValidationError if any field fails validation
14
+ */
15
+ export declare function validateAndTransformInput<T extends Record<string, any>>(data: Partial<T>, inputSchema?: Partial<Record<string, StandardSchemaV1>>): Promise<Partial<T>>;
16
+ export interface ExpandValidationConfig {
6
17
  relation: string;
7
- targetSchema?: Record<string, StandardSchemaV1>;
8
- targetOccurrence?: TableOccurrence<any, any, any, any>;
9
- targetBaseTable?: any;
10
- occurrence?: TableOccurrence<any, any, any, any>;
18
+ targetSchema?: Partial<Record<string, StandardSchemaV1>>;
19
+ targetTable?: FMTable<any, any>;
20
+ table?: FMTable<any, any>;
11
21
  selectedFields?: string[];
12
22
  nestedExpands?: ExpandValidationConfig[];
13
- };
23
+ }
14
24
  /**
15
25
  * Validates a single record against a schema, only validating selected fields.
16
26
  * Also validates expanded relations if expandConfigs are provided.
17
27
  */
18
- export declare function validateRecord<T extends Record<string, any>>(record: any, schema: Record<string, StandardSchemaV1> | undefined, selectedFields?: (keyof T)[], expandConfigs?: ExpandValidationConfig[]): Promise<{
28
+ export declare function validateRecord<T extends Record<string, any>>(record: any, schema: Partial<Record<string, StandardSchemaV1>> | undefined, selectedFields?: (keyof T)[], expandConfigs?: ExpandValidationConfig[], includeSpecialColumns?: boolean): Promise<{
19
29
  valid: true;
20
30
  data: T & ODataRecordMetadata;
21
31
  } | {
@@ -25,7 +35,7 @@ export declare function validateRecord<T extends Record<string, any>>(record: an
25
35
  /**
26
36
  * Validates a list response against a schema.
27
37
  */
28
- export declare function validateListResponse<T extends Record<string, any>>(response: any, schema: Record<string, StandardSchemaV1> | undefined, selectedFields?: (keyof T)[], expandConfigs?: ExpandValidationConfig[]): Promise<{
38
+ export declare function validateListResponse<T extends Record<string, any>>(response: any, schema: Partial<Record<string, StandardSchemaV1>> | undefined, selectedFields?: (keyof T)[], expandConfigs?: ExpandValidationConfig[], includeSpecialColumns?: boolean): Promise<{
29
39
  valid: true;
30
40
  data: (T & ODataRecordMetadata)[];
31
41
  } | {
@@ -35,7 +45,7 @@ export declare function validateListResponse<T extends Record<string, any>>(resp
35
45
  /**
36
46
  * Validates a single record response against a schema.
37
47
  */
38
- export declare function validateSingleResponse<T extends Record<string, any>>(response: any, schema: Record<string, StandardSchemaV1> | undefined, selectedFields?: (keyof T)[], expandConfigs?: ExpandValidationConfig[], mode?: "exact" | "maybe"): Promise<{
48
+ export declare function validateSingleResponse<T extends Record<string, any>>(response: any, schema: Partial<Record<string, StandardSchemaV1>> | undefined, selectedFields?: (keyof T)[], expandConfigs?: ExpandValidationConfig[], mode?: "exact" | "maybe", includeSpecialColumns?: boolean): Promise<{
39
49
  valid: true;
40
50
  data: (T & ODataRecordMetadata) | null;
41
51
  } | {