@jd-data-limited/easy-fm 3.2.8 → 4.0.1

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 (75) hide show
  1. package/README.md +36 -24
  2. package/package.json +12 -9
  3. package/src/FMError.js +2 -2
  4. package/src/FMError.ts +2 -2
  5. package/src/connection/FMHost.d.ts +2 -1
  6. package/src/connection/FMHost.js +1 -2
  7. package/src/connection/FMHost.ts +4 -4
  8. package/src/connection/HostBase.d.ts +1 -1
  9. package/src/connection/HostBase.js +1 -1
  10. package/src/connection/HostBase.ts +2 -4
  11. package/src/connection/database.d.ts +10 -10
  12. package/src/connection/database.js +6 -17
  13. package/src/connection/database.ts +17 -27
  14. package/src/connection/databaseBase.d.ts +4 -4
  15. package/src/connection/databaseBase.js +1 -1
  16. package/src/connection/databaseBase.ts +4 -6
  17. package/src/databaseStructure.d.ts +6 -0
  18. package/src/databaseStructure.js +4 -0
  19. package/src/databaseStructure.ts +12 -0
  20. package/src/index.d.ts +3 -6
  21. package/src/index.js +3 -5
  22. package/src/index.ts +4 -9
  23. package/src/layouts/layout.d.ts +3 -17
  24. package/src/layouts/layout.js +2 -20
  25. package/src/layouts/layout.ts +5 -27
  26. package/src/layouts/layoutBase.d.ts +4 -4
  27. package/src/layouts/layoutBase.js +1 -1
  28. package/src/layouts/layoutBase.ts +5 -6
  29. package/src/layouts/layoutInterface.d.ts +1 -1
  30. package/src/layouts/layoutInterface.js +1 -1
  31. package/src/layouts/layoutInterface.ts +2 -2
  32. package/src/layouts/layoutRecordManager.d.ts +5 -6
  33. package/src/layouts/layoutRecordManager.js +5 -9
  34. package/src/layouts/layoutRecordManager.ts +12 -16
  35. package/src/layouts/recordFieldsMap.d.ts +2 -2
  36. package/src/layouts/recordFieldsMap.js +1 -1
  37. package/src/layouts/recordFieldsMap.ts +3 -3
  38. package/src/models/apiResults.d.ts +3 -3
  39. package/src/models/apiResults.js +1 -1
  40. package/src/models/apiResults.ts +2 -4
  41. package/src/records/field.d.ts +3 -23
  42. package/src/records/field.js +3 -152
  43. package/src/records/field.ts +4 -169
  44. package/src/records/fieldBase.d.ts +30 -0
  45. package/src/records/fieldBase.js +154 -0
  46. package/src/records/fieldBase.ts +174 -0
  47. package/src/records/getOperations/recordGetOperation.d.ts +47 -11
  48. package/src/records/getOperations/recordGetOperation.js +142 -31
  49. package/src/records/getOperations/recordGetOperation.ts +172 -30
  50. package/src/records/layoutRecord.d.ts +14 -11
  51. package/src/records/layoutRecord.js +7 -8
  52. package/src/records/layoutRecord.ts +32 -22
  53. package/src/records/portal.d.ts +6 -5
  54. package/src/records/portal.js +1 -1
  55. package/src/records/portal.ts +10 -8
  56. package/src/records/portalBase.d.ts +5 -4
  57. package/src/records/portalBase.js +1 -1
  58. package/src/records/portalBase.ts +6 -6
  59. package/src/records/portalRecord.d.ts +12 -8
  60. package/src/records/portalRecord.js +6 -8
  61. package/src/records/portalRecord.ts +17 -16
  62. package/src/records/recordBase.d.ts +11 -15
  63. package/src/records/recordBase.js +9 -13
  64. package/src/records/recordBase.ts +17 -25
  65. package/src/types.d.ts +18 -15
  66. package/src/types.js +7 -1
  67. package/src/types.ts +20 -16
  68. package/src/records/getOperations/find.d.ts +0 -15
  69. package/src/records/getOperations/find.js +0 -70
  70. package/src/records/getOperations/find.ts +0 -77
  71. package/src/records/getOperations/recordGetRange.d.ts +0 -13
  72. package/src/records/getOperations/recordGetRange.js +0 -77
  73. package/src/records/getOperations/recordGetRange.ts +0 -77
  74. package/src/records/portalRecordBase.d.ts +0 -4
  75. package/src/records/portalRecordBase.js +0 -6
@@ -1,46 +1,157 @@
1
1
  /*
2
- * Copyright (c) 2023. See LICENSE file for more information
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";
4
6
  export class RecordGetOperation {
5
7
  layout;
6
8
  limit = 100;
7
- scripts;
8
- sort;
9
- limitPortals = [];
10
- offset = 0;
11
- constructor(layout) {
9
+ scriptData = {};
10
+ sortData = [];
11
+ portals;
12
+ offset = 1;
13
+ queries = [];
14
+ constructor(layout, options) {
12
15
  this.layout = layout;
13
- this.scripts = {
14
- "script": null,
15
- "script.prerequeset": null,
16
- "script.presort": null // Runs before the sort
16
+ this.sortData = [];
17
+ this.portals = options.portals;
18
+ this.offset = options.offset || 1; // Offset refers to the starting record. offset 1 is the same as no offset.
19
+ this.limit = options.limit || 100;
20
+ }
21
+ get isFindRequest() {
22
+ return this.queries.length !== 0;
23
+ }
24
+ generateParamsBody(offset, limit) {
25
+ const params = {
26
+ limit: limit.toString(),
27
+ offset: offset.toString(),
17
28
  };
18
- this.sort = [];
19
- }
20
- /*
21
- addToPortalLimit() will adjust the results of the get request so that if a layout has multiple portals in it,
22
- only data from the specified ones will be read. This may help reduce load on your FileMaker API
23
- */
24
- addToPortalLimit(portal, offset = 0, limit = 100) {
25
- if (offset < 0)
26
- throw "Portal offset cannot be less than 0";
27
- this.limitPortals.push({ portalName: portal.name, offset, limit });
28
- return this;
29
+ if (this.sortData.length !== 0)
30
+ params.sort = JSON.stringify(this.sortData);
31
+ if (this.scriptData.after)
32
+ params["script"] = this.scriptData.after.name;
33
+ if (this.scriptData.after?.parameter)
34
+ params["script.param"] = this.scriptData.after.parameter;
35
+ if (this.scriptData.presort)
36
+ params["script.presort"] = this.scriptData.after.name;
37
+ if (this.scriptData.presort?.parameter)
38
+ params["script.presort.param"] = this.scriptData.after.parameter;
39
+ if (this.scriptData.prerequest)
40
+ params["script.prerequest"] = this.scriptData.after.name;
41
+ if (this.scriptData.prerequest?.parameter)
42
+ params["script.prerequest.param"] = this.scriptData.after.parameter;
43
+ if (this.queries.length !== 0)
44
+ params["query"] = this.queries;
45
+ let portals = Object.keys(this.portals);
46
+ params["portal"] = portals;
47
+ for (let portal of portals) {
48
+ params[`offset.${portal}`] = this.portals[portal].offset;
49
+ params[`limit.${portal}`] = this.portals[portal].limit;
50
+ }
51
+ return params;
29
52
  }
30
- setLimit(limit) {
31
- if (limit < 1)
32
- throw "Record limit too low";
33
- this.limit = limit;
53
+ generateParamsURL(offset, limit) {
54
+ const params = new URLSearchParams({
55
+ _limit: limit.toString(),
56
+ _offset: offset.toString(),
57
+ });
58
+ if (this.sortData.length !== 0)
59
+ params.set("_sort", JSON.stringify(this.sortData));
60
+ if (this.scriptData.after)
61
+ params.set("script", this.scriptData.after.name);
62
+ if (this.scriptData.after?.parameter)
63
+ params.set("script.param", this.scriptData.after.parameter);
64
+ if (this.scriptData.presort)
65
+ params.set("script.presort", this.scriptData.after.name);
66
+ if (this.scriptData.presort?.parameter)
67
+ params.set("script.presort.param", this.scriptData.after.parameter);
68
+ if (this.scriptData.prerequest)
69
+ params.set("script.prerequest", this.scriptData.after.name);
70
+ if (this.scriptData.prerequest?.parameter)
71
+ params.set("script.prerequest.param", this.scriptData.after.parameter);
72
+ let portals = Object.keys(this.portals);
73
+ for (let portal of portals) {
74
+ params.set(`_offset.${portal}`, this.portals[portal].limit.toString());
75
+ params.set(`_offset.${portal}`, this.portals[portal].offset.toString());
76
+ }
77
+ params.set('portal', JSON.stringify(portals));
78
+ return params;
79
+ }
80
+ scripts(scripts) {
81
+ this.scriptData = scripts;
34
82
  return this;
35
83
  }
36
- addSort(fieldName, sortOrder) {
37
- this.sort.push({ fieldName, sortOrder });
84
+ sort(fieldName, sortOrder) {
85
+ this.sortData.push({ fieldName, sortOrder });
38
86
  return this;
39
87
  }
40
- setOffset(offset) {
41
- if (offset < 0)
42
- throw "Record offset too low";
43
- this.offset = offset;
88
+ addRequest(query) {
89
+ this.queries.push(query);
44
90
  return this;
45
91
  }
92
+ fetch() {
93
+ return this.performFind(this.offset, this.limit);
94
+ }
95
+ async performFind(offset, limit) {
96
+ let trace = new Error();
97
+ await this.layout.getLayoutMeta();
98
+ const is_find = this.isFindRequest;
99
+ let endpoint = this.layout.endpoint + (is_find ? "/_find" : "/records");
100
+ if (!is_find)
101
+ endpoint += "?" + new URLSearchParams(this.generateParamsURL(offset, limit)).toString();
102
+ const reqData = {
103
+ // port: 443,
104
+ method: is_find ? "POST" : "GET",
105
+ body: is_find ? JSON.stringify(this.generateParamsBody(offset, limit)) : undefined,
106
+ };
107
+ let res = await this.layout.database.apiRequest(endpoint, reqData);
108
+ if (res.messages[0].code === "0") {
109
+ // console.log("RESOLVING")
110
+ if (!this.layout.metadata)
111
+ await this.layout.getLayoutMeta();
112
+ return res.response.data.map(item => {
113
+ return new LayoutRecord(this.layout, item.recordId, item.modId, item.fieldData, item.portalData);
114
+ });
115
+ }
116
+ else if (res.messages[0].code == "401") {
117
+ // No records found, so return empty set
118
+ return [];
119
+ }
120
+ else {
121
+ throw new FMError(res.messages[0].code, res.httpStatus, res, trace);
122
+ }
123
+ }
124
+ [Symbol.asyncIterator]() {
125
+ let nextOffset = this.offset;
126
+ let startOffset = JSON.parse(JSON.stringify(this.offset));
127
+ let limit = this.limit;
128
+ let exit_after_last_record = false;
129
+ let records = [];
130
+ const fetch = async () => {
131
+ const theoretical_limit = (limit - nextOffset) + startOffset;
132
+ if (theoretical_limit === 0) {
133
+ exit_after_last_record = true;
134
+ records = [];
135
+ return;
136
+ }
137
+ records = await this.performFind(nextOffset, theoretical_limit < 100 ? theoretical_limit : 100);
138
+ nextOffset += 100;
139
+ if (records.length < 100)
140
+ exit_after_last_record = true;
141
+ };
142
+ return {
143
+ next: async () => {
144
+ if (records.length === 0 && !exit_after_last_record) {
145
+ await fetch();
146
+ }
147
+ if (records.length === 0 && exit_after_last_record) {
148
+ return { done: true, value: undefined };
149
+ }
150
+ else {
151
+ const record = records.shift();
152
+ return { done: false, value: record };
153
+ }
154
+ }
155
+ };
156
+ }
46
157
  }
@@ -1,54 +1,196 @@
1
1
  /*
2
- * Copyright (c) 2023. See LICENSE file for more information
2
+ * Copyright (c) 2023-2024. See LICENSE file for more information
3
3
  */
4
4
 
5
5
  import {LayoutInterface} from "../../layouts/layoutInterface.js";
6
- import {Portal} from "../portal.js";
7
- import {limitPortalsInterface} from "../../types.js";
6
+ import {ScriptRequestData} from "../../types.js";
8
7
  import {LayoutBase} from "../../layouts/layoutBase.js"
8
+ import {LayoutRecord} from "../layoutRecord.js";
9
+ import {ApiRecordResponseObj} from "../../models/apiResults.js";
10
+ import {FMError} from "../../FMError.js";
9
11
 
10
- export class RecordGetOperation<T extends LayoutInterface> {
12
+ export type SortOrder = "ascend" | "descend"
13
+ export type FindRequest = {
14
+ [key: string]: string,
15
+ omit?: "true" | "false"
16
+ }
17
+ export type PortalRequest = {
18
+ name: string,
19
+ }
20
+
21
+ type PortalData<T extends LayoutInterface> = {
22
+ [key in keyof T["portals"]]: {
23
+ limit: number,
24
+ offset: number
25
+ }
26
+ }
27
+ export type GetOperationOptions<T extends LayoutInterface> = {
28
+ portals: Partial<PortalData<T>>,
29
+ limit?: number,
30
+ offset?: number
31
+ }
32
+
33
+ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOperationOptions<T>> {
11
34
  protected layout: LayoutBase
12
35
  protected limit: number = 100
13
- protected scripts: object
14
- protected sort: object[]
15
- protected limitPortals: limitPortalsInterface[] = []
16
- protected offset: number = 0
36
+ protected scriptData: ScriptRequestData = {}
37
+ protected sortData: { fieldName: string, sortOrder: SortOrder }[] = []
38
+ protected portals: Partial<PortalData<T>>
39
+ protected offset: number = 1
40
+ protected queries: FindRequest[] = []
17
41
 
18
- constructor(layout: LayoutBase) {
42
+ constructor(layout: LayoutBase, options: OPTIONS) {
19
43
  this.layout = layout
20
- this.scripts = {
21
- "script": null, // Runs after everything
22
- "script.prerequeset": null, // Runs before the request
23
- "script.presort": null // Runs before the sort
44
+ this.sortData = []
45
+ this.portals = options.portals
46
+ this.offset = options.offset || 1 // Offset refers to the starting record. offset 1 is the same as no offset.
47
+ this.limit = options.limit || 100
48
+ }
49
+
50
+ get isFindRequest() {
51
+ return this.queries.length !== 0
52
+ }
53
+
54
+ protected generateParamsBody(offset: number, limit: number) {
55
+ const params: {[key: string]: any} = {
56
+ limit: limit.toString(),
57
+ offset: offset.toString(),
24
58
  }
25
- this.sort = []
59
+ if (this.sortData.length !== 0) params.sort = JSON.stringify(this.sortData)
60
+
61
+
62
+ if (this.scriptData.after) params["script"] = this.scriptData.after.name
63
+ if (this.scriptData.after?.parameter) params["script.param"] = this.scriptData.after.parameter
64
+
65
+ if (this.scriptData.presort) params["script.presort"] = this.scriptData.after.name
66
+ if (this.scriptData.presort?.parameter) params["script.presort.param"] = this.scriptData.after.parameter
67
+
68
+ if (this.scriptData.prerequest) params["script.prerequest"] = this.scriptData.after.name
69
+ if (this.scriptData.prerequest?.parameter) params["script.prerequest.param"] = this.scriptData.after.parameter
70
+
71
+ if (this.queries.length !== 0) params["query"] = this.queries
72
+
73
+ let portals = Object.keys(this.portals)
74
+ params["portal"] = portals
75
+ for (let portal of portals) {
76
+ params[`offset.${portal}`] = this.portals[portal].offset
77
+ params[`limit.${portal}`] = this.portals[portal].limit
78
+ }
79
+
80
+ return params
26
81
  }
82
+ protected generateParamsURL(offset: number, limit: number) {
83
+ const params = new URLSearchParams({
84
+ _limit: limit.toString(),
85
+ _offset: offset.toString(),
86
+ })
87
+ if (this.sortData.length !== 0) params.set("_sort", JSON.stringify(this.sortData))
27
88
 
28
- /*
29
- addToPortalLimit() will adjust the results of the get request so that if a layout has multiple portals in it,
30
- only data from the specified ones will be read. This may help reduce load on your FileMaker API
31
- */
32
- addToPortalLimit(portal: Portal<any>, offset = 0, limit = 100) {
33
- if (offset < 0) throw "Portal offset cannot be less than 0"
34
- this.limitPortals.push({portalName: portal.name, offset, limit})
35
- return this
89
+ if (this.scriptData.after) params.set("script", this.scriptData.after.name)
90
+ if (this.scriptData.after?.parameter) params.set("script.param", this.scriptData.after.parameter)
91
+
92
+ if (this.scriptData.presort) params.set("script.presort", this.scriptData.after.name)
93
+ if (this.scriptData.presort?.parameter) params.set("script.presort.param", this.scriptData.after.parameter)
94
+
95
+ if (this.scriptData.prerequest) params.set("script.prerequest", this.scriptData.after.name)
96
+ if (this.scriptData.prerequest?.parameter) params.set("script.prerequest.param", this.scriptData.after.parameter)
97
+
98
+ let portals = Object.keys(this.portals)
99
+ for (let portal of portals) {
100
+ params.set(`_offset.${portal}`, this.portals[portal].limit.toString())
101
+ params.set(`_offset.${portal}`, this.portals[portal].offset.toString())
102
+ }
103
+ params.set('portal', JSON.stringify(portals))
104
+
105
+ return params
36
106
  }
37
107
 
38
- setLimit(limit: number) {
39
- if (limit < 1) throw "Record limit too low"
40
- this.limit = limit
108
+ scripts(scripts: ScriptRequestData) {
109
+ this.scriptData = scripts;
41
110
  return this
42
111
  }
43
112
 
44
- addSort(fieldName, sortOrder) {
45
- this.sort.push({fieldName, sortOrder})
113
+ sort(fieldName: string, sortOrder: SortOrder) {
114
+ this.sortData.push({fieldName, sortOrder})
46
115
  return this
47
116
  }
48
117
 
49
- setOffset(offset: number) {
50
- if (offset < 0) throw "Record offset too low"
51
- this.offset = offset
118
+ addRequest(query: FindRequest) {
119
+ this.queries.push(query)
52
120
  return this
53
121
  }
122
+
123
+ fetch() {
124
+ return this.performFind(this.offset, this.limit)
125
+ }
126
+
127
+ private async performFind(offset: number, limit: number): Promise<LayoutRecord<T, keyof OPTIONS["portals"]>[]> {
128
+ let trace = new Error()
129
+ await this.layout.getLayoutMeta()
130
+
131
+ const is_find = this.isFindRequest
132
+ let endpoint = this.layout.endpoint + (is_find ? "/_find" : "/records")
133
+ if (!is_find) endpoint += "?" + new URLSearchParams(this.generateParamsURL(offset, limit)).toString()
134
+ const reqData = {
135
+ // port: 443,
136
+ method: is_find ? "POST" : "GET",
137
+ body: is_find ? JSON.stringify(this.generateParamsBody(offset, limit)) : undefined,
138
+ }
139
+
140
+ let res = await this.layout.database.apiRequest<ApiRecordResponseObj>(
141
+ endpoint,
142
+ reqData
143
+ )
144
+ if (res.messages[0].code === "0") {
145
+ // console.log("RESOLVING")
146
+ if (!this.layout.metadata) await this.layout.getLayoutMeta()
147
+ return res.response.data.map(item => {
148
+ return new LayoutRecord(this.layout, item.recordId, item.modId, item.fieldData, item.portalData)
149
+ })
150
+ }
151
+ else if (res.messages[0].code == "401") {
152
+ // No records found, so return empty set
153
+ return []
154
+ }
155
+ else {
156
+ throw new FMError(res.messages[0].code, res.httpStatus, res, trace)
157
+ }
158
+ }
159
+
160
+ [Symbol.asyncIterator]() {
161
+ let nextOffset = this.offset
162
+ let startOffset: number = JSON.parse(JSON.stringify(this.offset))
163
+ let limit = this.limit
164
+
165
+ let exit_after_last_record = false
166
+ let records: LayoutRecord<T, keyof OPTIONS["portals"]>[] = []
167
+
168
+ const fetch = async () => {
169
+ const theoretical_limit = (limit - nextOffset) + startOffset
170
+ if (theoretical_limit === 0) {
171
+ exit_after_last_record = true
172
+ records = []
173
+ return
174
+ }
175
+ records = await this.performFind(nextOffset, theoretical_limit < 100 ? theoretical_limit : 100);
176
+ nextOffset += 100;
177
+ if (records.length < 100) exit_after_last_record = true
178
+ }
179
+
180
+ return {
181
+ next: async () => {
182
+ if (records.length === 0 && !exit_after_last_record) {
183
+ await fetch();
184
+ }
185
+
186
+ if (records.length === 0 && exit_after_last_record) {
187
+ return {done: true, value: undefined};
188
+ }
189
+ else {
190
+ const record = records.shift()
191
+ return {done: false, value: record};
192
+ }
193
+ }
194
+ };
195
+ }
54
196
  }
@@ -1,18 +1,21 @@
1
- import { extraBodyOptions, recordObject } from "../types.js";
1
+ import { extraBodyOptions } from "../types.js";
2
2
  import { RecordBase } from "./recordBase.js";
3
+ import { PortalRecord } from "./portalRecord.js";
3
4
  import { Portal } from "./portal.js";
4
- import { PortalInterface } from "../layouts/layoutInterface.js";
5
- import { RecordFieldsMap } from "../layouts/recordFieldsMap";
6
- import { LayoutRecordBase } from "./layoutRecordBase";
7
- export declare class LayoutRecord<T extends RecordFieldsMap, P extends PortalInterface> extends RecordBase<T> implements LayoutRecordBase {
8
- portals: P;
9
- constructor(layout: any, recordId: any, modId?: any, fieldData?: {}, portalData?: any);
5
+ import { LayoutInterface } from "../layouts/layoutInterface.js";
6
+ import { LayoutRecordBase } from "./layoutRecordBase.js";
7
+ import { ApiPortalData } from "../models/apiResults.js";
8
+ import { LayoutBase } from "../layouts/layoutBase.js";
9
+ import { FieldBase, FieldValue } from "./fieldBase.js";
10
+ export declare class LayoutRecord<LAYOUT extends LayoutInterface, PORTALS_TO_INCLUDE = string> extends RecordBase<LAYOUT["fields"]> implements LayoutRecordBase {
11
+ portals: Pick<LAYOUT["portals"], PORTALS_TO_INCLUDE>;
12
+ private readonly portalsToInclude;
13
+ constructor(layout: LayoutBase, recordId: number | string, modId?: string | number, fieldData?: Record<string, string | number>, portalData?: ApiPortalData | null, portalsToInclude?: PORTALS_TO_INCLUDE[]);
10
14
  get portalsArray(): Portal<any>[];
11
15
  commit(extraBody?: extraBodyOptions): Promise<this>;
12
- protected processPortalData(portalData: any): void;
16
+ protected processPortalData(portalData: ApiPortalData): void;
13
17
  get(): Promise<this>;
14
- getPortal(portal: any): Portal<any>;
15
- duplicate(): Promise<LayoutRecord<T, P>>;
18
+ duplicate(): Promise<LayoutRecord<LAYOUT>>;
16
19
  delete(): Promise<void>;
17
- toObject(filter?: (a: any) => any, portalFilter?: (a: any) => any, portalRowFilter?: (a: any) => any, portalFieldFilter?: (a: any) => any): recordObject;
20
+ toObject(filter?: (a: FieldBase<FieldValue>) => any, portalFilter?: (a: Portal<any>) => any, portalRowFilter?: (a: PortalRecord<never>) => any, portalFieldFilter?: (a: FieldBase<FieldValue>) => any): Partial<Omit<import("../models/apiResults.js").ApiRowDataDef, "portalDataInfo">>;
18
21
  }
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2023. See LICENSE file for more information
2
+ * Copyright (c) 2023-2024. See LICENSE file for more information
3
3
  */
4
4
  import { RecordBase } from "./recordBase.js";
5
5
  import { PortalRecord } from "./portalRecord.js";
@@ -8,9 +8,11 @@ import { FMError } from "../FMError.js";
8
8
  export class LayoutRecord extends RecordBase {
9
9
  // @ts-ignore
10
10
  portals = {};
11
- constructor(layout, recordId, modId = recordId, fieldData = {}, portalData = null) {
12
- super(layout, recordId, modId);
11
+ portalsToInclude;
12
+ constructor(layout, recordId, modId = recordId, fieldData = {}, portalData = null, portalsToInclude = []) {
13
+ super(layout, parseInt(recordId), parseInt(modId));
13
14
  this.processFieldData(fieldData);
15
+ this.portalsToInclude = portalsToInclude;
14
16
  if (portalData) {
15
17
  this.processPortalData(portalData);
16
18
  }
@@ -81,7 +83,7 @@ export class LayoutRecord extends RecordBase {
81
83
  let fieldData = item;
82
84
  delete fieldData.recordId;
83
85
  delete fieldData.modId;
84
- return new PortalRecord(this, _portal, item.recordId, item.modId, fieldData);
86
+ return new PortalRecord(this, _portal, parseInt(item.recordId), parseInt(item.modId), fieldData);
85
87
  });
86
88
  // @ts-ignore
87
89
  this.portals[portalName] = _portal;
@@ -108,9 +110,6 @@ export class LayoutRecord extends RecordBase {
108
110
  return this;
109
111
  }
110
112
  }
111
- getPortal(portal) {
112
- return this.portalsArray.find(p => p.name === portal);
113
- }
114
113
  async duplicate() {
115
114
  let trace = new Error();
116
115
  let res = await this.layout.database.apiRequest(this.endpoint, {
@@ -148,7 +147,7 @@ export class LayoutRecord extends RecordBase {
148
147
  }
149
148
  }
150
149
  toObject(filter = (a) => a.edited, portalFilter = (a) => a.records.find(record => record.edited), portalRowFilter = (a) => a.edited, portalFieldFilter = (a) => a.edited) {
151
- let obj = super.toObject(filter, portalFilter, portalRowFilter, portalFieldFilter);
150
+ let obj = super.toObject(filter);
152
151
  // Check if there's been any edited portal information
153
152
  let portals = this.portalsArray.filter(a => portalFilter(a));
154
153
  if (portals) {
@@ -1,24 +1,33 @@
1
1
  /*
2
- * Copyright (c) 2023. See LICENSE file for more information
2
+ * Copyright (c) 2023-2024. See LICENSE file for more information
3
3
  */
4
4
 
5
- import {extraBodyOptions, recordObject} from "../types.js";
5
+ import {extraBodyOptions} from "../types.js";
6
6
  import {RecordBase} from "./recordBase.js";
7
7
  import {PortalRecord} from "./portalRecord.js";
8
8
  import {Portal} from "./portal.js";
9
- import {PortalInterface} from "../layouts/layoutInterface.js";
9
+ import {LayoutInterface} from "../layouts/layoutInterface.js";
10
10
  import {FMError} from "../FMError.js";
11
- import {RecordFieldsMap} from "../layouts/recordFieldsMap";
12
- import {LayoutRecordBase} from "./layoutRecordBase";
13
- import {ApiRecordResponseObj, ApiResultSetObj} from "../models/apiResults";
11
+ import {LayoutRecordBase} from "./layoutRecordBase.js";
12
+ import {ApiPortalData, ApiRecordResponseObj} from "../models/apiResults.js";
13
+ import {LayoutBase} from "../layouts/layoutBase.js"
14
+ import {FieldBase, FieldValue} from "./fieldBase.js";
14
15
 
15
- export class LayoutRecord<T extends RecordFieldsMap, P extends PortalInterface> extends RecordBase<T> implements LayoutRecordBase {
16
+ export class LayoutRecord<LAYOUT extends LayoutInterface, PORTALS_TO_INCLUDE = string> extends RecordBase<LAYOUT["fields"]> implements LayoutRecordBase {
16
17
  // @ts-ignore
17
- portals: P = {}
18
-
19
- constructor(layout, recordId, modId = recordId, fieldData = {}, portalData = null) {
20
- super(layout, recordId, modId);
18
+ portals: Pick<LAYOUT["portals"], PORTALS_TO_INCLUDE> = {}
19
+ private readonly portalsToInclude: PORTALS_TO_INCLUDE[]
20
+
21
+ constructor(
22
+ layout: LayoutBase,
23
+ recordId: number | string,
24
+ modId = recordId,
25
+ fieldData: Record<string, string | number> = {},
26
+ portalData: ApiPortalData | null = null, portalsToInclude: PORTALS_TO_INCLUDE[] = [])
27
+ {
28
+ super(layout, parseInt(recordId as string), parseInt(modId as string));
21
29
  this.processFieldData(fieldData)
30
+ this.portalsToInclude = portalsToInclude
22
31
  if (portalData) {
23
32
  this.processPortalData(portalData)
24
33
  }
@@ -29,7 +38,7 @@ export class LayoutRecord<T extends RecordFieldsMap, P extends PortalInterface>
29
38
  }
30
39
 
31
40
  async commit(extraBody: extraBodyOptions = {}): Promise<this> {
32
- let data = this.toObject()
41
+ let data: any = this.toObject()
33
42
  delete data.recordId
34
43
  delete data.modId
35
44
 
@@ -92,14 +101,14 @@ export class LayoutRecord<T extends RecordFieldsMap, P extends PortalInterface>
92
101
  }
93
102
  }
94
103
 
95
- protected processPortalData(portalData): void {
104
+ protected processPortalData(portalData: ApiPortalData): void {
96
105
  for (let portalName of Object.keys(portalData)) {
97
106
  let _portal = new Portal(this, portalName)
98
107
  _portal.records = portalData[portalName].map(item => {
99
108
  let fieldData = item;
100
109
  delete fieldData.recordId;
101
110
  delete fieldData.modId;
102
- return new PortalRecord(this, _portal, item.recordId, item.modId, fieldData);
111
+ return new PortalRecord(this, _portal, parseInt(item.recordId as string), parseInt(item.modId as string), fieldData);
103
112
  })
104
113
 
105
114
  // @ts-ignore
@@ -128,11 +137,7 @@ export class LayoutRecord<T extends RecordFieldsMap, P extends PortalInterface>
128
137
  }
129
138
  }
130
139
 
131
- getPortal(portal) {
132
- return this.portalsArray.find(p => p.name === portal)
133
- }
134
-
135
- async duplicate(): Promise<LayoutRecord<T, P>> {
140
+ async duplicate(): Promise<LayoutRecord<LAYOUT>> {
136
141
  let trace = new Error()
137
142
  let res = await this.layout.database.apiRequest<{recordId: string, modId: string}>(this.endpoint, {
138
143
  port: 443,
@@ -143,7 +148,7 @@ export class LayoutRecord<T extends RecordFieldsMap, P extends PortalInterface>
143
148
  }
144
149
  else if (res.messages[0].code === "0") {
145
150
  let data = this.toObject((a) => true, (a) => true, (a) => false, (a) => false)
146
- let _res = new LayoutRecord<T, P>(this.layout, res.response.recordId, res.response.modId, data.fieldData, data.portalData)
151
+ let _res = new LayoutRecord<LAYOUT>(this.layout, res.response.recordId, res.response.modId, data.fieldData, data.portalData)
147
152
 
148
153
  this.emit("duplicated")
149
154
  return _res
@@ -171,8 +176,13 @@ export class LayoutRecord<T extends RecordFieldsMap, P extends PortalInterface>
171
176
  }
172
177
  }
173
178
 
174
- toObject(filter: (a) => any = (a) => a.edited, portalFilter: (a) => any = (a) => a.records.find(record => record.edited), portalRowFilter: (a) => any = (a) => a.edited, portalFieldFilter: (a) => any = (a) => a.edited): recordObject {
175
- let obj = super.toObject(filter, portalFilter, portalRowFilter, portalFieldFilter);
179
+ toObject(
180
+ filter: (a: FieldBase<FieldValue>) => any = (a) => a.edited,
181
+ portalFilter: (a: Portal<any>) => any = (a) => a.records.find(record => record.edited),
182
+ portalRowFilter: (a: PortalRecord<never>) => any = (a) => a.edited,
183
+ portalFieldFilter: (a: FieldBase<FieldValue>) => any = (a) => a.edited
184
+ ) {
185
+ let obj = super.toObject(filter);
176
186
 
177
187
  // Check if there's been any edited portal information
178
188
  let portals = this.portalsArray.filter(a => portalFilter(a))
@@ -1,11 +1,12 @@
1
1
  import { PortalRecord } from "./portalRecord.js";
2
- import { RecordFieldsMap } from "../layouts/recordFieldsMap";
3
- import { PortalBase } from "./portalBase";
4
- import { LayoutRecord } from "./layoutRecord";
2
+ import { RecordFieldsMap } from "../layouts/recordFieldsMap.js";
3
+ import { PortalBase } from "./portalBase.js";
4
+ import { LayoutRecord } from "./layoutRecord.js";
5
+ import { LayoutInterface } from "../layouts/layoutInterface.js";
5
6
  export declare class Portal<T extends RecordFieldsMap> implements PortalBase<T> {
6
- readonly record: LayoutRecord<any, any>;
7
+ readonly record: LayoutRecord<LayoutInterface>;
7
8
  readonly name: string;
8
9
  records: PortalRecord<T>[];
9
- constructor(record: LayoutRecord<any, any>, name: string);
10
+ constructor(record: LayoutRecord<LayoutInterface, any>, name: string);
10
11
  create(): PortalRecord<T>;
11
12
  }
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright (c) 2023. See LICENSE file for more information
2
+ * Copyright (c) 2023-2024. See LICENSE file for more information
3
3
  */
4
4
  import { PortalRecord } from "./portalRecord.js";
5
5
  export class Portal {