@proofkit/fmodata 0.1.0-alpha.2 → 0.1.0-alpha.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1250 -377
- package/dist/esm/client/batch-builder.d.ts +56 -0
- package/dist/esm/client/batch-builder.js +238 -0
- package/dist/esm/client/batch-builder.js.map +1 -0
- package/dist/esm/client/batch-request.d.ts +61 -0
- package/dist/esm/client/batch-request.js +252 -0
- package/dist/esm/client/batch-request.js.map +1 -0
- package/dist/esm/client/builders/default-select.d.ts +10 -0
- package/dist/esm/client/builders/default-select.js +43 -0
- package/dist/esm/client/builders/default-select.js.map +1 -0
- package/dist/esm/client/builders/expand-builder.d.ts +45 -0
- package/dist/esm/client/builders/expand-builder.js +174 -0
- package/dist/esm/client/builders/expand-builder.js.map +1 -0
- package/dist/esm/client/builders/index.d.ts +8 -0
- package/dist/esm/client/builders/query-string-builder.d.ts +18 -0
- package/dist/esm/client/builders/query-string-builder.js +25 -0
- package/dist/esm/client/builders/query-string-builder.js.map +1 -0
- package/dist/esm/client/builders/response-processor.d.ts +43 -0
- package/dist/esm/client/builders/response-processor.js +176 -0
- package/dist/esm/client/builders/response-processor.js.map +1 -0
- package/dist/esm/client/builders/select-mixin.d.ts +32 -0
- package/dist/esm/client/builders/select-mixin.js +30 -0
- package/dist/esm/client/builders/select-mixin.js.map +1 -0
- package/dist/esm/client/builders/select-utils.d.ts +18 -0
- package/dist/esm/client/builders/select-utils.js +23 -0
- package/dist/esm/client/builders/select-utils.js.map +1 -0
- package/dist/esm/client/builders/shared-types.d.ts +40 -0
- package/dist/esm/client/builders/table-utils.d.ts +35 -0
- package/dist/esm/client/builders/table-utils.js +45 -0
- package/dist/esm/client/builders/table-utils.js.map +1 -0
- package/dist/esm/client/database.d.ts +68 -15
- package/dist/esm/client/database.js +88 -34
- package/dist/esm/client/database.js.map +1 -1
- package/dist/esm/client/delete-builder.d.ts +31 -17
- package/dist/esm/client/delete-builder.js +114 -47
- package/dist/esm/client/delete-builder.js.map +1 -1
- package/dist/esm/client/entity-set.d.ts +33 -27
- package/dist/esm/client/entity-set.js +123 -45
- package/dist/esm/client/entity-set.js.map +1 -1
- package/dist/esm/client/error-parser.d.ts +12 -0
- package/dist/esm/client/error-parser.js +30 -0
- package/dist/esm/client/error-parser.js.map +1 -0
- package/dist/esm/client/filemaker-odata.d.ts +44 -6
- package/dist/esm/client/filemaker-odata.js +172 -28
- package/dist/esm/client/filemaker-odata.js.map +1 -1
- package/dist/esm/client/insert-builder.d.ts +39 -9
- package/dist/esm/client/insert-builder.js +265 -36
- package/dist/esm/client/insert-builder.js.map +1 -1
- package/dist/esm/client/query/expand-builder.d.ts +35 -0
- package/dist/esm/client/query/index.d.ts +3 -0
- package/dist/esm/client/query/query-builder.d.ts +139 -0
- package/dist/esm/client/query/query-builder.js +481 -0
- package/dist/esm/client/query/query-builder.js.map +1 -0
- package/dist/esm/client/query/response-processor.d.ts +25 -0
- package/dist/esm/client/query/types.d.ts +77 -0
- package/dist/esm/client/query/url-builder.d.ts +71 -0
- package/dist/esm/client/query/url-builder.js +107 -0
- package/dist/esm/client/query/url-builder.js.map +1 -0
- package/dist/esm/client/query-builder.d.ts +1 -94
- package/dist/esm/client/record-builder.d.ts +107 -22
- package/dist/esm/client/record-builder.js +342 -64
- package/dist/esm/client/record-builder.js.map +1 -1
- package/dist/esm/client/response-processor.d.ts +33 -0
- package/dist/esm/client/sanitize-json.d.ts +35 -0
- package/dist/esm/client/sanitize-json.js +27 -0
- package/dist/esm/client/sanitize-json.js.map +1 -0
- package/dist/esm/client/schema-manager.d.ts +57 -0
- package/dist/esm/client/schema-manager.js +132 -0
- package/dist/esm/client/schema-manager.js.map +1 -0
- package/dist/esm/client/update-builder.d.ts +42 -25
- package/dist/esm/client/update-builder.js +179 -46
- package/dist/esm/client/update-builder.js.map +1 -1
- package/dist/esm/client/webhook-builder.d.ts +126 -0
- package/dist/esm/client/webhook-builder.js +197 -0
- package/dist/esm/client/webhook-builder.js.map +1 -0
- package/dist/esm/errors.d.ts +90 -0
- package/dist/esm/errors.js +180 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.d.ts +12 -4
- package/dist/esm/index.js +59 -6
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/logger.d.ts +47 -0
- package/dist/esm/logger.js +72 -0
- package/dist/esm/logger.js.map +1 -0
- package/dist/esm/logger.test.d.ts +1 -0
- package/dist/esm/orm/column.d.ts +62 -0
- package/dist/esm/orm/column.js +62 -0
- package/dist/esm/orm/column.js.map +1 -0
- package/dist/esm/orm/field-builders.d.ts +164 -0
- package/dist/esm/orm/field-builders.js +168 -0
- package/dist/esm/orm/field-builders.js.map +1 -0
- package/dist/esm/orm/index.d.ts +4 -0
- package/dist/esm/orm/operators.d.ts +175 -0
- package/dist/esm/orm/operators.js +242 -0
- package/dist/esm/orm/operators.js.map +1 -0
- package/dist/esm/orm/table.d.ts +355 -0
- package/dist/esm/orm/table.js +200 -0
- package/dist/esm/orm/table.js.map +1 -0
- package/dist/esm/transform.d.ts +64 -0
- package/dist/esm/transform.js +110 -0
- package/dist/esm/transform.js.map +1 -0
- package/dist/esm/types.d.ts +157 -7
- package/dist/esm/types.js +7 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/validation.d.ts +22 -9
- package/dist/esm/validation.js +195 -50
- package/dist/esm/validation.js.map +1 -1
- package/package.json +19 -4
- package/src/client/batch-builder.ts +334 -0
- package/src/client/batch-request.ts +485 -0
- package/src/client/builders/default-select.ts +80 -0
- package/src/client/builders/expand-builder.ts +245 -0
- package/src/client/builders/index.ts +11 -0
- package/src/client/builders/query-string-builder.ts +49 -0
- package/src/client/builders/response-processor.ts +286 -0
- package/src/client/builders/select-mixin.ts +75 -0
- package/src/client/builders/select-utils.ts +56 -0
- package/src/client/builders/shared-types.ts +42 -0
- package/src/client/builders/table-utils.ts +87 -0
- package/src/client/database.ts +147 -89
- package/src/client/delete-builder.ts +189 -87
- package/src/client/entity-set.ts +316 -205
- package/src/client/error-parser.ts +59 -0
- package/src/client/filemaker-odata.ts +254 -41
- package/src/client/insert-builder.ts +420 -49
- package/src/client/query/expand-builder.ts +164 -0
- package/src/client/query/index.ts +13 -0
- package/src/client/query/query-builder.ts +905 -0
- package/src/client/query/response-processor.ts +236 -0
- package/src/client/query/types.ts +128 -0
- package/src/client/query/url-builder.ts +179 -0
- package/src/client/query-builder.ts +8 -1076
- package/src/client/record-builder.ts +704 -139
- package/src/client/response-processor.ts +89 -0
- package/src/client/sanitize-json.ts +66 -0
- package/src/client/schema-manager.ts +246 -0
- package/src/client/update-builder.ts +318 -90
- package/src/client/webhook-builder.ts +285 -0
- package/src/errors.ts +261 -0
- package/src/index.ts +122 -14
- package/src/logger.test.ts +34 -0
- package/src/logger.ts +140 -0
- package/src/orm/column.ts +106 -0
- package/src/orm/field-builders.ts +318 -0
- package/src/orm/index.ts +60 -0
- package/src/orm/operators.ts +487 -0
- package/src/orm/table.ts +759 -0
- package/src/transform.ts +263 -0
- package/src/types.ts +275 -55
- package/src/validation.ts +255 -55
- package/dist/esm/client/base-table.d.ts +0 -13
- package/dist/esm/client/base-table.js +0 -19
- package/dist/esm/client/base-table.js.map +0 -1
- package/dist/esm/client/query-builder.js +0 -649
- package/dist/esm/client/query-builder.js.map +0 -1
- package/dist/esm/client/table-occurrence.d.ts +0 -25
- package/dist/esm/client/table-occurrence.js +0 -47
- package/dist/esm/client/table-occurrence.js.map +0 -1
- package/dist/esm/filter-types.d.ts +0 -76
- package/src/client/base-table.ts +0 -25
- package/src/client/table-occurrence.ts +0 -100
- package/src/filter-types.ts +0 -97
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
+
import type { FMTable } from "../orm/table";
|
|
3
|
+
import type { ExecuteOptions } from "../types";
|
|
4
|
+
import type { ExpandValidationConfig } from "../validation";
|
|
5
|
+
import { ValidationError, ResponseStructureError } from "../errors";
|
|
6
|
+
import { transformResponseFields } from "../transform";
|
|
7
|
+
import { validateListResponse, validateRecord } from "../validation";
|
|
8
|
+
|
|
9
|
+
// Type for raw OData responses
|
|
10
|
+
export type ODataResponse<T = unknown> = T & {
|
|
11
|
+
"@odata.context"?: string;
|
|
12
|
+
"@odata.count"?: number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type ODataListResponse<T = unknown> = ODataResponse<{
|
|
16
|
+
value: T[];
|
|
17
|
+
}>;
|
|
18
|
+
|
|
19
|
+
export type ODataRecordResponse<T = unknown> = ODataResponse<
|
|
20
|
+
T & {
|
|
21
|
+
"@id"?: string;
|
|
22
|
+
"@editLink"?: string;
|
|
23
|
+
}
|
|
24
|
+
>;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Transform field IDs back to names using the table configuration
|
|
28
|
+
*/
|
|
29
|
+
export function applyFieldTransformation<T extends Record<string, unknown>>(
|
|
30
|
+
response: ODataResponse<T> | ODataListResponse<T>,
|
|
31
|
+
table: FMTable<any, any>,
|
|
32
|
+
expandConfigs?: ExpandValidationConfig[],
|
|
33
|
+
): ODataResponse<T> | ODataListResponse<T> {
|
|
34
|
+
return transformResponseFields(response, table, expandConfigs) as
|
|
35
|
+
| ODataResponse<T>
|
|
36
|
+
| ODataListResponse<T>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Apply schema validation and transformation to data
|
|
41
|
+
*/
|
|
42
|
+
export async function applyValidation<T extends Record<string, unknown>>(
|
|
43
|
+
data: T | T[],
|
|
44
|
+
schema?: Record<string, StandardSchemaV1>,
|
|
45
|
+
selectedFields?: (keyof T)[],
|
|
46
|
+
expandConfigs?: ExpandValidationConfig[],
|
|
47
|
+
): Promise<
|
|
48
|
+
| { valid: true; data: T | T[] }
|
|
49
|
+
| { valid: false; error: ValidationError | ResponseStructureError }
|
|
50
|
+
> {
|
|
51
|
+
if (Array.isArray(data)) {
|
|
52
|
+
// Validate as a list
|
|
53
|
+
const validation = await validateListResponse<T>(
|
|
54
|
+
{ value: data },
|
|
55
|
+
schema,
|
|
56
|
+
selectedFields as string[] | undefined,
|
|
57
|
+
expandConfigs,
|
|
58
|
+
);
|
|
59
|
+
if (!validation.valid) {
|
|
60
|
+
return { valid: false, error: validation.error };
|
|
61
|
+
}
|
|
62
|
+
return { valid: true, data: validation.data };
|
|
63
|
+
} else {
|
|
64
|
+
// Validate as a single record
|
|
65
|
+
const validation = await validateRecord<T>(
|
|
66
|
+
data,
|
|
67
|
+
schema,
|
|
68
|
+
selectedFields,
|
|
69
|
+
expandConfigs,
|
|
70
|
+
);
|
|
71
|
+
if (!validation.valid) {
|
|
72
|
+
return { valid: false, error: validation.error };
|
|
73
|
+
}
|
|
74
|
+
return { valid: true, data: validation.data };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Extract value array from OData list response, or wrap single record in array
|
|
80
|
+
*/
|
|
81
|
+
export function extractListValue<T>(
|
|
82
|
+
response: ODataListResponse<T> | ODataRecordResponse<T>,
|
|
83
|
+
): T[] {
|
|
84
|
+
if ("value" in response && Array.isArray(response.value)) {
|
|
85
|
+
return response.value;
|
|
86
|
+
}
|
|
87
|
+
// Single record responses return the record directly
|
|
88
|
+
return [response as T];
|
|
89
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileMaker OData API sometimes returns invalid JSON containing unquoted `?`
|
|
3
|
+
* characters as field values (e.g., `"fieldName": ?`), which causes JSON.parse()
|
|
4
|
+
* to fail. This module provides utilities to sanitize such responses before parsing.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ResponseParseError } from "../errors";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Sanitizes FileMaker OData JSON responses by replacing unquoted `?` values with `null`.
|
|
11
|
+
*
|
|
12
|
+
* FileMaker uses `?` to represent undefined/null values in its OData responses,
|
|
13
|
+
* but this is not valid JSON. This function converts those to proper `null` values.
|
|
14
|
+
*
|
|
15
|
+
* The regex uses two patterns:
|
|
16
|
+
* 1. `/:\s*\?(?=\s*[,}\]])/g` - for values in objects (after `:`)
|
|
17
|
+
* 2. `/(?<=[\[,])\s*\?(?=\s*[,\]])/g` - for values in arrays (after `[` or `,`)
|
|
18
|
+
*
|
|
19
|
+
* @param text - The raw response text from FileMaker OData API
|
|
20
|
+
* @returns Sanitized JSON string with `?` values replaced by `null`
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* sanitizeFileMakerJson('{"field1": "valid", "field2": ?, "field3": null}')
|
|
24
|
+
* // Returns: '{"field1": "valid", "field2": null, "field3": null}'
|
|
25
|
+
*/
|
|
26
|
+
export function sanitizeFileMakerJson(text: string): string {
|
|
27
|
+
// Replace unquoted ? values in objects (after colon)
|
|
28
|
+
// Also handles arrays when the array is a value in an object
|
|
29
|
+
let result = text.replace(/:\s*\?(?=\s*[,}\]])/g, ": null");
|
|
30
|
+
|
|
31
|
+
// Replace unquoted ? values directly in arrays (not after colon)
|
|
32
|
+
// e.g., [1, ?, 3] -> [1, null, 3]
|
|
33
|
+
result = result.replace(/(?<=[\[,])\s*\?(?=\s*[,\]])/g, " null");
|
|
34
|
+
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Safely parses a Response body as JSON, handling FileMaker's invalid JSON responses.
|
|
40
|
+
*
|
|
41
|
+
* This function reads the response as text first, sanitizes any invalid `?` values,
|
|
42
|
+
* and then parses the sanitized JSON. This approach handles the case where FileMaker
|
|
43
|
+
* returns a Content-Type of application/json but the body contains invalid JSON.
|
|
44
|
+
*
|
|
45
|
+
* @param response - The fetch Response object
|
|
46
|
+
* @returns Parsed JSON data
|
|
47
|
+
* @throws ResponseParseError if the JSON is still invalid after sanitization (includes sanitized text for debugging)
|
|
48
|
+
*/
|
|
49
|
+
export async function safeJsonParse<T = unknown>(
|
|
50
|
+
response: Response,
|
|
51
|
+
): Promise<T> {
|
|
52
|
+
const text = await response.text();
|
|
53
|
+
const sanitized = sanitizeFileMakerJson(text);
|
|
54
|
+
try {
|
|
55
|
+
return JSON.parse(sanitized) as T;
|
|
56
|
+
} catch (err) {
|
|
57
|
+
throw new ResponseParseError(
|
|
58
|
+
response.url,
|
|
59
|
+
`Failed to parse response as JSON: ${err instanceof Error ? err.message : "Unknown error"}`,
|
|
60
|
+
{
|
|
61
|
+
rawText: sanitized,
|
|
62
|
+
cause: err instanceof Error ? err : undefined,
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import type { FFetchOptions } from "@fetchkit/ffetch";
|
|
2
|
+
import type { ExecutionContext } from "../types";
|
|
3
|
+
|
|
4
|
+
type GenericField = {
|
|
5
|
+
name: string;
|
|
6
|
+
nullable?: boolean;
|
|
7
|
+
primary?: boolean;
|
|
8
|
+
unique?: boolean;
|
|
9
|
+
global?: boolean;
|
|
10
|
+
repetitions?: number;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type StringField = GenericField & {
|
|
14
|
+
type: "string";
|
|
15
|
+
maxLength?: number;
|
|
16
|
+
default?: "USER" | "USERNAME" | "CURRENT_USER";
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
type NumericField = GenericField & {
|
|
20
|
+
type: "numeric";
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type DateField = GenericField & {
|
|
24
|
+
type: "date";
|
|
25
|
+
default?: "CURRENT_DATE" | "CURDATE";
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
type TimeField = GenericField & {
|
|
29
|
+
type: "time";
|
|
30
|
+
default?: "CURRENT_TIME" | "CURTIME";
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
type TimestampField = GenericField & {
|
|
34
|
+
type: "timestamp";
|
|
35
|
+
default?: "CURRENT_TIMESTAMP" | "CURTIMESTAMP";
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
type ContainerField = GenericField & {
|
|
39
|
+
type: "container";
|
|
40
|
+
externalSecurePath?: string;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type Field =
|
|
44
|
+
| StringField
|
|
45
|
+
| NumericField
|
|
46
|
+
| DateField
|
|
47
|
+
| TimeField
|
|
48
|
+
| TimestampField
|
|
49
|
+
| ContainerField;
|
|
50
|
+
|
|
51
|
+
export type {
|
|
52
|
+
StringField,
|
|
53
|
+
NumericField,
|
|
54
|
+
DateField,
|
|
55
|
+
TimeField,
|
|
56
|
+
TimestampField,
|
|
57
|
+
ContainerField,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
type FileMakerField = Omit<Field, "type" | "repetitions" | "maxLength"> & {
|
|
61
|
+
type: string;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
type TableDefinition = {
|
|
65
|
+
tableName: string;
|
|
66
|
+
fields: FileMakerField[];
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export class SchemaManager {
|
|
70
|
+
public constructor(
|
|
71
|
+
private readonly databaseName: string,
|
|
72
|
+
private readonly context: ExecutionContext,
|
|
73
|
+
) {}
|
|
74
|
+
|
|
75
|
+
public async createTable(
|
|
76
|
+
tableName: string,
|
|
77
|
+
fields: Field[],
|
|
78
|
+
options?: RequestInit & FFetchOptions,
|
|
79
|
+
): Promise<TableDefinition> {
|
|
80
|
+
const result = await this.context._makeRequest<TableDefinition>(
|
|
81
|
+
`/${this.databaseName}/FileMaker_Tables`,
|
|
82
|
+
{
|
|
83
|
+
method: "POST",
|
|
84
|
+
body: JSON.stringify({
|
|
85
|
+
tableName,
|
|
86
|
+
fields: fields.map(SchemaManager.compileFieldDefinition),
|
|
87
|
+
}),
|
|
88
|
+
...options,
|
|
89
|
+
},
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
if (result.error) {
|
|
93
|
+
throw result.error;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return result.data;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public async addFields(
|
|
100
|
+
tableName: string,
|
|
101
|
+
fields: Field[],
|
|
102
|
+
options?: RequestInit & FFetchOptions,
|
|
103
|
+
): Promise<TableDefinition> {
|
|
104
|
+
const result = await this.context._makeRequest<TableDefinition>(
|
|
105
|
+
`/${this.databaseName}/FileMaker_Tables/${tableName}`,
|
|
106
|
+
{
|
|
107
|
+
method: "PATCH",
|
|
108
|
+
body: JSON.stringify({
|
|
109
|
+
fields: fields.map(SchemaManager.compileFieldDefinition),
|
|
110
|
+
}),
|
|
111
|
+
...options,
|
|
112
|
+
},
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
if (result.error) {
|
|
116
|
+
throw result.error;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return result.data;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public async deleteTable(
|
|
123
|
+
tableName: string,
|
|
124
|
+
options?: RequestInit & FFetchOptions,
|
|
125
|
+
): Promise<void> {
|
|
126
|
+
const result = await this.context._makeRequest(
|
|
127
|
+
`/${this.databaseName}/FileMaker_Tables/${tableName}`,
|
|
128
|
+
{ method: "DELETE", ...options },
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
if (result.error) {
|
|
132
|
+
throw result.error;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public async deleteField(
|
|
137
|
+
tableName: string,
|
|
138
|
+
fieldName: string,
|
|
139
|
+
options?: RequestInit & FFetchOptions,
|
|
140
|
+
): Promise<void> {
|
|
141
|
+
const result = await this.context._makeRequest(
|
|
142
|
+
`/${this.databaseName}/FileMaker_Tables/${tableName}/${fieldName}`,
|
|
143
|
+
{
|
|
144
|
+
method: "DELETE",
|
|
145
|
+
...options,
|
|
146
|
+
},
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
if (result.error) {
|
|
150
|
+
throw result.error;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public async createIndex(
|
|
155
|
+
tableName: string,
|
|
156
|
+
fieldName: string,
|
|
157
|
+
options?: RequestInit & FFetchOptions,
|
|
158
|
+
): Promise<{ indexName: string }> {
|
|
159
|
+
const result = await this.context._makeRequest<{ indexName: string }>(
|
|
160
|
+
`/${this.databaseName}/FileMaker_Indexes/${tableName}`,
|
|
161
|
+
{
|
|
162
|
+
method: "POST",
|
|
163
|
+
body: JSON.stringify({ indexName: fieldName }),
|
|
164
|
+
...options,
|
|
165
|
+
},
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
if (result.error) {
|
|
169
|
+
throw result.error;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return result.data;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public async deleteIndex(
|
|
176
|
+
tableName: string,
|
|
177
|
+
fieldName: string,
|
|
178
|
+
options?: RequestInit & FFetchOptions,
|
|
179
|
+
): Promise<void> {
|
|
180
|
+
const result = await this.context._makeRequest(
|
|
181
|
+
`/${this.databaseName}/FileMaker_Indexes/${tableName}/${fieldName}`,
|
|
182
|
+
{
|
|
183
|
+
method: "DELETE",
|
|
184
|
+
...options,
|
|
185
|
+
},
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
if (result.error) {
|
|
189
|
+
throw result.error;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
private static compileFieldDefinition(field: Field): FileMakerField {
|
|
194
|
+
let type: string = field.type;
|
|
195
|
+
const repetitions = field.repetitions;
|
|
196
|
+
|
|
197
|
+
// Handle string fields - convert to varchar and add maxLength if present
|
|
198
|
+
if (field.type === "string") {
|
|
199
|
+
type = "varchar";
|
|
200
|
+
const stringField = field as StringField;
|
|
201
|
+
if (stringField.maxLength !== undefined) {
|
|
202
|
+
type += `(${stringField.maxLength})`;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Add repetitions suffix if present
|
|
207
|
+
if (repetitions !== undefined) {
|
|
208
|
+
type += `[${repetitions}]`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Build the result object, excluding type, maxLength, and repetitions
|
|
212
|
+
const result: any = {
|
|
213
|
+
name: field.name,
|
|
214
|
+
type,
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// Add optional properties that FileMaker expects
|
|
218
|
+
if (field.nullable !== undefined) result.nullable = field.nullable;
|
|
219
|
+
if (field.primary !== undefined) result.primary = field.primary;
|
|
220
|
+
if (field.unique !== undefined) result.unique = field.unique;
|
|
221
|
+
if (field.global !== undefined) result.global = field.global;
|
|
222
|
+
|
|
223
|
+
// Add type-specific properties
|
|
224
|
+
if (field.type === "string") {
|
|
225
|
+
const stringField = field as StringField;
|
|
226
|
+
if (stringField.default !== undefined)
|
|
227
|
+
result.default = stringField.default;
|
|
228
|
+
} else if (field.type === "date") {
|
|
229
|
+
const dateField = field as DateField;
|
|
230
|
+
if (dateField.default !== undefined) result.default = dateField.default;
|
|
231
|
+
} else if (field.type === "time") {
|
|
232
|
+
const timeField = field as TimeField;
|
|
233
|
+
if (timeField.default !== undefined) result.default = timeField.default;
|
|
234
|
+
} else if (field.type === "timestamp") {
|
|
235
|
+
const timestampField = field as TimestampField;
|
|
236
|
+
if (timestampField.default !== undefined)
|
|
237
|
+
result.default = timestampField.default;
|
|
238
|
+
} else if (field.type === "container") {
|
|
239
|
+
const containerField = field as ContainerField;
|
|
240
|
+
if (containerField.externalSecurePath !== undefined)
|
|
241
|
+
result.externalSecurePath = containerField.externalSecurePath;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return result as FileMakerField;
|
|
245
|
+
}
|
|
246
|
+
}
|