@jd-data-limited/easy-fm 4.0.16 → 4.1.0
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/package.json +12 -6
- package/src/FMError.d.ts +2 -2
- package/src/FMError.js +507 -508
- package/src/FMError.ts +510 -511
- package/src/connection/FMHost.d.ts +23 -5
- package/src/connection/FMHost.js +42 -26
- package/src/connection/FMHost.ts +63 -49
- package/src/connection/HostBase.d.ts +3 -3
- package/src/connection/HostBase.ts +5 -5
- package/src/connection/database.d.ts +50 -17
- package/src/connection/database.js +94 -66
- package/src/connection/database.ts +125 -105
- package/src/connection/databaseBase.d.ts +11 -6
- package/src/connection/databaseBase.ts +9 -8
- package/src/connection/generateAuthorizationHeaders.d.ts +1 -1
- package/src/connection/generateAuthorizationHeaders.js +10 -10
- package/src/connection/generateAuthorizationHeaders.ts +21 -21
- package/src/databaseStructure.d.ts +2 -4
- package/src/databaseStructure.ts +3 -5
- package/src/index.d.ts +17 -17
- package/src/index.js +13 -13
- package/src/index.ts +24 -24
- package/src/layouts/layout.d.ts +17 -6
- package/src/layouts/layout.js +19 -8
- package/src/layouts/layout.ts +33 -23
- package/src/layouts/layoutBase.d.ts +5 -5
- package/src/layouts/layoutBase.ts +6 -6
- package/src/layouts/layoutInterface.d.ts +3 -5
- package/src/layouts/layoutInterface.ts +4 -6
- package/src/layouts/layoutRecordManager.d.ts +29 -6
- package/src/layouts/layoutRecordManager.js +32 -9
- package/src/layouts/layoutRecordManager.ts +42 -19
- package/src/layouts/recordFieldsMap.d.ts +2 -4
- package/src/layouts/recordFieldsMap.ts +2 -4
- package/src/models/apiResults.d.ts +7 -13
- package/src/models/apiResults.ts +58 -58
- package/src/records/field.d.ts +42 -12
- package/src/records/field.js +69 -59
- package/src/records/field.ts +102 -81
- package/src/records/getOperations/recordGetOperation.d.ts +44 -24
- package/src/records/getOperations/recordGetOperation.js +87 -61
- package/src/records/getOperations/recordGetOperation.ts +127 -108
- package/src/records/layoutRecord.d.ts +28 -14
- package/src/records/layoutRecord.js +69 -60
- package/src/records/layoutRecord.ts +121 -119
- package/src/records/layoutRecordBase.d.ts +2 -2
- package/src/records/layoutRecordBase.ts +3 -3
- package/src/records/portal.d.ts +19 -5
- package/src/records/portal.js +19 -5
- package/src/records/portal.ts +28 -16
- package/src/records/portalBase.d.ts +5 -5
- package/src/records/portalBase.ts +6 -6
- package/src/records/portalRecord.d.ts +16 -8
- package/src/records/portalRecord.js +16 -6
- package/src/records/portalRecord.ts +29 -19
- package/src/records/recordBase.d.ts +17 -7
- package/src/records/recordBase.js +23 -16
- package/src/records/recordBase.ts +41 -37
- package/src/types.d.ts +21 -24
- package/src/types.ts +55 -59
- package/src/utils/query.d.ts +7 -7
- package/src/utils/query.js +10 -10
- package/src/utils/query.ts +19 -20
package/src/records/field.ts
CHANGED
|
@@ -2,39 +2,53 @@
|
|
|
2
2
|
* Copyright (c) 2023-2024. See LICENSE file for more information
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import * as http from
|
|
6
|
-
import {ContainerBufferResult, DownloadModes,
|
|
7
|
-
import {ApiFieldDisplayTypes, ApiFieldMetadata, ApiFieldResultTypes, ApiFieldTypes} from
|
|
8
|
-
import {LayoutBase} from
|
|
9
|
-
import {Moment} from
|
|
5
|
+
import type * as http from 'http'
|
|
6
|
+
import {type ContainerBufferResult, DownloadModes, RecordTypes} from '../types.js'
|
|
7
|
+
import {ApiFieldDisplayTypes, type ApiFieldMetadata, ApiFieldResultTypes, ApiFieldTypes} from '../models/apiResults.js'
|
|
8
|
+
import {type LayoutBase} from '../layouts/layoutBase.js'
|
|
9
|
+
import {type Moment} from 'moment'
|
|
10
10
|
|
|
11
11
|
export type FieldValue = string | number | Moment | Container
|
|
12
12
|
export type Container = null
|
|
13
13
|
|
|
14
|
-
export
|
|
14
|
+
export interface Parentable {
|
|
15
|
+
layout: LayoutBase
|
|
16
|
+
type: RecordTypes
|
|
17
|
+
endpoint: string
|
|
18
|
+
portal?: { name: string }
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A class representing a field in a record.
|
|
23
|
+
*
|
|
24
|
+
* @template T - The type of the field value.
|
|
25
|
+
*/
|
|
15
26
|
export class Field<T extends FieldValue> {
|
|
16
|
-
parent: Parentable
|
|
17
|
-
id: string
|
|
18
|
-
protected _value: T
|
|
19
|
-
edited: boolean
|
|
27
|
+
parent: Parentable
|
|
28
|
+
id: string
|
|
29
|
+
protected _value: T | null
|
|
30
|
+
edited: boolean
|
|
20
31
|
|
|
21
|
-
constructor(record: Parentable, id: string, contents: T) {
|
|
32
|
+
constructor (record: Parentable, id: string, contents: T) {
|
|
22
33
|
this.parent = record
|
|
23
34
|
this.id = id
|
|
24
35
|
this._value = contents
|
|
25
36
|
this.edited = false
|
|
26
37
|
}
|
|
27
38
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Sets the value of the field.
|
|
41
|
+
*
|
|
42
|
+
* @param {T | null} content - The new content value to be set. Can be either the type T or null.
|
|
43
|
+
* @throws {Error} Cannot set container value using set(). Use upload() instead, if the result is a 'container'.
|
|
44
|
+
*/
|
|
45
|
+
set (content: T | null) {
|
|
46
|
+
if (this.metadata.result === 'container') throw new Error('Cannot set container value using set(). Use upload() instead.')
|
|
33
47
|
else this._value = content
|
|
34
48
|
this.edited = true
|
|
35
49
|
}
|
|
36
50
|
|
|
37
|
-
get metadata(): ApiFieldMetadata {
|
|
51
|
+
get metadata (): ApiFieldMetadata {
|
|
38
52
|
if (!this.parent.layout.metadata) {
|
|
39
53
|
// Default to a regular text field
|
|
40
54
|
return {
|
|
@@ -51,30 +65,29 @@ export class Field<T extends FieldValue> {
|
|
|
51
65
|
numeric: false,
|
|
52
66
|
timeOfDay: false,
|
|
53
67
|
repetitions: 1,
|
|
54
|
-
valueList:
|
|
68
|
+
valueList: ''
|
|
55
69
|
}
|
|
56
70
|
}
|
|
57
|
-
if (this.parent.type === RecordTypes.PORTAL) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
return this.parent.layout.metadata.fieldMetaData.find(i => i.name === this.id) || {
|
|
71
|
+
if (this.parent.type === RecordTypes.PORTAL && this.parent.portal) {
|
|
72
|
+
return this.parent.layout.metadata.portalMetaData[this.parent.portal.name || 'portal not attached'].find(i => i.name === this.id) ??
|
|
73
|
+
{
|
|
74
|
+
name: this.id.toString(),
|
|
75
|
+
type: ApiFieldTypes.NORMAL,
|
|
76
|
+
displayType: ApiFieldDisplayTypes.EDIT_TEXT,
|
|
77
|
+
result: ApiFieldResultTypes.TEXT,
|
|
78
|
+
global: false,
|
|
79
|
+
autoEnter: true,
|
|
80
|
+
fourDigitYear: false,
|
|
81
|
+
maxRepeat: 1,
|
|
82
|
+
maxCharacters: 0,
|
|
83
|
+
notEmpty: false,
|
|
84
|
+
numeric: false,
|
|
85
|
+
timeOfDay: false,
|
|
86
|
+
repetitions: 1,
|
|
87
|
+
valueList: ''
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
return this.parent.layout.metadata.fieldMetaData.find(i => i.name === this.id) ?? {
|
|
78
91
|
name: this.id.toString(),
|
|
79
92
|
type: ApiFieldTypes.NORMAL,
|
|
80
93
|
displayType: ApiFieldDisplayTypes.EDIT_TEXT,
|
|
@@ -88,80 +101,88 @@ export class Field<T extends FieldValue> {
|
|
|
88
101
|
numeric: false,
|
|
89
102
|
timeOfDay: false,
|
|
90
103
|
repetitions: 1,
|
|
91
|
-
valueList:
|
|
104
|
+
valueList: ''
|
|
92
105
|
}
|
|
93
106
|
}
|
|
94
107
|
}
|
|
95
108
|
|
|
96
|
-
get value(): T {
|
|
109
|
+
get value (): T | null {
|
|
97
110
|
// if (this.metadata.result === "container") throw "Use await field.stream() to get the contents of a container field, instead of field.value"
|
|
98
111
|
return this._value
|
|
99
112
|
}
|
|
100
113
|
|
|
101
|
-
set value(value: T) {
|
|
114
|
+
set value (value: T) {
|
|
102
115
|
this._value = value
|
|
103
116
|
}
|
|
104
117
|
|
|
105
|
-
get string(): string {
|
|
106
|
-
if (typeof this._value ===
|
|
107
|
-
return this._value
|
|
108
|
-
}
|
|
109
|
-
throw "Field value is not a string"
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
get date(): Date {
|
|
113
|
-
if (this._value instanceof Date) {
|
|
118
|
+
get string (): string {
|
|
119
|
+
if (typeof this._value === 'string') {
|
|
114
120
|
return this._value
|
|
115
121
|
}
|
|
116
|
-
throw
|
|
122
|
+
throw new Error('Field value is not a string')
|
|
117
123
|
}
|
|
118
124
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Uploads a file to the container field.
|
|
127
|
+
*
|
|
128
|
+
* @param {Buffer} buffer - The file content as a buffer.
|
|
129
|
+
* @param {string} filename - The filename of the file.
|
|
130
|
+
* @param {string} mime - The MIME type of the file.
|
|
131
|
+
*
|
|
132
|
+
* @throws {Error} - Cannot upload a file to the field if it's not a container field.
|
|
133
|
+
* @throws {Error} - Upload failed with HTTP error.
|
|
134
|
+
*
|
|
135
|
+
* @returns {Promise<void>} - A promise that resolves when the file is successfully uploaded.
|
|
136
|
+
*/
|
|
137
|
+
async upload (buffer: Buffer, filename: string, mime: string): Promise<void> {
|
|
138
|
+
if (this.metadata.result !== 'container') {
|
|
139
|
+
throw new Error('Cannot upload a file to the field; ' + this.id + ' (not a container field)')
|
|
122
140
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
let res = await this.parent.layout.database.apiRequestRaw(`${this.parent.endpoint}/containers/${this.id}/1`, {
|
|
133
|
-
method: "POST",
|
|
134
|
-
// @ts-ignore
|
|
141
|
+
const form = new FormData()
|
|
142
|
+
form.append('upload', new File([buffer], filename, {type: mime}))
|
|
143
|
+
|
|
144
|
+
const res = await this.parent.layout.database._apiRequestRaw(`${this.parent.endpoint}/containers/${this.id}/1`, {
|
|
145
|
+
method: 'POST',
|
|
146
|
+
headers: {
|
|
147
|
+
Authorization: 'Bearer ' + this.parent.layout.database.token,
|
|
148
|
+
'Content-Type': 'multipart/form-data'
|
|
149
|
+
},
|
|
135
150
|
body: form
|
|
136
151
|
})
|
|
137
152
|
if (!res.ok) throw new Error(`Upload failed with HTTP error: ${res.status} (${res.statusText})`)
|
|
138
153
|
}
|
|
139
154
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
155
|
+
/**
|
|
156
|
+
* Downloads a resource from the server using the specified download mode.
|
|
157
|
+
*
|
|
158
|
+
* @param {DownloadModes} mode - The mode to use for downloading the resource.
|
|
159
|
+
* @return {Promise<http.IncomingMessage>} - A promise that resolves with the incoming message representing the downloaded resource.
|
|
160
|
+
*/
|
|
161
|
+
download (mode: DownloadModes.Stream): Promise<http.IncomingMessage>
|
|
162
|
+
download (mode: DownloadModes.Buffer): Promise<ContainerBufferResult>
|
|
163
|
+
async download (mode: DownloadModes = DownloadModes.Stream): Promise<http.IncomingMessage | ContainerBufferResult> {
|
|
164
|
+
if (this.metadata.result !== ApiFieldResultTypes.CONTAINER) throw new Error('Cannot perform download() on a non-container field')
|
|
165
|
+
|
|
166
|
+
const stream = await this.parent.layout.database.streamURL(this.string)
|
|
146
167
|
if (mode === DownloadModes.Stream) {
|
|
147
168
|
return stream
|
|
148
169
|
}
|
|
149
170
|
|
|
150
|
-
|
|
151
|
-
return new Promise((resolve, reject) => {
|
|
152
|
-
stream.on(
|
|
171
|
+
const body: Uint8Array[] = []
|
|
172
|
+
return await new Promise((resolve, reject) => {
|
|
173
|
+
stream.on('data', (chunk: Uint8Array) => {
|
|
153
174
|
body.push(chunk)
|
|
154
175
|
})
|
|
155
|
-
stream.on(
|
|
176
|
+
stream.on('error', (e) => {
|
|
156
177
|
reject(e)
|
|
157
178
|
})
|
|
158
|
-
stream.on(
|
|
179
|
+
stream.on('end', () => {
|
|
159
180
|
resolve({
|
|
160
181
|
buffer: Buffer.concat(body),
|
|
161
|
-
mime: stream.headers[
|
|
182
|
+
mime: stream.headers['content-type'],
|
|
162
183
|
request: stream
|
|
163
|
-
}
|
|
184
|
+
} satisfies ContainerBufferResult)
|
|
164
185
|
})
|
|
165
186
|
})
|
|
166
187
|
}
|
|
167
|
-
}
|
|
188
|
+
}
|
|
@@ -1,54 +1,74 @@
|
|
|
1
|
-
import { LayoutInterface } from
|
|
2
|
-
import { PickPortals, ScriptRequestData } from
|
|
3
|
-
import { LayoutBase } from
|
|
4
|
-
import { LayoutRecord } from
|
|
5
|
-
import { Query } from
|
|
6
|
-
export type SortOrder =
|
|
7
|
-
export type FindRequestRaw =
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export type FindRequest = {
|
|
11
|
-
[key: string]: Query;
|
|
12
|
-
};
|
|
13
|
-
export type PortalRequest = {
|
|
1
|
+
import { type LayoutInterface } from '../../layouts/layoutInterface.js';
|
|
2
|
+
import { type PickPortals, type ScriptRequestData } from '../../types.js';
|
|
3
|
+
import { type LayoutBase } from '../../layouts/layoutBase.js';
|
|
4
|
+
import { LayoutRecord } from '../layoutRecord.js';
|
|
5
|
+
import { type Query } from '../../utils/query.js';
|
|
6
|
+
export type SortOrder = 'ascend' | 'descend';
|
|
7
|
+
export type FindRequestRaw = Record<string, string>;
|
|
8
|
+
export type FindRequest = Record<string, Query>;
|
|
9
|
+
export interface PortalRequest {
|
|
14
10
|
name: string;
|
|
15
|
-
}
|
|
11
|
+
}
|
|
16
12
|
type PortalData<T extends LayoutInterface> = {
|
|
17
|
-
[key in keyof T[
|
|
13
|
+
[key in keyof T['portals']]: {
|
|
18
14
|
limit: number;
|
|
19
15
|
offset: number;
|
|
20
16
|
};
|
|
21
17
|
};
|
|
22
|
-
export
|
|
18
|
+
export interface GetOperationOptions<T extends LayoutInterface> {
|
|
23
19
|
portals: Partial<PortalData<T>>;
|
|
24
20
|
limit?: number;
|
|
25
21
|
offset?: number;
|
|
26
|
-
}
|
|
22
|
+
}
|
|
27
23
|
export declare class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOperationOptions<T>> {
|
|
28
24
|
protected layout: LayoutBase;
|
|
29
25
|
protected limit: number;
|
|
30
26
|
protected scriptData: ScriptRequestData;
|
|
31
|
-
protected sortData: {
|
|
27
|
+
protected sortData: Array<{
|
|
32
28
|
fieldName: string;
|
|
33
29
|
sortOrder: SortOrder;
|
|
34
|
-
}
|
|
30
|
+
}>;
|
|
35
31
|
protected portals: Partial<PortalData<T>>;
|
|
36
32
|
protected offset: number;
|
|
37
|
-
protected queries: {
|
|
33
|
+
protected queries: Array<{
|
|
38
34
|
req: FindRequestRaw;
|
|
39
35
|
omit: boolean;
|
|
40
|
-
}
|
|
36
|
+
}>;
|
|
41
37
|
constructor(layout: LayoutBase, options: OPTIONS);
|
|
42
38
|
get isFindRequest(): boolean;
|
|
43
39
|
private formatQueries;
|
|
44
|
-
protected generateParamsBody(offset: number, limit: number):
|
|
45
|
-
[key: string]: any;
|
|
46
|
-
};
|
|
40
|
+
protected generateParamsBody(offset: number, limit: number): Record<string, any>;
|
|
47
41
|
protected generateParamsURL(offset: number, limit: number): URLSearchParams;
|
|
42
|
+
/**
|
|
43
|
+
* Configures any FileMaker scripts to be run as a part of the request
|
|
44
|
+
*
|
|
45
|
+
* @param {ScriptRequestData} scripts - The script request data to set.
|
|
46
|
+
* @return {this} - The current instance of the class.
|
|
47
|
+
*/
|
|
48
48
|
scripts(scripts: ScriptRequestData): this;
|
|
49
|
+
/**
|
|
50
|
+
* Sorts the data based on the given field name and sort order.
|
|
51
|
+
*
|
|
52
|
+
* @param {string} fieldName - The name of the field by which the data should be sorted.
|
|
53
|
+
* @param {SortOrder} sortOrder - The sort order to be applied (either "asc" for ascending or "desc" for descending).
|
|
54
|
+
*
|
|
55
|
+
* @return {this} - Returns the current instance of the object.
|
|
56
|
+
*/
|
|
49
57
|
sort(fieldName: string, sortOrder: SortOrder): this;
|
|
50
58
|
private parseFindRequest;
|
|
59
|
+
/**
|
|
60
|
+
* Adds a new request/query to the list of queries.
|
|
61
|
+
*
|
|
62
|
+
* @param {FindRequest} query - The find request to be added.
|
|
63
|
+
* @param {boolean} [omit=false] - Flag to indicate if the find request should be omitted.
|
|
64
|
+
* @return {Object} - The current object instance.
|
|
65
|
+
*/
|
|
51
66
|
addRequest(query: FindRequest, omit?: boolean): this;
|
|
67
|
+
/**
|
|
68
|
+
* Perform a fetch operation.
|
|
69
|
+
*
|
|
70
|
+
* @returns {Promise} A promise that resolves with the result of the fetch operation.
|
|
71
|
+
*/
|
|
52
72
|
fetch(): Promise<LayoutRecord<PickPortals<T, keyof OPTIONS["portals"]>>[]>;
|
|
53
73
|
private performFind;
|
|
54
74
|
[Symbol.asyncIterator](): {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Copyright (c) 2023-2024. See LICENSE file for more information
|
|
3
3
|
*/
|
|
4
|
-
import { LayoutRecord } from
|
|
5
|
-
import { FMError } from
|
|
6
|
-
import { FindRequestSymbol } from
|
|
4
|
+
import { LayoutRecord } from '../layoutRecord.js';
|
|
5
|
+
import { FMError } from '../../FMError.js';
|
|
6
|
+
import { FindRequestSymbol } from '../../utils/query.js';
|
|
7
7
|
export class RecordGetOperation {
|
|
8
8
|
layout;
|
|
9
9
|
limit = 100;
|
|
@@ -16,16 +16,16 @@ export class RecordGetOperation {
|
|
|
16
16
|
this.layout = layout;
|
|
17
17
|
this.sortData = [];
|
|
18
18
|
this.portals = options.portals;
|
|
19
|
-
this.offset = options.offset
|
|
20
|
-
this.limit = options.limit
|
|
19
|
+
this.offset = options.offset ?? 1; // Offset refers to the starting record. offset 1 is the same as no offset.
|
|
20
|
+
this.limit = options.limit ?? 100;
|
|
21
21
|
}
|
|
22
22
|
get isFindRequest() {
|
|
23
23
|
return this.queries.length !== 0;
|
|
24
24
|
}
|
|
25
25
|
formatQueries() {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
for (
|
|
26
|
+
const test = this.queries.map(query => {
|
|
27
|
+
const out = {};
|
|
28
|
+
for (const key of Object.keys(query.req)) {
|
|
29
29
|
if (query.req[key])
|
|
30
30
|
out[key] = query.req[key];
|
|
31
31
|
else {
|
|
@@ -33,7 +33,7 @@ export class RecordGetOperation {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
if (query.omit)
|
|
36
|
-
out.omit =
|
|
36
|
+
out.omit = 'true';
|
|
37
37
|
return out;
|
|
38
38
|
});
|
|
39
39
|
return test;
|
|
@@ -47,22 +47,22 @@ export class RecordGetOperation {
|
|
|
47
47
|
if (this.sortData.length !== 0)
|
|
48
48
|
params.sort = this.sortData;
|
|
49
49
|
if (this.scriptData.after)
|
|
50
|
-
params
|
|
50
|
+
params.script = this.scriptData.after.name;
|
|
51
51
|
if (this.scriptData.after?.parameter)
|
|
52
|
-
params[
|
|
52
|
+
params['script.param'] = this.scriptData.after.parameter;
|
|
53
53
|
if (this.scriptData.presort)
|
|
54
|
-
params[
|
|
54
|
+
params['script.presort'] = this.scriptData.presort.name;
|
|
55
55
|
if (this.scriptData.presort?.parameter)
|
|
56
|
-
params[
|
|
56
|
+
params['script.presort.param'] = this.scriptData.presort.parameter;
|
|
57
57
|
if (this.scriptData.prerequest)
|
|
58
|
-
params[
|
|
58
|
+
params['script.prerequest'] = this.scriptData.prerequest.name;
|
|
59
59
|
if (this.scriptData.prerequest?.parameter)
|
|
60
|
-
params[
|
|
60
|
+
params['script.prerequest.param'] = this.scriptData.prerequest.parameter;
|
|
61
61
|
if (this.queries.length !== 0)
|
|
62
|
-
params
|
|
63
|
-
|
|
64
|
-
params
|
|
65
|
-
for (
|
|
62
|
+
params.query = this.formatQueries();
|
|
63
|
+
const portals = Object.keys(this.portals);
|
|
64
|
+
params.portal = portals;
|
|
65
|
+
for (const portal of portals) {
|
|
66
66
|
params[`offset.${portal.toString()}`] = this.portals[portal]?.offset;
|
|
67
67
|
params[`limit.${portal.toString()}`] = this.portals[portal]?.limit;
|
|
68
68
|
}
|
|
@@ -72,80 +72,106 @@ export class RecordGetOperation {
|
|
|
72
72
|
const params = new URLSearchParams({
|
|
73
73
|
_limit: limit.toString(),
|
|
74
74
|
_offset: offset.toString(),
|
|
75
|
-
dateformats:
|
|
75
|
+
dateformats: '2' // Ensure dates are received in ISO8601 format
|
|
76
76
|
});
|
|
77
77
|
if (this.sortData.length !== 0)
|
|
78
|
-
params.set(
|
|
78
|
+
params.set('_sort', JSON.stringify(this.sortData));
|
|
79
79
|
if (this.scriptData.after)
|
|
80
|
-
params.set(
|
|
80
|
+
params.set('script', this.scriptData.after.name);
|
|
81
81
|
if (this.scriptData.after?.parameter)
|
|
82
|
-
params.set(
|
|
82
|
+
params.set('script.param', this.scriptData.after.parameter);
|
|
83
83
|
if (this.scriptData.presort)
|
|
84
|
-
params.set(
|
|
84
|
+
params.set('script.presort', this.scriptData.presort.name);
|
|
85
85
|
if (this.scriptData.presort?.parameter)
|
|
86
|
-
params.set(
|
|
86
|
+
params.set('script.presort.param', this.scriptData.presort.parameter);
|
|
87
87
|
if (this.scriptData.prerequest)
|
|
88
|
-
params.set(
|
|
88
|
+
params.set('script.prerequest', this.scriptData.prerequest.name);
|
|
89
89
|
if (this.scriptData.prerequest?.parameter)
|
|
90
|
-
params.set(
|
|
91
|
-
|
|
92
|
-
for (
|
|
93
|
-
params.set(`_offset.${portal.toString()}`, (this.portals[portal]?.limit
|
|
94
|
-
params.set(`_offset.${portal.toString()}`, (this.portals[portal]?.offset
|
|
90
|
+
params.set('script.prerequest.param', this.scriptData.prerequest.parameter);
|
|
91
|
+
const portals = Object.keys(this.portals);
|
|
92
|
+
for (const portal of portals) {
|
|
93
|
+
params.set(`_offset.${portal.toString()}`, (this.portals[portal]?.limit ?? '').toString());
|
|
94
|
+
params.set(`_offset.${portal.toString()}`, (this.portals[portal]?.offset ?? '').toString());
|
|
95
95
|
}
|
|
96
96
|
params.set('portal', JSON.stringify(portals));
|
|
97
97
|
return params;
|
|
98
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Configures any FileMaker scripts to be run as a part of the request
|
|
101
|
+
*
|
|
102
|
+
* @param {ScriptRequestData} scripts - The script request data to set.
|
|
103
|
+
* @return {this} - The current instance of the class.
|
|
104
|
+
*/
|
|
99
105
|
scripts(scripts) {
|
|
100
106
|
this.scriptData = scripts;
|
|
101
107
|
return this;
|
|
102
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Sorts the data based on the given field name and sort order.
|
|
111
|
+
*
|
|
112
|
+
* @param {string} fieldName - The name of the field by which the data should be sorted.
|
|
113
|
+
* @param {SortOrder} sortOrder - The sort order to be applied (either "asc" for ascending or "desc" for descending).
|
|
114
|
+
*
|
|
115
|
+
* @return {this} - Returns the current instance of the object.
|
|
116
|
+
*/
|
|
103
117
|
sort(fieldName, sortOrder) {
|
|
104
118
|
this.sortData.push({ fieldName, sortOrder });
|
|
105
119
|
return this;
|
|
106
120
|
}
|
|
107
121
|
parseFindRequest(query) {
|
|
108
|
-
|
|
109
|
-
for (
|
|
122
|
+
const out = {};
|
|
123
|
+
for (const key of Object.keys(query)) {
|
|
110
124
|
out[key] = query[key][FindRequestSymbol].map(item => {
|
|
111
|
-
if (typeof item ===
|
|
125
|
+
if (typeof item === 'string')
|
|
112
126
|
return item;
|
|
113
127
|
// Re-write date into correct format
|
|
114
128
|
return item
|
|
115
129
|
.moment
|
|
116
130
|
.clone()
|
|
117
131
|
.utcOffset(this.layout.database.host.timezoneOffsetFunc(item.moment))
|
|
118
|
-
.format(item.type ===
|
|
119
|
-
this.layout.database.host.dateFormat
|
|
120
|
-
item.type ==
|
|
121
|
-
this.layout.database.host.timeFormat
|
|
122
|
-
this.layout.database.host.timeStampFormat);
|
|
123
|
-
}).join(
|
|
132
|
+
.format(item.type === 'date'
|
|
133
|
+
? this.layout.database.host.dateFormat
|
|
134
|
+
: item.type == 'time'
|
|
135
|
+
? this.layout.database.host.timeFormat
|
|
136
|
+
: this.layout.database.host.timeStampFormat);
|
|
137
|
+
}).join('');
|
|
124
138
|
}
|
|
125
139
|
return out;
|
|
126
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Adds a new request/query to the list of queries.
|
|
143
|
+
*
|
|
144
|
+
* @param {FindRequest} query - The find request to be added.
|
|
145
|
+
* @param {boolean} [omit=false] - Flag to indicate if the find request should be omitted.
|
|
146
|
+
* @return {Object} - The current object instance.
|
|
147
|
+
*/
|
|
127
148
|
addRequest(query, omit = false) {
|
|
128
149
|
this.queries.push({ req: this.parseFindRequest(query), omit });
|
|
129
150
|
return this;
|
|
130
151
|
}
|
|
131
|
-
|
|
132
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Perform a fetch operation.
|
|
154
|
+
*
|
|
155
|
+
* @returns {Promise} A promise that resolves with the result of the fetch operation.
|
|
156
|
+
*/
|
|
157
|
+
async fetch() {
|
|
158
|
+
return await this.performFind(this.offset, this.limit);
|
|
133
159
|
}
|
|
134
160
|
async performFind(offset, limit) {
|
|
135
|
-
|
|
161
|
+
const trace = new Error();
|
|
136
162
|
await this.layout.getLayoutMeta();
|
|
137
|
-
const
|
|
138
|
-
let endpoint = this.layout.endpoint + (
|
|
139
|
-
if (!
|
|
140
|
-
endpoint +=
|
|
163
|
+
const isFind = this.isFindRequest;
|
|
164
|
+
let endpoint = this.layout.endpoint + (isFind ? '/_find' : '/records');
|
|
165
|
+
if (!isFind)
|
|
166
|
+
endpoint += '?' + new URLSearchParams(this.generateParamsURL(offset, limit)).toString();
|
|
141
167
|
const reqData = {
|
|
142
168
|
// port: 443,
|
|
143
|
-
method:
|
|
144
|
-
body:
|
|
169
|
+
method: isFind ? 'POST' : 'GET',
|
|
170
|
+
body: isFind ? JSON.stringify(this.generateParamsBody(offset, limit)) : undefined
|
|
145
171
|
};
|
|
146
172
|
try {
|
|
147
|
-
|
|
148
|
-
if (res.messages[0].code ===
|
|
173
|
+
const res = await this.layout.database._apiRequestJSON(endpoint, reqData);
|
|
174
|
+
if (res.messages[0].code === '0' && res.response) {
|
|
149
175
|
// console.log("RESOLVING")
|
|
150
176
|
if (!this.layout.metadata)
|
|
151
177
|
await this.layout.getLayoutMeta();
|
|
@@ -169,28 +195,28 @@ export class RecordGetOperation {
|
|
|
169
195
|
}
|
|
170
196
|
[Symbol.asyncIterator]() {
|
|
171
197
|
let nextOffset = this.offset;
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
let
|
|
198
|
+
const startOffset = JSON.parse(JSON.stringify(this.offset));
|
|
199
|
+
const limit = this.limit;
|
|
200
|
+
let exitAfterLastRecord = false;
|
|
175
201
|
let records = [];
|
|
176
202
|
const fetch = async () => {
|
|
177
|
-
const
|
|
178
|
-
if (
|
|
179
|
-
|
|
203
|
+
const theoreticalLimit = (limit - nextOffset) + startOffset;
|
|
204
|
+
if (theoreticalLimit === 0) {
|
|
205
|
+
exitAfterLastRecord = true;
|
|
180
206
|
records = [];
|
|
181
207
|
return;
|
|
182
208
|
}
|
|
183
|
-
records = await this.performFind(nextOffset,
|
|
209
|
+
records = await this.performFind(nextOffset, theoreticalLimit < 100 ? theoreticalLimit : 100);
|
|
184
210
|
nextOffset += 100;
|
|
185
211
|
if (records.length < 100)
|
|
186
|
-
|
|
212
|
+
exitAfterLastRecord = true;
|
|
187
213
|
};
|
|
188
214
|
return {
|
|
189
215
|
next: async () => {
|
|
190
|
-
if (records.length === 0 && !
|
|
216
|
+
if (records.length === 0 && !exitAfterLastRecord) {
|
|
191
217
|
await fetch();
|
|
192
218
|
}
|
|
193
|
-
if (records.length === 0 &&
|
|
219
|
+
if (records.length === 0 && exitAfterLastRecord) {
|
|
194
220
|
return { done: true, value: undefined };
|
|
195
221
|
}
|
|
196
222
|
else {
|