@jd-data-limited/easy-fm 4.1.5 → 4.1.8
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/dist/bin/cli.js +17 -0
- package/dist/bin/generateTypes.js +161 -0
- package/{src → dist}/connection/FMHost.js +3 -2
- package/{src → dist}/connection/database.d.ts +0 -1
- package/{src → dist}/connection/database.js +22 -39
- package/dist/index.d.ts +18 -0
- package/dist/index.js +16 -0
- package/{src → dist}/records/field.d.ts +0 -1
- package/{src → dist}/records/getOperations/recordGetOperation.d.ts +6 -2
- package/{src → dist}/records/getOperations/recordGetOperation.js +9 -5
- package/{src → dist}/records/layoutRecord.d.ts +1 -1
- package/{src → dist}/records/layoutRecord.js +9 -7
- package/{src → dist}/records/recordBase.d.ts +0 -1
- package/{src → dist}/types.d.ts +12 -2
- package/package.json +23 -12
- package/src/FMError.ts +0 -1033
- package/src/bin/cli.js +0 -17
- package/src/bin/cli.ts +0 -22
- package/src/bin/generateTypes.d.ts +0 -1
- package/src/bin/generateTypes.js +0 -161
- package/src/bin/generateTypes.ts +0 -189
- package/src/connection/FMHost.ts +0 -123
- package/src/connection/HostBase.ts +0 -18
- package/src/connection/database.ts +0 -257
- package/src/connection/databaseBase.ts +0 -19
- package/src/connection/generateAuthorizationHeaders.ts +0 -32
- package/src/connection/requestHoldable.d.ts +0 -10
- package/src/connection/requestHoldable.js +0 -44
- package/src/databaseStructure.ts +0 -10
- package/src/index.d.ts +0 -18
- package/src/index.js +0 -18
- package/src/index.ts +0 -47
- package/src/layouts/layout.ts +0 -66
- package/src/layouts/layoutBase.ts +0 -16
- package/src/layouts/layoutInterface.ts +0 -13
- package/src/layouts/layoutRecordManager.ts +0 -66
- package/src/layouts/recordFieldsMap.ts +0 -7
- package/src/models/apiResults.ts +0 -110
- package/src/records/field.ts +0 -235
- package/src/records/getOperations/recordGetOperation.ts +0 -268
- package/src/records/layoutRecord.ts +0 -246
- package/src/records/layoutRecordBase.ts +0 -10
- package/src/records/portal.ts +0 -43
- package/src/records/portalBase.ts +0 -14
- package/src/records/portalRecord.ts +0 -52
- package/src/records/recordBase.ts +0 -91
- package/src/types.ts +0 -150
- package/src/utils/query.ts +0 -59
- /package/{src → dist}/FMError.d.ts +0 -0
- /package/{src → dist}/FMError.js +0 -0
- /package/{src → dist}/bin/cli.d.ts +0 -0
- /package/{src/bin/dist → dist}/bin/generateTypes.d.ts +0 -0
- /package/{src → dist}/connection/FMHost.d.ts +0 -0
- /package/{src → dist}/connection/HostBase.d.ts +0 -0
- /package/{src → dist}/connection/HostBase.js +0 -0
- /package/{src → dist}/connection/databaseBase.d.ts +0 -0
- /package/{src → dist}/connection/databaseBase.js +0 -0
- /package/{src → dist}/connection/generateAuthorizationHeaders.d.ts +0 -0
- /package/{src → dist}/connection/generateAuthorizationHeaders.js +0 -0
- /package/{src → dist}/databaseStructure.d.ts +0 -0
- /package/{src → dist}/databaseStructure.js +0 -0
- /package/{src → dist}/layouts/layout.d.ts +0 -0
- /package/{src → dist}/layouts/layout.js +0 -0
- /package/{src → dist}/layouts/layoutBase.d.ts +0 -0
- /package/{src → dist}/layouts/layoutBase.js +0 -0
- /package/{src → dist}/layouts/layoutInterface.d.ts +0 -0
- /package/{src → dist}/layouts/layoutInterface.js +0 -0
- /package/{src → dist}/layouts/layoutRecordManager.d.ts +0 -0
- /package/{src → dist}/layouts/layoutRecordManager.js +0 -0
- /package/{src → dist}/layouts/recordFieldsMap.d.ts +0 -0
- /package/{src → dist}/layouts/recordFieldsMap.js +0 -0
- /package/{src → dist}/models/apiResults.d.ts +0 -0
- /package/{src → dist}/models/apiResults.js +0 -0
- /package/{src → dist}/records/field.js +0 -0
- /package/{src → dist}/records/layoutRecordBase.d.ts +0 -0
- /package/{src → dist}/records/layoutRecordBase.js +0 -0
- /package/{src → dist}/records/portal.d.ts +0 -0
- /package/{src → dist}/records/portal.js +0 -0
- /package/{src → dist}/records/portalBase.d.ts +0 -0
- /package/{src → dist}/records/portalBase.js +0 -0
- /package/{src → dist}/records/portalRecord.d.ts +0 -0
- /package/{src → dist}/records/portalRecord.js +0 -0
- /package/{src → dist}/records/recordBase.js +0 -0
- /package/{src → dist}/types.js +0 -0
- /package/{src → dist}/utils/query.d.ts +0 -0
- /package/{src → dist}/utils/query.js +0 -0
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2023-2024. See LICENSE file for more information
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {type extraBodyOptions} from '../types.js'
|
|
6
|
-
import {RecordBase} from './recordBase.js'
|
|
7
|
-
import {PortalRecord} from './portalRecord.js'
|
|
8
|
-
import {Portal} from './portal.js'
|
|
9
|
-
import {type LayoutInterface} from '../layouts/layoutInterface.js'
|
|
10
|
-
import {FMError} from '../FMError.js'
|
|
11
|
-
import {type LayoutRecordBase} from './layoutRecordBase.js'
|
|
12
|
-
import {
|
|
13
|
-
type ApiFieldData,
|
|
14
|
-
type ApiPortalData,
|
|
15
|
-
type ApiRecordResponseObj,
|
|
16
|
-
type ApiRowDataDef
|
|
17
|
-
} from '../models/apiResults.js'
|
|
18
|
-
import {type LayoutBase} from '../layouts/layoutBase.js'
|
|
19
|
-
import * as moment from 'moment/moment.js'
|
|
20
|
-
import {type Field, type FieldValue} from './field.js'
|
|
21
|
-
|
|
22
|
-
export class LayoutRecord<LAYOUT extends LayoutInterface> extends RecordBase<LAYOUT['fields']> implements LayoutRecordBase {
|
|
23
|
-
portals: LAYOUT['portals'] = {}
|
|
24
|
-
private readonly portalsToInclude: Array<string | number | symbol>
|
|
25
|
-
|
|
26
|
-
constructor (
|
|
27
|
-
layout: LayoutBase,
|
|
28
|
-
recordId: number | string,
|
|
29
|
-
modId = recordId,
|
|
30
|
-
fieldData: Record<string, string | number> = {},
|
|
31
|
-
portalData: ApiPortalData | null = null, portalsToInclude: Array<keyof LAYOUT['portals']> = []) {
|
|
32
|
-
super(layout, parseInt(recordId as string), parseInt(modId as string), fieldData)
|
|
33
|
-
this.portalsToInclude = portalsToInclude
|
|
34
|
-
if (portalData) {
|
|
35
|
-
this.processPortalData(portalData)
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
get portalsArray (): Array<Portal<any>> {
|
|
40
|
-
return Object.values(this.portals)
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Asynchronously commits the changes made to the current record.
|
|
45
|
-
* @param {extraBodyOptions} extraBody - The options for the extra body elements.
|
|
46
|
-
* @returns {Promise<this>} - A promise that resolves with the modified object.
|
|
47
|
-
* @throws {FMError} - If an error occurs during the commit process.
|
|
48
|
-
*/
|
|
49
|
-
async commit (extraBody: extraBodyOptions = {}): Promise<this> {
|
|
50
|
-
const data: any = this.toObject()
|
|
51
|
-
delete data.recordId
|
|
52
|
-
delete data.modId
|
|
53
|
-
|
|
54
|
-
if (extraBody.scripts?.after) {
|
|
55
|
-
data.script = extraBody.scripts.after.name
|
|
56
|
-
if (extraBody.scripts.after.parameter) data['script.param'] = extraBody.scripts.after.parameter
|
|
57
|
-
}
|
|
58
|
-
if (extraBody.scripts?.prerequest) {
|
|
59
|
-
data['script.prerequest'] = extraBody.scripts.prerequest.name
|
|
60
|
-
if (extraBody.scripts.prerequest.parameter) data['script.prerequest.param'] = extraBody.scripts.prerequest.parameter
|
|
61
|
-
}
|
|
62
|
-
if (extraBody.scripts?.presort) {
|
|
63
|
-
data['script.presort'] = extraBody.scripts.presort.name
|
|
64
|
-
if (extraBody.scripts.presort.parameter) data['script.presort.param'] = extraBody.scripts.presort.parameter
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (this.recordId === -1) {
|
|
68
|
-
// This is a new LayoutRecord
|
|
69
|
-
const res = await this.layout.database._apiRequestJSON<{ recordId: string, modId: string }>(`${this.layout.endpoint}/records`, {
|
|
70
|
-
method: 'POST',
|
|
71
|
-
body: JSON.stringify(data)
|
|
72
|
-
})
|
|
73
|
-
console.log(res)
|
|
74
|
-
|
|
75
|
-
if (!res.response) {
|
|
76
|
-
throw new FMError(res.messages[0].code, res.httpStatus, res)
|
|
77
|
-
} else if (typeof res.response.scriptError !== 'undefined' && res.response.scriptError !== '0') {
|
|
78
|
-
throw new FMError(res.response.scriptError, res.httpStatus, res)
|
|
79
|
-
} else if (res.messages[0].code === '0') {
|
|
80
|
-
this.recordId = parseInt(res.response.recordId)
|
|
81
|
-
this.modId = parseInt(res.response.modId)
|
|
82
|
-
return this
|
|
83
|
-
} else {
|
|
84
|
-
throw new FMError(res.messages[0].code, res.httpStatus, res)
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// for (let item of Object.keys(data)) extraBody[item] = data[item]
|
|
89
|
-
const res = await this.layout.database._apiRequestJSON<{
|
|
90
|
-
modId: string,
|
|
91
|
-
newPortalRecordInfo: Array<{
|
|
92
|
-
tableName: string
|
|
93
|
-
recordId: string
|
|
94
|
-
modId: string
|
|
95
|
-
}>
|
|
96
|
-
}>(this.endpoint, {
|
|
97
|
-
method: 'PATCH',
|
|
98
|
-
body: JSON.stringify(data)
|
|
99
|
-
})
|
|
100
|
-
if (!res.response) {
|
|
101
|
-
throw new FMError(res.messages[0].code, res.httpStatus, res)
|
|
102
|
-
} else if (typeof res.response.scriptError !== 'undefined' && res.response.scriptError !== '0') {
|
|
103
|
-
throw new FMError(res.response.scriptError, res.httpStatus, res)
|
|
104
|
-
} else if (res.messages[0].code === '0') {
|
|
105
|
-
this.modId = +res.response.modId
|
|
106
|
-
this._onSave()
|
|
107
|
-
return this
|
|
108
|
-
} else {
|
|
109
|
-
throw new FMError(res.messages[0].code, res.httpStatus, res)
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
protected processPortalData (portalData: ApiPortalData): void {
|
|
114
|
-
for (const portalName of Object.keys(portalData)) {
|
|
115
|
-
const _portal = new Portal(this, portalName)
|
|
116
|
-
_portal.records = portalData[portalName].map(item => {
|
|
117
|
-
const fieldData = item
|
|
118
|
-
delete fieldData.recordId
|
|
119
|
-
delete fieldData.modId
|
|
120
|
-
return new PortalRecord(this, _portal, parseInt(item.recordId as string), parseInt(item.modId as string), fieldData)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
// @ts-expect-error - This code is actually correct, but throws a typescript error
|
|
124
|
-
this.portals[portalName] = _portal
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Re-fetches the current record from the database server.
|
|
130
|
-
* Throws an error if commit() has not been called.
|
|
131
|
-
*
|
|
132
|
-
* @return {Promise<this>} A Promise that resolves to this RecordBase instance if the record is successfully retrieved.
|
|
133
|
-
* @throws {Error} If commit() has not been called.
|
|
134
|
-
* @throws {FMError} If the retrieval fails.
|
|
135
|
-
*/
|
|
136
|
-
async get (): Promise<this> {
|
|
137
|
-
if (this.recordId === -1) {
|
|
138
|
-
throw new Error('Cannot get this RecordBase until a commit() is done.')
|
|
139
|
-
}
|
|
140
|
-
if (!this.layout.metadata) await this.layout.getLayoutMeta()
|
|
141
|
-
const res = await this.layout.database._apiRequestJSON<ApiRecordResponseObj>(this.endpoint, {
|
|
142
|
-
method: 'GET'
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
if (res.response && res.messages[0].code === '0') {
|
|
146
|
-
// console.log(res, res.response.data)
|
|
147
|
-
this.modId = +res.response.data[0].modId
|
|
148
|
-
this.processFieldData(res.response.data[0].fieldData)
|
|
149
|
-
this.portalData = []
|
|
150
|
-
if (res.response.data[0].portalData) this.processPortalData(res.response.data[0].portalData)
|
|
151
|
-
return this
|
|
152
|
-
} else {
|
|
153
|
-
throw new FMError(res.messages[0].code, res.httpStatus, res)
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
async duplicate (): Promise<LayoutRecord<LAYOUT>> {
|
|
158
|
-
const trace = new Error()
|
|
159
|
-
const res = await this.layout.database._apiRequestJSON<{ recordId: string, modId: string }>(this.endpoint, {
|
|
160
|
-
method: 'POST'
|
|
161
|
-
})
|
|
162
|
-
if (!res.response) {
|
|
163
|
-
throw new FMError(res.messages[0].code, res.httpStatus, res, trace)
|
|
164
|
-
} else if (typeof res.response.scriptError !== 'undefined' && res.response.scriptError !== '0') {
|
|
165
|
-
throw new FMError(res.response.scriptError, res.httpStatus, res, trace)
|
|
166
|
-
} else if (res.messages[0].code === '0') {
|
|
167
|
-
const data = this.toObject((a) => true, (a) => true, (a) => false, (a) => false)
|
|
168
|
-
const _res = new LayoutRecord<LAYOUT>(this.layout, res.response.recordId, res.response.modId, data.fieldData, data.portalData)
|
|
169
|
-
|
|
170
|
-
this.emit('duplicated')
|
|
171
|
-
return _res
|
|
172
|
-
} else {
|
|
173
|
-
throw new FMError(res.messages[0].code, res.httpStatus, res, trace)
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
async delete (): Promise<void> {
|
|
178
|
-
const res = await this.layout.database._apiRequestJSON(this.endpoint, {
|
|
179
|
-
method: 'DELETE'
|
|
180
|
-
})
|
|
181
|
-
if (typeof res.response?.scriptError !== 'undefined' && res.response?.scriptError !== '0') {
|
|
182
|
-
throw new FMError(res.response.scriptError, res.httpStatus, res)
|
|
183
|
-
} else if (res.messages[0].code === '0') {
|
|
184
|
-
this.emit('deleted')
|
|
185
|
-
} else {
|
|
186
|
-
throw new FMError(res.messages[0].code, res.httpStatus, res)
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
fieldsToObject (filter = (a: Field<FieldValue>) => a.edited): Omit<ApiRowDataDef, 'portalData'> {
|
|
191
|
-
const fields_processed: ApiFieldData = {}
|
|
192
|
-
let field: Field<FieldValue>
|
|
193
|
-
for (field of this.fieldsArray.filter(field => filter(field))) {
|
|
194
|
-
let value = field.value as string | number | Date
|
|
195
|
-
if (value instanceof Date) {
|
|
196
|
-
let _value = moment.default(value)
|
|
197
|
-
_value = _value
|
|
198
|
-
.utcOffset(this.layout.database.host.timezoneOffsetFunc(_value))
|
|
199
|
-
|
|
200
|
-
switch (field.metadata.result) {
|
|
201
|
-
case 'time':
|
|
202
|
-
value = _value.format(this.layout.database.host.timeFormat)
|
|
203
|
-
break
|
|
204
|
-
case 'date':
|
|
205
|
-
value = _value.format(this.layout.database.host.dateFormat)
|
|
206
|
-
break
|
|
207
|
-
default:
|
|
208
|
-
value = _value.format(this.layout.database.host.timeStampFormat)
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
fields_processed[field.id] = value
|
|
212
|
-
}
|
|
213
|
-
const obj = {
|
|
214
|
-
recordId: this.recordId.toString(),
|
|
215
|
-
modId: this.modId.toString(),
|
|
216
|
-
fieldData: fields_processed
|
|
217
|
-
}
|
|
218
|
-
return obj
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
toObject (
|
|
222
|
-
filter: (a: Field<FieldValue>) => any = (a) => a.edited,
|
|
223
|
-
portalFilter: (a: Portal<any>) => any = (a) => a.records.find(record => record.edited),
|
|
224
|
-
portalRowFilter: (a: PortalRecord<never>) => any = (a) => a.edited,
|
|
225
|
-
portalFieldFilter: (a: Field<FieldValue>) => any = (a) => a.edited
|
|
226
|
-
) {
|
|
227
|
-
const obj: ApiRowDataDef = {
|
|
228
|
-
...this.fieldsToObject(filter),
|
|
229
|
-
portalData: {}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Check if there's been any edited portal information
|
|
233
|
-
const portals = this.portalsArray.filter(a => portalFilter(a))
|
|
234
|
-
if (portals) {
|
|
235
|
-
obj.portalData = {}
|
|
236
|
-
for (const portal of portals) {
|
|
237
|
-
// @ts-expect-error
|
|
238
|
-
obj.portalData[portal.name] = portal.records.filter(a => portalRowFilter(a)).map(record => {
|
|
239
|
-
return record.toObject(portalFieldFilter)
|
|
240
|
-
})
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return obj
|
|
245
|
-
}
|
|
246
|
-
}
|
package/src/records/portal.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2023-2024. See LICENSE file for more information
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {PortalRecord} from './portalRecord.js'
|
|
6
|
-
import {type RecordFieldsMap} from '../layouts/recordFieldsMap.js'
|
|
7
|
-
import {type PortalBase} from './portalBase.js'
|
|
8
|
-
import {type LayoutRecord} from './layoutRecord.js'
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Represents a portal.
|
|
12
|
-
*
|
|
13
|
-
* @template T - The type of RecordFieldsMap.
|
|
14
|
-
* @class
|
|
15
|
-
* @implements {PortalBase<T>}
|
|
16
|
-
*/
|
|
17
|
-
export class Portal<T extends RecordFieldsMap> implements PortalBase<T> {
|
|
18
|
-
readonly record: LayoutRecord<any>
|
|
19
|
-
readonly name: string
|
|
20
|
-
public records: Array<PortalRecord<T>> = []
|
|
21
|
-
|
|
22
|
-
constructor (record: LayoutRecord<any>, name: string) {
|
|
23
|
-
this.record = record
|
|
24
|
-
this.name = name
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Add a new record to the portal
|
|
29
|
-
* @function create
|
|
30
|
-
* @async
|
|
31
|
-
* @summary Creates a new record.
|
|
32
|
-
* @returns {Promise<PortalRecord<T>>} A Promise that resolves to the newly created record.
|
|
33
|
-
*/
|
|
34
|
-
async create () {
|
|
35
|
-
const fields: Record<string, string> = {}
|
|
36
|
-
for (const _field of (await this.record.layout.getLayoutMeta()).portalMetaData[this.name]) {
|
|
37
|
-
fields[_field.name] = ''
|
|
38
|
-
}
|
|
39
|
-
const record = new PortalRecord<T>(this.record, this, -1, -1, fields)
|
|
40
|
-
this.records.push(record)
|
|
41
|
-
return record
|
|
42
|
-
}
|
|
43
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2023-2024. See LICENSE file for more information
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {type RecordFieldsMap} from '../layouts/recordFieldsMap.js'
|
|
6
|
-
import {type RecordBase} from './recordBase.js'
|
|
7
|
-
import {type LayoutRecord} from './layoutRecord.js'
|
|
8
|
-
import {type LayoutInterface} from '../layouts/layoutInterface.js'
|
|
9
|
-
|
|
10
|
-
export interface PortalBase<T extends RecordFieldsMap> {
|
|
11
|
-
readonly record: LayoutRecord<LayoutInterface>
|
|
12
|
-
readonly name: string
|
|
13
|
-
records: Array<RecordBase<T>>
|
|
14
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2023-2024. See LICENSE file for more information
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {RecordBase} from './recordBase.js'
|
|
6
|
-
import {type extraBodyOptions, RecordTypes} from '../types.js'
|
|
7
|
-
|
|
8
|
-
import {type RecordFieldsMap} from '../layouts/recordFieldsMap.js'
|
|
9
|
-
import {type PortalBase} from './portalBase.js'
|
|
10
|
-
import {type Field, type FieldValue} from './field.js'
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Represents a PortalRecord, which is a record in a portal within a parent record.
|
|
14
|
-
* @template T - The type of the record's field map.
|
|
15
|
-
*/
|
|
16
|
-
export class PortalRecord<T extends RecordFieldsMap> extends RecordBase<T> {
|
|
17
|
-
readonly portal: PortalBase<T>
|
|
18
|
-
readonly type = RecordTypes.PORTAL
|
|
19
|
-
|
|
20
|
-
constructor (record: RecordBase<any>, portal: PortalBase<any>, recordId: number, modId = recordId, fieldData = {}) {
|
|
21
|
-
super(record.layout, recordId, modId, fieldData)
|
|
22
|
-
this.portal = portal
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
_onSave () {
|
|
26
|
-
super._onSave()
|
|
27
|
-
this.portal.record._onSave()
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Commits the parent record, and in turn this one.
|
|
32
|
-
*
|
|
33
|
-
* @param {extraBodyOptions} [extraBody={}] - The optional extra body options.
|
|
34
|
-
* @returns {Promise} - A promise that resolves when the record is committed.
|
|
35
|
-
*/
|
|
36
|
-
async commit (extraBody: extraBodyOptions = {}) {
|
|
37
|
-
return await this.portal.record.commit(extraBody)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
toObject (fieldFilter: (a: Field<FieldValue>) => boolean): {
|
|
41
|
-
modId?: string
|
|
42
|
-
recordId?: string
|
|
43
|
-
} & Record<string, string> {
|
|
44
|
-
const res: any = {
|
|
45
|
-
recordId: this.recordId === -1 ? undefined : this.recordId.toString(),
|
|
46
|
-
modId: this.modId === -1 ? undefined : this.modId.toString()
|
|
47
|
-
}
|
|
48
|
-
for (const field of this.fieldsArray.filter(a => fieldFilter(a))) res[field.id] = field.value?.toString()
|
|
49
|
-
// console.log(res)
|
|
50
|
-
return res
|
|
51
|
-
}
|
|
52
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2023-2024. See LICENSE file for more information
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import {EventEmitter} from 'events'
|
|
6
|
-
import * as moment from 'moment'
|
|
7
|
-
import {type Moment} from 'moment'
|
|
8
|
-
import {RecordTypes} from '../types.js'
|
|
9
|
-
import {type RecordFieldsMap} from '../layouts/recordFieldsMap.js'
|
|
10
|
-
import {type LayoutBase} from '../layouts/layoutBase.js'
|
|
11
|
-
import {type ApiFieldData} from '../models/apiResults.js'
|
|
12
|
-
import {Field, type FieldValue} from './field.js'
|
|
13
|
-
|
|
14
|
-
export abstract class RecordBase<T extends RecordFieldsMap> extends EventEmitter {
|
|
15
|
-
readonly layout: LayoutBase
|
|
16
|
-
readonly type: RecordTypes = RecordTypes.UNKNOWN
|
|
17
|
-
public recordId: number
|
|
18
|
-
modId: number
|
|
19
|
-
/**
|
|
20
|
-
* An object containing each field in this record.
|
|
21
|
-
*
|
|
22
|
-
* @template T - The type of the field.
|
|
23
|
-
*/
|
|
24
|
-
fields: T
|
|
25
|
-
protected portalData: any[] = []
|
|
26
|
-
|
|
27
|
-
protected constructor (layout: LayoutBase, recordId: number, modId = recordId, fieldData: ApiFieldData) {
|
|
28
|
-
super()
|
|
29
|
-
this.layout = layout
|
|
30
|
-
this.recordId = recordId
|
|
31
|
-
this.modId = modId
|
|
32
|
-
this.fields = this.processFieldData(fieldData)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
get endpoint (): string {
|
|
36
|
-
return `${this.layout.endpoint}/records/${this.recordId}`
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* A boolean indicating whether this record has been modified and should be committed
|
|
41
|
-
*
|
|
42
|
-
* @returns {boolean} A boolean value indicating whether any of the fields have been edited.
|
|
43
|
-
*/
|
|
44
|
-
get edited (): boolean {
|
|
45
|
-
return !!this.fieldsArray.find(i => i.edited)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
get fieldsArray (): Array<Field<FieldValue>> {
|
|
49
|
-
return Object.values(this.fields)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
protected processFieldData (fieldData: ApiFieldData) {
|
|
53
|
-
const fields: RecordFieldsMap = {}
|
|
54
|
-
|
|
55
|
-
for (const key of Object.keys(fieldData)) {
|
|
56
|
-
const _field = new Field<number | string | Moment>(this, key, fieldData[key])
|
|
57
|
-
if (fieldData[key]) {
|
|
58
|
-
if (_field.metadata.result === 'timeStamp') {
|
|
59
|
-
let date = moment.default(fieldData[key])
|
|
60
|
-
date = date
|
|
61
|
-
.utcOffset(this.layout.database.host.timezoneOffsetFunc(date), true)
|
|
62
|
-
.local()
|
|
63
|
-
_field.set(date)
|
|
64
|
-
_field.edited = false
|
|
65
|
-
} else if (_field.metadata.result === 'time') {
|
|
66
|
-
let date = moment.default(fieldData[key])
|
|
67
|
-
date = date
|
|
68
|
-
.utcOffset(this.layout.database.host.timezoneOffsetFunc(date), true)
|
|
69
|
-
.local()
|
|
70
|
-
_field.set(date)
|
|
71
|
-
_field.edited = false
|
|
72
|
-
} else if (_field.metadata.result === 'date') {
|
|
73
|
-
let date = moment.default(fieldData[key])
|
|
74
|
-
date = date
|
|
75
|
-
.utcOffset(this.layout.database.host.timezoneOffsetFunc(date), true)
|
|
76
|
-
.local()
|
|
77
|
-
_field.set(date)
|
|
78
|
-
_field.edited = false
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
fields[key] = _field
|
|
82
|
-
}
|
|
83
|
-
this.fields = fields as T
|
|
84
|
-
return fields as T
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
_onSave () {
|
|
88
|
-
this.emit('saved')
|
|
89
|
-
for (const field of this.fieldsArray) field.edited = false
|
|
90
|
-
}
|
|
91
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2022-2024. See LICENSE file for more information
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
// const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
|
6
|
-
import type * as http from 'http'
|
|
7
|
-
import {type FMError} from './FMError.js'
|
|
8
|
-
import {type LayoutInterface} from './layouts/layoutInterface.js'
|
|
9
|
-
|
|
10
|
-
export type PickPortals<LAYOUT extends LayoutInterface, PORTALS extends string | number | symbol = ''> =
|
|
11
|
-
Omit<LAYOUT, 'portals'> & { portals: Pick<LAYOUT['portals'], PORTALS> }
|
|
12
|
-
|
|
13
|
-
export interface databaseOptionsBase {
|
|
14
|
-
database: string
|
|
15
|
-
debug?: boolean
|
|
16
|
-
credentials: loginOptionsOAuth | loginOptionsFileMaker | loginOptionsClaris | loginOptionsToken
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface databaseOptionsWithExternalSources extends databaseOptionsBase {
|
|
20
|
-
database: string
|
|
21
|
-
debug?: boolean
|
|
22
|
-
credentials: loginOptionsOAuth | loginOptionsFileMaker | loginOptionsClaris | loginOptionsToken
|
|
23
|
-
externalSources: databaseOptionsBase[]
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface loginOptionsToken {
|
|
27
|
-
method: 'token'
|
|
28
|
-
token: string
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface loginOptionsOAuth {
|
|
32
|
-
method: 'oauth'
|
|
33
|
-
oauth: {
|
|
34
|
-
requestId: string
|
|
35
|
-
requestIdentifier: string
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface loginOptionsFileMaker {
|
|
40
|
-
method: 'filemaker'
|
|
41
|
-
username: string
|
|
42
|
-
password: string
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface loginOptionsClaris {
|
|
46
|
-
method: 'claris'
|
|
47
|
-
claris: {
|
|
48
|
-
fmid: string
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface portalFetchData<T = string> {
|
|
53
|
-
portalName: T
|
|
54
|
-
offset: number
|
|
55
|
-
limit: number
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export interface ScriptRequestData {
|
|
59
|
-
prerequest?: Script
|
|
60
|
-
presort?: Script
|
|
61
|
-
after?: Script
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export interface extraBodyOptions {
|
|
65
|
-
scripts?: ScriptRequestData
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export interface Script {
|
|
69
|
-
name: string
|
|
70
|
-
parameter: string
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface recordObject {
|
|
74
|
-
recordId: number
|
|
75
|
-
modId: number
|
|
76
|
-
fieldData: any
|
|
77
|
-
portalData?: portalDataObject
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export type portalDataObject = Record<string, recordObject>
|
|
81
|
-
|
|
82
|
-
export interface FieldMetaData {
|
|
83
|
-
name: string
|
|
84
|
-
type: string
|
|
85
|
-
displayType: string
|
|
86
|
-
result: string
|
|
87
|
-
global: boolean
|
|
88
|
-
autoEnter: boolean
|
|
89
|
-
fourDigitYear: boolean
|
|
90
|
-
maxRepeat: number
|
|
91
|
-
maxCharacters: number
|
|
92
|
-
notEmpty: boolean
|
|
93
|
-
numeric: boolean
|
|
94
|
-
timeOfDay: false
|
|
95
|
-
repetitionStart: number
|
|
96
|
-
repetitionEnd: number
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export interface LayoutMetaData {
|
|
100
|
-
fieldMetaData: FieldMetaData[]
|
|
101
|
-
portalMetaData?: Record<string, FieldMetaData[]>
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export interface FMHostMetadata {
|
|
105
|
-
productInfo: {
|
|
106
|
-
buildDate: Date
|
|
107
|
-
name: string
|
|
108
|
-
version: string
|
|
109
|
-
dateFormat: string
|
|
110
|
-
timeFormat: string
|
|
111
|
-
timeStampFormat: string
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export interface ScriptResult {
|
|
116
|
-
scriptError?: FMError
|
|
117
|
-
scriptResult?: string
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export interface ContainerBufferResult {
|
|
121
|
-
buffer: Buffer
|
|
122
|
-
mime?: string
|
|
123
|
-
request: http.IncomingMessage
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
//
|
|
127
|
-
// module.exports = {
|
|
128
|
-
// default: {FileMakerConnection}
|
|
129
|
-
// }
|
|
130
|
-
|
|
131
|
-
export interface AuthorizationHeaders {
|
|
132
|
-
'Content-Type': 'application/json'
|
|
133
|
-
Authorization: string
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export interface AuthorizationHeadersOAuth {
|
|
137
|
-
'Content-Type': 'application/json'
|
|
138
|
-
'X-FM-Data-OAuth-RequestId': string
|
|
139
|
-
'X-FM-Data-OAuth-Identifier': string
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export interface RecordFetchOptions {
|
|
143
|
-
readonly portals: readonly string[]
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
export enum RecordTypes {
|
|
147
|
-
UNKNOWN,
|
|
148
|
-
LAYOUT,
|
|
149
|
-
PORTAL
|
|
150
|
-
}
|
package/src/utils/query.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* Copyright (c) 2024. See LICENSE file for more information
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import moment, {type Moment} from 'moment'
|
|
6
|
-
|
|
7
|
-
export const FindRequestSymbol = Symbol('easyfm-findrequest')
|
|
8
|
-
const SPECIAL_CHARACTERS = ['\\', '=', '<', '≤', '≥', '>', '…', '...', '//', '@', '#', '*', '"', '~']
|
|
9
|
-
export interface TimestampType {
|
|
10
|
-
type: 'date' | 'time' | 'timestamp'
|
|
11
|
-
moment: Moment
|
|
12
|
-
}
|
|
13
|
-
type QueryParameter = string | number | TimestampType
|
|
14
|
-
export interface Query { [FindRequestSymbol]: Array<string | TimestampType> }
|
|
15
|
-
|
|
16
|
-
export function queryEscape (str: string) {
|
|
17
|
-
for (const char of SPECIAL_CHARACTERS) {
|
|
18
|
-
str = str.replace(char, `\\${char}`)
|
|
19
|
-
}
|
|
20
|
-
return str
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function query (strings: TemplateStringsArray, ...args: QueryParameter[]): Query {
|
|
24
|
-
const argStrings = args.map(item => {
|
|
25
|
-
if (typeof item === 'number') {
|
|
26
|
-
return queryEscape(item.toString())
|
|
27
|
-
} else if (typeof item === 'string') return queryEscape(item)
|
|
28
|
-
else return item
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
// Zip the parameters together
|
|
32
|
-
const query = strings.map((str, index) => {
|
|
33
|
-
return [str, (argStrings[index] || '')]
|
|
34
|
-
}).flat(1)
|
|
35
|
-
return {[FindRequestSymbol]: query}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function asDate (date: Date | Moment): TimestampType {
|
|
39
|
-
return {
|
|
40
|
-
type: 'date',
|
|
41
|
-
moment: moment(date)
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function asTime (date: Date | Moment): TimestampType {
|
|
46
|
-
return {
|
|
47
|
-
type: 'time',
|
|
48
|
-
moment: moment(date)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function asTimestamp (date: Date | Moment): TimestampType {
|
|
53
|
-
return {
|
|
54
|
-
type: 'timestamp',
|
|
55
|
-
moment: moment(date)
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
query
|
|
File without changes
|
/package/{src → dist}/FMError.js
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|