@jd-data-limited/easy-fm 4.0.14 → 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.
Files changed (65) hide show
  1. package/package.json +12 -6
  2. package/src/FMError.d.ts +2 -2
  3. package/src/FMError.js +507 -508
  4. package/src/FMError.ts +510 -511
  5. package/src/bin/cli.js +7 -5
  6. package/src/bin/generateTypes.js +215 -121
  7. package/src/connection/FMHost.d.ts +28 -6
  8. package/src/connection/FMHost.js +52 -25
  9. package/src/connection/FMHost.ts +75 -43
  10. package/src/connection/HostBase.d.ts +7 -3
  11. package/src/connection/HostBase.ts +8 -4
  12. package/src/connection/database.d.ts +50 -17
  13. package/src/connection/database.js +94 -66
  14. package/src/connection/database.ts +125 -105
  15. package/src/connection/databaseBase.d.ts +11 -6
  16. package/src/connection/databaseBase.ts +9 -8
  17. package/src/connection/generateAuthorizationHeaders.d.ts +1 -1
  18. package/src/connection/generateAuthorizationHeaders.js +10 -10
  19. package/src/connection/generateAuthorizationHeaders.ts +21 -21
  20. package/src/databaseStructure.d.ts +2 -4
  21. package/src/databaseStructure.ts +3 -5
  22. package/src/index.d.ts +17 -17
  23. package/src/index.js +14 -14
  24. package/src/index.ts +28 -25
  25. package/src/layouts/layout.d.ts +17 -6
  26. package/src/layouts/layout.js +19 -8
  27. package/src/layouts/layout.ts +33 -23
  28. package/src/layouts/layoutBase.d.ts +5 -5
  29. package/src/layouts/layoutBase.ts +6 -6
  30. package/src/layouts/layoutInterface.d.ts +3 -5
  31. package/src/layouts/layoutInterface.ts +4 -6
  32. package/src/layouts/layoutRecordManager.d.ts +29 -6
  33. package/src/layouts/layoutRecordManager.js +32 -9
  34. package/src/layouts/layoutRecordManager.ts +42 -19
  35. package/src/layouts/recordFieldsMap.d.ts +2 -4
  36. package/src/layouts/recordFieldsMap.ts +2 -4
  37. package/src/models/apiResults.d.ts +7 -13
  38. package/src/models/apiResults.ts +58 -58
  39. package/src/records/field.d.ts +42 -12
  40. package/src/records/field.js +69 -59
  41. package/src/records/field.ts +102 -81
  42. package/src/records/getOperations/recordGetOperation.d.ts +44 -24
  43. package/src/records/getOperations/recordGetOperation.js +89 -58
  44. package/src/records/getOperations/recordGetOperation.ts +137 -108
  45. package/src/records/layoutRecord.d.ts +28 -14
  46. package/src/records/layoutRecord.js +75 -65
  47. package/src/records/layoutRecord.ts +126 -123
  48. package/src/records/layoutRecordBase.d.ts +2 -2
  49. package/src/records/layoutRecordBase.ts +3 -3
  50. package/src/records/portal.d.ts +19 -5
  51. package/src/records/portal.js +19 -5
  52. package/src/records/portal.ts +28 -16
  53. package/src/records/portalBase.d.ts +5 -5
  54. package/src/records/portalBase.ts +6 -6
  55. package/src/records/portalRecord.d.ts +16 -8
  56. package/src/records/portalRecord.js +16 -6
  57. package/src/records/portalRecord.ts +29 -19
  58. package/src/records/recordBase.d.ts +17 -7
  59. package/src/records/recordBase.js +32 -22
  60. package/src/records/recordBase.ts +50 -43
  61. package/src/types.d.ts +21 -24
  62. package/src/types.ts +55 -59
  63. package/src/utils/query.d.ts +12 -5
  64. package/src/utils/query.js +28 -9
  65. package/src/utils/query.ts +40 -15
@@ -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 "http";
6
- import {ContainerBufferResult, DownloadModes, FieldMetaData, RecordTypes} from "../types.js";
7
- import {ApiFieldDisplayTypes, ApiFieldMetadata, ApiFieldResultTypes, ApiFieldTypes} from "../models/apiResults.js";
8
- import {LayoutBase} from "../layouts/layoutBase.js";
9
- import {Moment} from "moment";
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 type Parentable = {layout: LayoutBase, type: RecordTypes, endpoint: string}
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
- set(content: T) {
29
- if (this.metadata.result === "container") throw "Cannot set container value using set(). Use upload() instead."
30
- // @ts-ignore
31
- if (!content) this._value = ""
32
- // @ts-ignore
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
- // @ts-ignore
59
- return this.parent.layout.metadata.portalMetaData[this.parent.portal.name || "portal not attached"].find(i => i.name === this.id) as FieldMetaData || {
60
- name: this.id.toString(),
61
- type: 'normal',
62
- displayType: 'editText',
63
- result: 'text',
64
- global: false,
65
- autoEnter: true,
66
- fourDigitYear: false,
67
- maxRepeat: 1,
68
- maxCharacters: 0,
69
- notEmpty: false,
70
- numeric: false,
71
- timeOfDay: false,
72
- repetitionStart: 1,
73
- repetitionEnd: 1
74
- } as FieldMetaData
75
- }
76
- else {
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 === "string") {
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 "Field value is not a date"
122
+ throw new Error('Field value is not a string')
117
123
  }
118
124
 
119
- get number(): number {
120
- if (typeof this._value === "number") {
121
- return this._value
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
- throw "Field value is not a number"
124
- }
125
-
126
- async upload(buffer: Buffer, filename: string, mime: string): Promise<void> {
127
- let trace = new Error()
128
- if (this.metadata.result !== "container") throw "Cannot upload a file to the field; " + this.id + " (not a container field)"
129
- let form = new FormData()
130
- form.append("upload", new File([buffer], filename, {type: mime}))
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
- download(mode: DownloadModes.Stream): Promise<http.IncomingMessage>
141
- download(mode: DownloadModes.Buffer): Promise<ContainerBufferResult>
142
- async download(mode: DownloadModes = DownloadModes.Stream): Promise<http.IncomingMessage | ContainerBufferResult> {
143
- if (this.metadata.result !== ApiFieldResultTypes.CONTAINER) throw new Error("Cannot perform download() on a non-container field")
144
-
145
- let stream = await this.parent.layout.database.streamURL(this.string)
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
- let body: Uint8Array[] = []
151
- return new Promise((resolve, reject) => {
152
- stream.on("data", chunk => {
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("error", (e) => {
176
+ stream.on('error', (e) => {
156
177
  reject(e)
157
178
  })
158
- stream.on("end", () => {
179
+ stream.on('end', () => {
159
180
  resolve({
160
181
  buffer: Buffer.concat(body),
161
- mime: stream.headers["content-type"],
182
+ mime: stream.headers['content-type'],
162
183
  request: stream
163
- } as ContainerBufferResult)
184
+ } satisfies ContainerBufferResult)
164
185
  })
165
186
  })
166
187
  }
167
- }
188
+ }
@@ -1,54 +1,74 @@
1
- import { LayoutInterface } from "../../layouts/layoutInterface.js";
2
- import { PickPortals, ScriptRequestData } from "../../types.js";
3
- import { LayoutBase } from "../../layouts/layoutBase.js";
4
- import { LayoutRecord } from "../layoutRecord.js";
5
- import { Query } from "../../utils/query.js";
6
- export type SortOrder = "ascend" | "descend";
7
- export type FindRequestRaw = {
8
- [key: string]: string;
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["portals"]]: {
13
+ [key in keyof T['portals']]: {
18
14
  limit: number;
19
15
  offset: number;
20
16
  };
21
17
  };
22
- export type GetOperationOptions<T extends LayoutInterface> = {
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 "../layoutRecord.js";
5
- import { FMError } from "../../FMError.js";
6
- import { FindRequestSymbol } from "../../utils/query.js";
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 || 1; // Offset refers to the starting record. offset 1 is the same as no offset.
20
- this.limit = options.limit || 100;
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
- let test = this.queries.map(query => {
27
- let out = {};
28
- for (let key of Object.keys(query.req)) {
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 = "true";
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["script"] = this.scriptData.after.name;
50
+ params.script = this.scriptData.after.name;
51
51
  if (this.scriptData.after?.parameter)
52
- params["script.param"] = this.scriptData.after.parameter;
52
+ params['script.param'] = this.scriptData.after.parameter;
53
53
  if (this.scriptData.presort)
54
- params["script.presort"] = this.scriptData.presort.name;
54
+ params['script.presort'] = this.scriptData.presort.name;
55
55
  if (this.scriptData.presort?.parameter)
56
- params["script.presort.param"] = this.scriptData.presort.parameter;
56
+ params['script.presort.param'] = this.scriptData.presort.parameter;
57
57
  if (this.scriptData.prerequest)
58
- params["script.prerequest"] = this.scriptData.prerequest.name;
58
+ params['script.prerequest'] = this.scriptData.prerequest.name;
59
59
  if (this.scriptData.prerequest?.parameter)
60
- params["script.prerequest.param"] = this.scriptData.prerequest.parameter;
60
+ params['script.prerequest.param'] = this.scriptData.prerequest.parameter;
61
61
  if (this.queries.length !== 0)
62
- params["query"] = this.formatQueries();
63
- let portals = Object.keys(this.portals);
64
- params["portal"] = portals;
65
- for (let portal of portals) {
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,75 +72,106 @@ export class RecordGetOperation {
72
72
  const params = new URLSearchParams({
73
73
  _limit: limit.toString(),
74
74
  _offset: offset.toString(),
75
- dateformats: "2" // Ensure dates are received in ISO8601 format
75
+ dateformats: '2' // Ensure dates are received in ISO8601 format
76
76
  });
77
77
  if (this.sortData.length !== 0)
78
- params.set("_sort", JSON.stringify(this.sortData));
78
+ params.set('_sort', JSON.stringify(this.sortData));
79
79
  if (this.scriptData.after)
80
- params.set("script", this.scriptData.after.name);
80
+ params.set('script', this.scriptData.after.name);
81
81
  if (this.scriptData.after?.parameter)
82
- params.set("script.param", this.scriptData.after.parameter);
82
+ params.set('script.param', this.scriptData.after.parameter);
83
83
  if (this.scriptData.presort)
84
- params.set("script.presort", this.scriptData.presort.name);
84
+ params.set('script.presort', this.scriptData.presort.name);
85
85
  if (this.scriptData.presort?.parameter)
86
- params.set("script.presort.param", this.scriptData.presort.parameter);
86
+ params.set('script.presort.param', this.scriptData.presort.parameter);
87
87
  if (this.scriptData.prerequest)
88
- params.set("script.prerequest", this.scriptData.prerequest.name);
88
+ params.set('script.prerequest', this.scriptData.prerequest.name);
89
89
  if (this.scriptData.prerequest?.parameter)
90
- params.set("script.prerequest.param", this.scriptData.prerequest.parameter);
91
- let portals = Object.keys(this.portals);
92
- for (let 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());
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
- let out = {};
109
- for (let key of Object.keys(query)) {
122
+ const out = {};
123
+ for (const key of Object.keys(query)) {
110
124
  out[key] = query[key][FindRequestSymbol].map(item => {
111
- if (typeof item === "string")
125
+ if (typeof item === 'string')
112
126
  return item;
113
127
  // Re-write date into correct format
114
128
  return item
129
+ .moment
115
130
  .clone()
116
- .utcOffset(this.layout.database.host.timezoneOffset)
117
- .format("MM/DD/YYYY HH:mm:ss");
118
- }).join("");
131
+ .utcOffset(this.layout.database.host.timezoneOffsetFunc(item.moment))
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('');
119
138
  }
120
139
  return out;
121
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
+ */
122
148
  addRequest(query, omit = false) {
123
149
  this.queries.push({ req: this.parseFindRequest(query), omit });
124
150
  return this;
125
151
  }
126
- fetch() {
127
- return this.performFind(this.offset, this.limit);
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);
128
159
  }
129
160
  async performFind(offset, limit) {
130
- let trace = new Error();
161
+ const trace = new Error();
131
162
  await this.layout.getLayoutMeta();
132
- const is_find = this.isFindRequest;
133
- let endpoint = this.layout.endpoint + (is_find ? "/_find" : "/records");
134
- if (!is_find)
135
- endpoint += "?" + new URLSearchParams(this.generateParamsURL(offset, limit)).toString();
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();
136
167
  const reqData = {
137
168
  // port: 443,
138
- method: is_find ? "POST" : "GET",
139
- body: is_find ? JSON.stringify(this.generateParamsBody(offset, limit)) : undefined,
169
+ method: isFind ? 'POST' : 'GET',
170
+ body: isFind ? JSON.stringify(this.generateParamsBody(offset, limit)) : undefined
140
171
  };
141
172
  try {
142
- let res = await this.layout.database.apiRequestJSON(endpoint, reqData);
143
- if (res.messages[0].code === "0" && res.response) {
173
+ const res = await this.layout.database._apiRequestJSON(endpoint, reqData);
174
+ if (res.messages[0].code === '0' && res.response) {
144
175
  // console.log("RESOLVING")
145
176
  if (!this.layout.metadata)
146
177
  await this.layout.getLayoutMeta();
@@ -164,28 +195,28 @@ export class RecordGetOperation {
164
195
  }
165
196
  [Symbol.asyncIterator]() {
166
197
  let nextOffset = this.offset;
167
- let startOffset = JSON.parse(JSON.stringify(this.offset));
168
- let limit = this.limit;
169
- let exit_after_last_record = false;
198
+ const startOffset = JSON.parse(JSON.stringify(this.offset));
199
+ const limit = this.limit;
200
+ let exitAfterLastRecord = false;
170
201
  let records = [];
171
202
  const fetch = async () => {
172
- const theoretical_limit = (limit - nextOffset) + startOffset;
173
- if (theoretical_limit === 0) {
174
- exit_after_last_record = true;
203
+ const theoreticalLimit = (limit - nextOffset) + startOffset;
204
+ if (theoreticalLimit === 0) {
205
+ exitAfterLastRecord = true;
175
206
  records = [];
176
207
  return;
177
208
  }
178
- records = await this.performFind(nextOffset, theoretical_limit < 100 ? theoretical_limit : 100);
209
+ records = await this.performFind(nextOffset, theoreticalLimit < 100 ? theoreticalLimit : 100);
179
210
  nextOffset += 100;
180
211
  if (records.length < 100)
181
- exit_after_last_record = true;
212
+ exitAfterLastRecord = true;
182
213
  };
183
214
  return {
184
215
  next: async () => {
185
- if (records.length === 0 && !exit_after_last_record) {
216
+ if (records.length === 0 && !exitAfterLastRecord) {
186
217
  await fetch();
187
218
  }
188
- if (records.length === 0 && exit_after_last_record) {
219
+ if (records.length === 0 && exitAfterLastRecord) {
189
220
  return { done: true, value: undefined };
190
221
  }
191
222
  else {