@jd-data-limited/easy-fm 4.0.14 → 4.0.16
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 +1 -1
- package/src/bin/cli.js +7 -5
- package/src/bin/generateTypes.js +215 -121
- package/src/connection/FMHost.d.ts +6 -2
- package/src/connection/FMHost.js +17 -6
- package/src/connection/FMHost.ts +24 -6
- package/src/connection/HostBase.d.ts +5 -1
- package/src/connection/HostBase.ts +5 -1
- package/src/index.d.ts +2 -2
- package/src/index.js +2 -2
- package/src/index.ts +5 -2
- package/src/records/getOperations/recordGetOperation.js +7 -2
- package/src/records/getOperations/recordGetOperation.ts +17 -7
- package/src/records/layoutRecord.js +6 -5
- package/src/records/layoutRecord.ts +5 -4
- package/src/records/recordBase.js +9 -6
- package/src/records/recordBase.ts +9 -6
- package/src/utils/query.d.ts +9 -2
- package/src/utils/query.js +24 -5
- package/src/utils/query.ts +34 -8
package/package.json
CHANGED
package/src/bin/cli.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
2
3
|
/*
|
|
3
4
|
* Copyright (c) 2024. See LICENSE file for more information
|
|
4
5
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
var commander_1 = require("commander");
|
|
8
|
+
var generateTypes_js_1 = require("./generateTypes.js");
|
|
9
|
+
var program = new commander_1.Command();
|
|
8
10
|
program
|
|
9
11
|
.name("easyfm")
|
|
10
12
|
.description("A NodeJS wrapper for the FileMaker Data CLI");
|
|
11
13
|
program
|
|
12
14
|
.command("generate-types")
|
|
13
15
|
.description("Automatically generate layout interfaces from your database")
|
|
14
|
-
.action(()
|
|
15
|
-
generateTypesCLI();
|
|
16
|
+
.action(function () {
|
|
17
|
+
(0, generateTypes_js_1.generateTypesCLI)();
|
|
16
18
|
});
|
|
17
19
|
program.parse(process.argv);
|
package/src/bin/generateTypes.js
CHANGED
|
@@ -1,10 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/*
|
|
2
3
|
* Copyright (c) 2024. See LICENSE file for more information
|
|
3
4
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
|
|
6
|
+
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
|
|
7
|
+
return cooked;
|
|
8
|
+
};
|
|
9
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
10
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
11
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
12
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
13
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
14
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
15
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
19
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
20
|
+
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
21
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
22
|
+
function step(op) {
|
|
23
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
24
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
25
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
26
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
27
|
+
switch (op[0]) {
|
|
28
|
+
case 0: case 1: t = op; break;
|
|
29
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
30
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
31
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
32
|
+
default:
|
|
33
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
34
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
35
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
36
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
37
|
+
if (t[2]) _.ops.pop();
|
|
38
|
+
_.trys.pop(); continue;
|
|
39
|
+
}
|
|
40
|
+
op = body.call(thisArg, _);
|
|
41
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
42
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.generateTypesCLI = void 0;
|
|
47
|
+
var apiResults_js_1 = require("../models/apiResults.js");
|
|
48
|
+
var inquirer_1 = require("inquirer");
|
|
49
|
+
var FMHost_js_1 = require("../connection/FMHost.js");
|
|
50
|
+
var fs = require("fs");
|
|
8
51
|
function sub(str) {
|
|
9
52
|
return str
|
|
10
53
|
.replace(/[^a-zA-Z0-9_]/g, "") // Remove non-alphanumeric characters
|
|
@@ -12,38 +55,42 @@ function sub(str) {
|
|
|
12
55
|
}
|
|
13
56
|
function generateFieldType(field) {
|
|
14
57
|
switch (field.result) {
|
|
15
|
-
case ApiFieldResultTypes.TEXT:
|
|
58
|
+
case apiResults_js_1.ApiFieldResultTypes.TEXT:
|
|
16
59
|
return "Field<string>";
|
|
17
|
-
case ApiFieldResultTypes.CONTAINER:
|
|
60
|
+
case apiResults_js_1.ApiFieldResultTypes.CONTAINER:
|
|
18
61
|
return "Field<Container>";
|
|
19
|
-
case ApiFieldResultTypes.DATE:
|
|
62
|
+
case apiResults_js_1.ApiFieldResultTypes.DATE:
|
|
20
63
|
return "Field<Date>";
|
|
21
|
-
case ApiFieldResultTypes.NUMBER:
|
|
64
|
+
case apiResults_js_1.ApiFieldResultTypes.NUMBER:
|
|
22
65
|
return "Field<number>";
|
|
23
|
-
case ApiFieldResultTypes.TIME:
|
|
66
|
+
case apiResults_js_1.ApiFieldResultTypes.TIME:
|
|
24
67
|
return "Field<Date>";
|
|
25
|
-
case ApiFieldResultTypes.TIMESTAMP:
|
|
68
|
+
case apiResults_js_1.ApiFieldResultTypes.TIMESTAMP:
|
|
26
69
|
return "Field<Date>";
|
|
27
70
|
}
|
|
28
71
|
}
|
|
29
72
|
function processFieldsChunk(fields) {
|
|
30
|
-
|
|
31
|
-
fields = fields.filter(field
|
|
73
|
+
var existing_fields = [];
|
|
74
|
+
fields = fields.filter(function (field) {
|
|
32
75
|
if (existing_fields.includes(field.name))
|
|
33
76
|
return false;
|
|
34
77
|
existing_fields.push(field.name);
|
|
35
78
|
return true;
|
|
36
79
|
});
|
|
37
|
-
return fields.map(field
|
|
80
|
+
return fields.map(function (field) {
|
|
38
81
|
return JSON.stringify(field.name) + ": " + generateFieldType(field);
|
|
39
82
|
});
|
|
40
83
|
}
|
|
41
84
|
function camelToSnakeCase(str) {
|
|
42
85
|
return str.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();
|
|
43
86
|
}
|
|
44
|
-
function safeStringInjection(str
|
|
45
|
-
|
|
46
|
-
for (
|
|
87
|
+
function safeStringInjection(str) {
|
|
88
|
+
var args = [];
|
|
89
|
+
for (var _i = 1; _i < arguments.length; _i++) {
|
|
90
|
+
args[_i - 1] = arguments[_i];
|
|
91
|
+
}
|
|
92
|
+
var result = "";
|
|
93
|
+
for (var i = 0; i < str.length; i++) {
|
|
47
94
|
result += str[i];
|
|
48
95
|
if (i < args.length) {
|
|
49
96
|
result += JSON.stringify(args[i].toString());
|
|
@@ -51,111 +98,158 @@ function safeStringInjection(str, ...args) {
|
|
|
51
98
|
}
|
|
52
99
|
return result;
|
|
53
100
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
101
|
+
function generateTypesCLI() {
|
|
102
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
103
|
+
var data, HOST, DATABASE, stream, layouts, layoutInterfaces, _loop_1, _i, layouts_1, layout, layoutInterfaceLinks, _a, layoutInterfaces_1, layout, _b, layoutInterfaces_2, layout;
|
|
104
|
+
return __generator(this, function (_c) {
|
|
105
|
+
switch (_c.label) {
|
|
106
|
+
case 0:
|
|
107
|
+
process.stdout.write('\x1Bc');
|
|
108
|
+
console.log("For this tool to work, you are required to have access to an account on the target database.\n" +
|
|
109
|
+
"This account must have the fmrest extended privilege enabled.\n" +
|
|
110
|
+
"This tool can only export type interfaces for layouts that the given account has access to.");
|
|
111
|
+
console.log("\n");
|
|
112
|
+
return [4 /*yield*/, inquirer_1.default.prompt([
|
|
113
|
+
{
|
|
114
|
+
type: "input",
|
|
115
|
+
name: "hostname",
|
|
116
|
+
message: "The IP address/domain of your FileMaker server (must start with either http:// or https://)",
|
|
117
|
+
validate: function (input) {
|
|
118
|
+
return input.startsWith("http://") || input.startsWith("https://") || "Please enter a valid IP address/domain starting with http:// or https://";
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
type: "number",
|
|
123
|
+
name: "timezoneOffset",
|
|
124
|
+
message: "Server timezone offset (minutes)",
|
|
125
|
+
default: 0 - (new Date()).getTimezoneOffset()
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
type: "confirm",
|
|
129
|
+
name: "verify",
|
|
130
|
+
default: true,
|
|
131
|
+
message: "Verify your server's identity",
|
|
132
|
+
when: function (previousAnswers) {
|
|
133
|
+
return previousAnswers.hostname.startsWith("https://");
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
type: "input",
|
|
138
|
+
name: "database",
|
|
139
|
+
message: "Database filename"
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
type: "input",
|
|
143
|
+
name: "username",
|
|
144
|
+
message: "Database username"
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
type: "password",
|
|
148
|
+
name: "password",
|
|
149
|
+
message: "Database password",
|
|
150
|
+
mask: "*"
|
|
151
|
+
}
|
|
152
|
+
])];
|
|
153
|
+
case 1:
|
|
154
|
+
data = _c.sent();
|
|
155
|
+
HOST = new FMHost_js_1.default(data.hostname, data.timezoneOffset, data.verify);
|
|
156
|
+
DATABASE = HOST.database({
|
|
157
|
+
database: data.database,
|
|
158
|
+
credentials: {
|
|
159
|
+
method: "filemaker",
|
|
160
|
+
username: data.username,
|
|
161
|
+
password: data.password
|
|
162
|
+
},
|
|
163
|
+
externalSources: []
|
|
164
|
+
});
|
|
165
|
+
return [4 /*yield*/, DATABASE.login()
|
|
166
|
+
// Create file write stream
|
|
167
|
+
];
|
|
168
|
+
case 2:
|
|
169
|
+
_c.sent();
|
|
170
|
+
stream = fs.createWriteStream("./types.ts");
|
|
171
|
+
return [4 /*yield*/, DATABASE.listLayouts()];
|
|
172
|
+
case 3:
|
|
173
|
+
layouts = _c.sent();
|
|
174
|
+
stream.write("import FMHost, {Container, FieldBase, LayoutInterface, Portal} from \"@jd-data-limited/easy-fm\";\n");
|
|
175
|
+
stream.write("// " + layouts.length + " layouts found\n\n");
|
|
176
|
+
layoutInterfaces = new Map();
|
|
177
|
+
_loop_1 = function (layout) {
|
|
178
|
+
var substituteName, metadata, fields, portals, portalsProcessed, interfaceName;
|
|
179
|
+
return __generator(this, function (_d) {
|
|
180
|
+
switch (_d.label) {
|
|
181
|
+
case 0:
|
|
182
|
+
substituteName = sub(layout.name);
|
|
183
|
+
if (!substituteName)
|
|
184
|
+
return [2 /*return*/, "continue"];
|
|
185
|
+
console.log(substituteName);
|
|
186
|
+
return [4 /*yield*/, layout.getLayoutMeta()];
|
|
187
|
+
case 1:
|
|
188
|
+
metadata = _d.sent();
|
|
189
|
+
fields = processFieldsChunk(metadata.fieldMetaData);
|
|
190
|
+
portals = metadata.portalMetaData;
|
|
191
|
+
portalsProcessed = Object.keys(portals).map(function (portalName) {
|
|
192
|
+
return "".concat(JSON.stringify(portalName), ": Portal<{").concat(processFieldsChunk(portals[portalName]), "}>");
|
|
193
|
+
});
|
|
194
|
+
interfaceName = substituteName + "LayoutInterface";
|
|
195
|
+
layoutInterfaces.set(layout.name, {
|
|
196
|
+
interfaceName: interfaceName,
|
|
197
|
+
interface: "export interface ".concat(interfaceName, " extends LayoutInterface {\n fields: {").concat(fields.join(",\n "), "},\n portals: {").concat(portalsProcessed.join(",\n "), "}\n }")
|
|
198
|
+
});
|
|
199
|
+
return [2 /*return*/];
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
_i = 0, layouts_1 = layouts;
|
|
204
|
+
_c.label = 4;
|
|
205
|
+
case 4:
|
|
206
|
+
if (!(_i < layouts_1.length)) return [3 /*break*/, 7];
|
|
207
|
+
layout = layouts_1[_i];
|
|
208
|
+
return [5 /*yield**/, _loop_1(layout)];
|
|
209
|
+
case 5:
|
|
210
|
+
_c.sent();
|
|
211
|
+
_c.label = 6;
|
|
212
|
+
case 6:
|
|
213
|
+
_i++;
|
|
214
|
+
return [3 /*break*/, 4];
|
|
215
|
+
case 7:
|
|
216
|
+
layoutInterfaceLinks = [];
|
|
217
|
+
for (_a = 0, layoutInterfaces_1 = layoutInterfaces; _a < layoutInterfaces_1.length; _a++) {
|
|
218
|
+
layout = layoutInterfaces_1[_a];
|
|
219
|
+
layoutInterfaceLinks.push([
|
|
220
|
+
"".concat(JSON.stringify(layout[0]), ": ").concat(layout[1].interfaceName),
|
|
221
|
+
"".concat(sub(camelToSnakeCase(layout[0]).toUpperCase().replace(" ", "_")), ": HOST.getLayout<").concat(layout[1].interfaceName, ">(").concat(JSON.stringify(layout[0]), ")")
|
|
222
|
+
]);
|
|
223
|
+
}
|
|
224
|
+
stream.write(safeStringInjection(templateObject_1 || (templateObject_1 = __makeTemplateObject(["const HOST = new FMHost(", ", ", ", ", ");"], ["const HOST = new FMHost(", ", ", ", ", ");"])), data.hostname, data.timezoneOffset, data.verify));
|
|
225
|
+
stream.write("HOST.database<{layouts:{".concat(layoutInterfaceLinks.map(function (i) { return i[0]; }).join(","), "}}>();"));
|
|
226
|
+
stream.write("\n\n");
|
|
227
|
+
stream.write("const LAYOUTS = {".concat(layoutInterfaceLinks.map(function (i) { return i[1]; }).join(","), "};"));
|
|
228
|
+
for (_b = 0, layoutInterfaces_2 = layoutInterfaces; _b < layoutInterfaces_2.length; _b++) {
|
|
229
|
+
layout = layoutInterfaces_2[_b];
|
|
230
|
+
stream.write("\n\n");
|
|
231
|
+
stream.write(layout[1].interface + ";");
|
|
232
|
+
}
|
|
233
|
+
// StructureKind
|
|
234
|
+
//
|
|
235
|
+
// const project = new Project({
|
|
236
|
+
// tsConfigFilePath: "../tsconfig.json"
|
|
237
|
+
// })
|
|
238
|
+
// project.resolveSourceFileDependencies()
|
|
239
|
+
return [4 /*yield*/, DATABASE.logout()];
|
|
240
|
+
case 8:
|
|
241
|
+
// StructureKind
|
|
242
|
+
//
|
|
243
|
+
// const project = new Project({
|
|
244
|
+
// tsConfigFilePath: "../tsconfig.json"
|
|
245
|
+
// })
|
|
246
|
+
// project.resolveSourceFileDependencies()
|
|
247
|
+
_c.sent();
|
|
248
|
+
console.log("DONE! Wrote database types to ./types.ts");
|
|
249
|
+
return [2 /*return*/];
|
|
82
250
|
}
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
type: "input",
|
|
86
|
-
name: "database",
|
|
87
|
-
message: "Database filename"
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
type: "input",
|
|
91
|
-
name: "username",
|
|
92
|
-
message: "Database username"
|
|
93
|
-
},
|
|
94
|
-
{
|
|
95
|
-
type: "password",
|
|
96
|
-
name: "password",
|
|
97
|
-
message: "Database password",
|
|
98
|
-
mask: "*"
|
|
99
|
-
}
|
|
100
|
-
]);
|
|
101
|
-
const HOST = new FMHost(data.hostname, data.timezoneOffset, data.verify);
|
|
102
|
-
const DATABASE = HOST.database({
|
|
103
|
-
database: data.database,
|
|
104
|
-
credentials: {
|
|
105
|
-
method: "filemaker",
|
|
106
|
-
username: data.username,
|
|
107
|
-
password: data.password
|
|
108
|
-
},
|
|
109
|
-
externalSources: []
|
|
110
|
-
});
|
|
111
|
-
await DATABASE.login();
|
|
112
|
-
// Create file write stream
|
|
113
|
-
const stream = fs.createWriteStream("./types.ts");
|
|
114
|
-
let layouts = await DATABASE.listLayouts();
|
|
115
|
-
stream.write(`import FMHost, {Container, FieldBase, LayoutInterface, Portal} from "@jd-data-limited/easy-fm";\n`);
|
|
116
|
-
stream.write("// " + layouts.length + " layouts found\n\n");
|
|
117
|
-
let layoutInterfaces = new Map();
|
|
118
|
-
for (let layout of layouts) {
|
|
119
|
-
let substituteName = sub(layout.name);
|
|
120
|
-
if (!substituteName)
|
|
121
|
-
continue;
|
|
122
|
-
console.log(substituteName);
|
|
123
|
-
let metadata = await layout.getLayoutMeta();
|
|
124
|
-
let fields = processFieldsChunk(metadata.fieldMetaData);
|
|
125
|
-
let portals = metadata.portalMetaData;
|
|
126
|
-
let portalsProcessed = Object.keys(portals).map(portalName => {
|
|
127
|
-
return `${JSON.stringify(portalName)}: Portal<{${processFieldsChunk(portals[portalName])}}>`;
|
|
128
|
-
});
|
|
129
|
-
let interfaceName = substituteName + "LayoutInterface";
|
|
130
|
-
layoutInterfaces.set(layout.name, {
|
|
131
|
-
interfaceName,
|
|
132
|
-
interface: `export interface ${interfaceName} extends LayoutInterface {
|
|
133
|
-
fields: {${fields.join(",\n ")}},
|
|
134
|
-
portals: {${portalsProcessed.join(",\n ")}}
|
|
135
|
-
}`
|
|
136
251
|
});
|
|
137
|
-
}
|
|
138
|
-
let layoutInterfaceLinks = [];
|
|
139
|
-
for (let layout of layoutInterfaces) {
|
|
140
|
-
layoutInterfaceLinks.push([
|
|
141
|
-
`${JSON.stringify(layout[0])}: ${layout[1].interfaceName}`,
|
|
142
|
-
`${sub(camelToSnakeCase(layout[0]).toUpperCase().replace(" ", "_"))}: HOST.getLayout<${layout[1].interfaceName}>(${JSON.stringify(layout[0])})`
|
|
143
|
-
]);
|
|
144
|
-
}
|
|
145
|
-
stream.write(safeStringInjection `const HOST = new FMHost(${data.hostname}, ${data.timezoneOffset}, ${data.verify});`);
|
|
146
|
-
stream.write(`HOST.database<{layouts:{${layoutInterfaceLinks.map(i => i[0]).join(",")}}}>();`);
|
|
147
|
-
stream.write("\n\n");
|
|
148
|
-
stream.write(`const LAYOUTS = {${layoutInterfaceLinks.map(i => i[1]).join(",")}};`);
|
|
149
|
-
for (let layout of layoutInterfaces) {
|
|
150
|
-
stream.write("\n\n");
|
|
151
|
-
stream.write(layout[1].interface + ";");
|
|
152
|
-
}
|
|
153
|
-
// StructureKind
|
|
154
|
-
//
|
|
155
|
-
// const project = new Project({
|
|
156
|
-
// tsConfigFilePath: "../tsconfig.json"
|
|
157
|
-
// })
|
|
158
|
-
// project.resolveSourceFileDependencies()
|
|
159
|
-
await DATABASE.logout();
|
|
160
|
-
console.log("DONE! Wrote database types to ./types.ts");
|
|
252
|
+
});
|
|
161
253
|
}
|
|
254
|
+
exports.generateTypesCLI = generateTypesCLI;
|
|
255
|
+
var templateObject_1;
|
|
@@ -2,13 +2,17 @@ import { Database } from "./database.js";
|
|
|
2
2
|
import { HostBase } from "./HostBase.js";
|
|
3
3
|
import { databaseOptionsWithExternalSources, FMHostMetadata, loginOptionsClaris, loginOptionsFileMaker, loginOptionsOAuth } from "../types.js";
|
|
4
4
|
import { DatabaseStructure } from "../databaseStructure.js";
|
|
5
|
+
import { Moment } from "moment";
|
|
5
6
|
export default class FMHost implements HostBase {
|
|
6
7
|
readonly hostname: string;
|
|
7
|
-
readonly
|
|
8
|
+
readonly timezoneOffsetFunc: (moment: Moment) => number;
|
|
8
9
|
readonly verify: boolean;
|
|
9
10
|
_metadata: FMHostMetadata | null;
|
|
10
|
-
constructor(_hostname: string, timezoneOffset?: number, verify?: boolean);
|
|
11
|
+
constructor(_hostname: string, timezoneOffset?: (moment: Moment) => number, verify?: boolean);
|
|
11
12
|
get metadata(): FMHostMetadata;
|
|
13
|
+
get dateFormat(): string;
|
|
14
|
+
get timeFormat(): string;
|
|
15
|
+
get timeStampFormat(): string;
|
|
12
16
|
listDatabases(credentials?: loginOptionsOAuth | loginOptionsFileMaker | loginOptionsClaris): Promise<any>;
|
|
13
17
|
database<T extends DatabaseStructure>(data: databaseOptionsWithExternalSources): Database<T>;
|
|
14
18
|
getMetadata(): Promise<FMHostMetadata>;
|
package/src/connection/FMHost.js
CHANGED
|
@@ -6,14 +6,14 @@ import { FMError } from "../FMError.js";
|
|
|
6
6
|
import { Database } from "./database.js";
|
|
7
7
|
export default class FMHost {
|
|
8
8
|
hostname;
|
|
9
|
-
|
|
9
|
+
timezoneOffsetFunc;
|
|
10
10
|
verify;
|
|
11
11
|
_metadata = null;
|
|
12
|
-
constructor(_hostname, timezoneOffset = 0 - (new Date()).getTimezoneOffset(), verify = true) {
|
|
12
|
+
constructor(_hostname, timezoneOffset = (moment) => 0 - (new Date()).getTimezoneOffset(), verify = true) {
|
|
13
13
|
if (!(/^https?:\/\//).test(_hostname))
|
|
14
14
|
throw "hostname MUST begin with either http:// or https://";
|
|
15
15
|
this.hostname = _hostname;
|
|
16
|
-
this.
|
|
16
|
+
this.timezoneOffsetFunc = timezoneOffset;
|
|
17
17
|
this.verify = verify;
|
|
18
18
|
}
|
|
19
19
|
get metadata() {
|
|
@@ -22,12 +22,23 @@ export default class FMHost {
|
|
|
22
22
|
buildDate: new Date(),
|
|
23
23
|
name: "",
|
|
24
24
|
version: "",
|
|
25
|
-
dateFormat: "",
|
|
26
|
-
timeFormat: "",
|
|
27
|
-
timeStampFormat: ""
|
|
25
|
+
dateFormat: "MM/dd/yyyy",
|
|
26
|
+
timeFormat: "HH:mm:ss",
|
|
27
|
+
timeStampFormat: "MM/dd/yyyy HH:mm:ss"
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
+
get dateFormat() {
|
|
32
|
+
return this.metadata.productInfo.dateFormat
|
|
33
|
+
.replace("dd", "DD")
|
|
34
|
+
.replace("yyyy", "YYYY");
|
|
35
|
+
}
|
|
36
|
+
get timeFormat() { return this.metadata.productInfo.timeFormat; }
|
|
37
|
+
get timeStampFormat() {
|
|
38
|
+
return this.metadata.productInfo.timeStampFormat
|
|
39
|
+
.replace("dd", "DD")
|
|
40
|
+
.replace("yyyy", "YYYY");
|
|
41
|
+
}
|
|
31
42
|
async listDatabases(credentials) {
|
|
32
43
|
let headers = {};
|
|
33
44
|
if (credentials) {
|
package/src/connection/FMHost.ts
CHANGED
|
@@ -15,17 +15,22 @@ import {
|
|
|
15
15
|
} from "../types.js";
|
|
16
16
|
import {ApiResults} from "../models/apiResults.js";
|
|
17
17
|
import {DatabaseStructure} from "../databaseStructure.js";
|
|
18
|
+
import {Moment} from "moment";
|
|
18
19
|
|
|
19
20
|
export default class FMHost implements HostBase {
|
|
20
21
|
readonly hostname: string
|
|
21
|
-
readonly
|
|
22
|
+
readonly timezoneOffsetFunc: (moment: Moment) => number
|
|
22
23
|
readonly verify: boolean
|
|
23
24
|
_metadata: FMHostMetadata | null = null
|
|
24
25
|
|
|
25
|
-
constructor(
|
|
26
|
+
constructor(
|
|
27
|
+
_hostname: string,
|
|
28
|
+
timezoneOffset = (moment: Moment) => 0 - (new Date()).getTimezoneOffset(),
|
|
29
|
+
verify = true
|
|
30
|
+
) {
|
|
26
31
|
if (!(/^https?:\/\//).test(_hostname)) throw "hostname MUST begin with either http:// or https://"
|
|
27
32
|
this.hostname = _hostname
|
|
28
|
-
this.
|
|
33
|
+
this.timezoneOffsetFunc = timezoneOffset
|
|
29
34
|
this.verify = verify
|
|
30
35
|
}
|
|
31
36
|
|
|
@@ -35,13 +40,26 @@ export default class FMHost implements HostBase {
|
|
|
35
40
|
buildDate: new Date(),
|
|
36
41
|
name: "",
|
|
37
42
|
version: "",
|
|
38
|
-
dateFormat: "",
|
|
39
|
-
timeFormat: "",
|
|
40
|
-
timeStampFormat: ""
|
|
43
|
+
dateFormat: "MM/dd/yyyy",
|
|
44
|
+
timeFormat: "HH:mm:ss",
|
|
45
|
+
timeStampFormat: "MM/dd/yyyy HH:mm:ss"
|
|
41
46
|
}
|
|
42
47
|
};
|
|
43
48
|
}
|
|
44
49
|
|
|
50
|
+
get dateFormat() {
|
|
51
|
+
return this.metadata.productInfo.dateFormat
|
|
52
|
+
.replace("dd", "DD")
|
|
53
|
+
.replace("yyyy", "YYYY")
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
get timeFormat() {return this.metadata.productInfo.timeFormat}
|
|
57
|
+
get timeStampFormat() {
|
|
58
|
+
return this.metadata.productInfo.timeStampFormat
|
|
59
|
+
.replace("dd", "DD")
|
|
60
|
+
.replace("yyyy", "YYYY")
|
|
61
|
+
}
|
|
62
|
+
|
|
45
63
|
async listDatabases(credentials?: loginOptionsOAuth | loginOptionsFileMaker | loginOptionsClaris) {
|
|
46
64
|
let headers = {}
|
|
47
65
|
if (credentials) {
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { FMHostMetadata } from "../types.js";
|
|
2
|
+
import { Moment } from "moment";
|
|
2
3
|
export interface HostBase {
|
|
3
4
|
readonly hostname: string;
|
|
4
|
-
readonly
|
|
5
|
+
readonly timezoneOffsetFunc: (moment: Moment) => number;
|
|
5
6
|
readonly verify: boolean;
|
|
6
7
|
metadata: FMHostMetadata;
|
|
7
8
|
getMetadata(): PromiseLike<any>;
|
|
9
|
+
timeFormat: string;
|
|
10
|
+
dateFormat: string;
|
|
11
|
+
timeStampFormat: string;
|
|
8
12
|
}
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import {FMHostMetadata} from "../types.js";
|
|
6
|
+
import {Moment} from "moment";
|
|
6
7
|
|
|
7
8
|
export interface HostBase {
|
|
8
9
|
readonly hostname: string
|
|
9
|
-
readonly
|
|
10
|
+
readonly timezoneOffsetFunc: (moment: Moment) => number,
|
|
10
11
|
readonly verify: boolean
|
|
11
12
|
metadata: FMHostMetadata
|
|
12
13
|
getMetadata(): PromiseLike<any>
|
|
14
|
+
timeFormat: string
|
|
15
|
+
dateFormat: string
|
|
16
|
+
timeStampFormat: string
|
|
13
17
|
}
|
package/src/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { Portal } from "./records/portal.js";
|
|
|
12
12
|
import { FindRequest, FindRequestRaw, RecordGetOperation } from "./records/getOperations/recordGetOperation.js";
|
|
13
13
|
import { LayoutRecordManager } from "./layouts/layoutRecordManager.js";
|
|
14
14
|
import { RecordFieldsMap } from "./layouts/recordFieldsMap.js";
|
|
15
|
-
import { query, queryEscape } from "./utils/query.js";
|
|
15
|
+
import { asDate, asTime, asTimestamp, query, queryEscape } from "./utils/query.js";
|
|
16
16
|
import { Container, Field } from "./records/field.js";
|
|
17
17
|
export default FMHost;
|
|
18
|
-
export { FMError, TYPES, Database, Layout, RecordBase, LayoutRecord, LayoutInterface, RecordFieldsMap, PortalInterface, PortalRecord, Portal, Field, RecordGetOperation, LayoutRecordManager, Container, PickPortals, FindRequestRaw, FindRequest, query, queryEscape };
|
|
18
|
+
export { FMError, TYPES, Database, Layout, RecordBase, LayoutRecord, LayoutInterface, RecordFieldsMap, PortalInterface, PortalRecord, Portal, Field, RecordGetOperation, LayoutRecordManager, Container, PickPortals, FindRequestRaw, FindRequest, query, queryEscape, asDate, asTime, asTimestamp };
|
package/src/index.js
CHANGED
|
@@ -12,7 +12,7 @@ import { PortalRecord } from "./records/portalRecord.js";
|
|
|
12
12
|
import { Portal } from "./records/portal.js";
|
|
13
13
|
import { RecordGetOperation } from "./records/getOperations/recordGetOperation.js";
|
|
14
14
|
import { LayoutRecordManager } from "./layouts/layoutRecordManager.js";
|
|
15
|
-
import { query, queryEscape } from "./utils/query.js";
|
|
15
|
+
import { asDate, asTime, asTimestamp, query, queryEscape } from "./utils/query.js";
|
|
16
16
|
import { Field } from "./records/field.js";
|
|
17
17
|
export default FMHost;
|
|
18
|
-
export { FMError, TYPES, Database, Layout, RecordBase, LayoutRecord, PortalRecord, Portal, Field, RecordGetOperation, LayoutRecordManager, query, queryEscape };
|
|
18
|
+
export { FMError, TYPES, Database, Layout, RecordBase, LayoutRecord, PortalRecord, Portal, Field, RecordGetOperation, LayoutRecordManager, query, queryEscape, asDate, asTime, asTimestamp };
|
package/src/index.ts
CHANGED
|
@@ -16,7 +16,7 @@ import {Portal} from "./records/portal.js";
|
|
|
16
16
|
import {FindRequest, FindRequestRaw, RecordGetOperation} from "./records/getOperations/recordGetOperation.js";
|
|
17
17
|
import {LayoutRecordManager} from "./layouts/layoutRecordManager.js";
|
|
18
18
|
import {RecordFieldsMap} from "./layouts/recordFieldsMap.js";
|
|
19
|
-
import {query, queryEscape} from "./utils/query.js";
|
|
19
|
+
import {asDate, asTime, asTimestamp, query, queryEscape} from "./utils/query.js";
|
|
20
20
|
import {Container, Field} from "./records/field.js";
|
|
21
21
|
|
|
22
22
|
export default FMHost
|
|
@@ -40,5 +40,8 @@ export {
|
|
|
40
40
|
FindRequestRaw,
|
|
41
41
|
FindRequest,
|
|
42
42
|
query,
|
|
43
|
-
queryEscape
|
|
43
|
+
queryEscape,
|
|
44
|
+
asDate,
|
|
45
|
+
asTime,
|
|
46
|
+
asTimestamp
|
|
44
47
|
}
|
|
@@ -112,9 +112,14 @@ export class RecordGetOperation {
|
|
|
112
112
|
return item;
|
|
113
113
|
// Re-write date into correct format
|
|
114
114
|
return item
|
|
115
|
+
.moment
|
|
115
116
|
.clone()
|
|
116
|
-
.utcOffset(this.layout.database.host.
|
|
117
|
-
.format("
|
|
117
|
+
.utcOffset(this.layout.database.host.timezoneOffsetFunc(item.moment))
|
|
118
|
+
.format(item.type === "date" ?
|
|
119
|
+
this.layout.database.host.dateFormat :
|
|
120
|
+
item.type == "time" ?
|
|
121
|
+
this.layout.database.host.timeFormat :
|
|
122
|
+
this.layout.database.host.timeStampFormat);
|
|
118
123
|
}).join("");
|
|
119
124
|
}
|
|
120
125
|
return out;
|
|
@@ -41,7 +41,7 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
|
|
|
41
41
|
protected sortData: { fieldName: string, sortOrder: SortOrder }[] = []
|
|
42
42
|
protected portals: Partial<PortalData<T>>
|
|
43
43
|
protected offset: number = 1
|
|
44
|
-
protected queries: {req: FindRequestRaw, omit: boolean}[] = []
|
|
44
|
+
protected queries: { req: FindRequestRaw, omit: boolean }[] = []
|
|
45
45
|
|
|
46
46
|
constructor(layout: LayoutBase, options: OPTIONS) {
|
|
47
47
|
this.layout = layout
|
|
@@ -60,7 +60,9 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
|
|
|
60
60
|
let out: any = {}
|
|
61
61
|
for (let key of Object.keys(query.req)) {
|
|
62
62
|
if (query.req[key]) out[key] = query.req[key]
|
|
63
|
-
else {
|
|
63
|
+
else {
|
|
64
|
+
out[key] = query.req[key]
|
|
65
|
+
}
|
|
64
66
|
}
|
|
65
67
|
if (query.omit) out.omit = "true"
|
|
66
68
|
return out
|
|
@@ -69,7 +71,7 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
|
|
|
69
71
|
}
|
|
70
72
|
|
|
71
73
|
protected generateParamsBody(offset: number, limit: number) {
|
|
72
|
-
const params: {[key: string]: any} = {
|
|
74
|
+
const params: { [key: string]: any } = {
|
|
73
75
|
limit: limit.toString(),
|
|
74
76
|
offset: offset.toString(),
|
|
75
77
|
dateformats: 2 // Ensure dates are received in ISO8601 format
|
|
@@ -97,6 +99,7 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
|
|
|
97
99
|
|
|
98
100
|
return params
|
|
99
101
|
}
|
|
102
|
+
|
|
100
103
|
protected generateParamsURL(offset: number, limit: number) {
|
|
101
104
|
const params = new URLSearchParams({
|
|
102
105
|
_limit: limit.toString(),
|
|
@@ -134,7 +137,7 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
|
|
|
134
137
|
return this
|
|
135
138
|
}
|
|
136
139
|
|
|
137
|
-
private parseFindRequest<I extends FindRequest>(query: I): {[key in keyof I]: string} {
|
|
140
|
+
private parseFindRequest<I extends FindRequest>(query: I): { [key in keyof I]: string } {
|
|
138
141
|
let out: any = {}
|
|
139
142
|
for (let key of Object.keys(query)) {
|
|
140
143
|
out[key] = query[key][FindRequestSymbol].map(item => {
|
|
@@ -142,9 +145,16 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
|
|
|
142
145
|
|
|
143
146
|
// Re-write date into correct format
|
|
144
147
|
return item
|
|
148
|
+
.moment
|
|
145
149
|
.clone()
|
|
146
|
-
.utcOffset(this.layout.database.host.
|
|
147
|
-
.format(
|
|
150
|
+
.utcOffset(this.layout.database.host.timezoneOffsetFunc(item.moment))
|
|
151
|
+
.format(
|
|
152
|
+
item.type === "date" ?
|
|
153
|
+
this.layout.database.host.dateFormat :
|
|
154
|
+
item.type == "time" ?
|
|
155
|
+
this.layout.database.host.timeFormat :
|
|
156
|
+
this.layout.database.host.timeStampFormat
|
|
157
|
+
)
|
|
148
158
|
}).join("")
|
|
149
159
|
}
|
|
150
160
|
return out
|
|
@@ -189,7 +199,7 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
|
|
|
189
199
|
else {
|
|
190
200
|
throw new FMError(res.messages[0].code, res.httpStatus, res, trace)
|
|
191
201
|
}
|
|
192
|
-
} catch(e) {
|
|
202
|
+
} catch (e) {
|
|
193
203
|
if (e instanceof FMError) {
|
|
194
204
|
if (e.code === 401) {
|
|
195
205
|
// No records found, so return empty set
|
|
@@ -160,18 +160,19 @@ export class LayoutRecord extends RecordBase {
|
|
|
160
160
|
let value = field.value;
|
|
161
161
|
if (value instanceof Date) {
|
|
162
162
|
// @ts-ignore
|
|
163
|
-
let _value = moment.default(value)
|
|
164
|
-
|
|
163
|
+
let _value = moment.default(value);
|
|
164
|
+
_value = _value
|
|
165
|
+
.utcOffset(this.layout.database.host.timezoneOffsetFunc(_value));
|
|
165
166
|
// @ts-ignore
|
|
166
167
|
switch (field.metadata.result) {
|
|
167
168
|
case "time":
|
|
168
|
-
value = _value.format(this.layout.database.host.
|
|
169
|
+
value = _value.format(this.layout.database.host.timeFormat);
|
|
169
170
|
break;
|
|
170
171
|
case "date":
|
|
171
|
-
value = _value.format(this.layout.database.host.
|
|
172
|
+
value = _value.format(this.layout.database.host.dateFormat);
|
|
172
173
|
break;
|
|
173
174
|
default:
|
|
174
|
-
value = _value.format(this.layout.database.host.
|
|
175
|
+
value = _value.format(this.layout.database.host.timeStampFormat);
|
|
175
176
|
}
|
|
176
177
|
}
|
|
177
178
|
fields_processed[field.id] = value;
|
|
@@ -190,19 +190,20 @@ export class LayoutRecord<LAYOUT extends LayoutInterface> extends RecordBase<LAY
|
|
|
190
190
|
if (value instanceof Date) {
|
|
191
191
|
// @ts-ignore
|
|
192
192
|
let _value = moment.default(value)
|
|
193
|
-
|
|
193
|
+
_value = _value
|
|
194
|
+
.utcOffset(this.layout.database.host.timezoneOffsetFunc(_value))
|
|
194
195
|
|
|
195
196
|
// @ts-ignore
|
|
196
197
|
|
|
197
198
|
switch (field.metadata.result) {
|
|
198
199
|
case "time":
|
|
199
|
-
value = _value.format(this.layout.database.host.
|
|
200
|
+
value = _value.format(this.layout.database.host.timeFormat)
|
|
200
201
|
break
|
|
201
202
|
case "date":
|
|
202
|
-
value = _value.format(this.layout.database.host.
|
|
203
|
+
value = _value.format(this.layout.database.host.dateFormat)
|
|
203
204
|
break
|
|
204
205
|
default:
|
|
205
|
-
value = _value.format(this.layout.database.host.
|
|
206
|
+
value = _value.format(this.layout.database.host.timeStampFormat)
|
|
206
207
|
}
|
|
207
208
|
}
|
|
208
209
|
fields_processed[field.id] = value
|
|
@@ -35,24 +35,27 @@ export class RecordBase extends EventEmitter {
|
|
|
35
35
|
if (!!fieldData[key]) {
|
|
36
36
|
if (_field.metadata.result === "timeStamp") {
|
|
37
37
|
// @ts-ignore
|
|
38
|
-
let date = moment.default(fieldData[key]
|
|
39
|
-
|
|
38
|
+
let date = moment.default(fieldData[key]);
|
|
39
|
+
date = date
|
|
40
|
+
.utcOffset(this.layout.database.host.timezoneOffsetFunc(date), true)
|
|
40
41
|
.local();
|
|
41
42
|
_field.set(date);
|
|
42
43
|
_field.edited = false;
|
|
43
44
|
}
|
|
44
45
|
else if (_field.metadata.result === "time") {
|
|
45
46
|
// @ts-ignore
|
|
46
|
-
let date = moment.default(fieldData[key]
|
|
47
|
-
|
|
47
|
+
let date = moment.default(fieldData[key]);
|
|
48
|
+
date = date
|
|
49
|
+
.utcOffset(this.layout.database.host.timezoneOffsetFunc(date), true)
|
|
48
50
|
.local();
|
|
49
51
|
_field.set(date);
|
|
50
52
|
_field.edited = false;
|
|
51
53
|
}
|
|
52
54
|
else if (_field.metadata.result === "date") {
|
|
53
55
|
// @ts-ignore
|
|
54
|
-
let date = moment.default(fieldData[key]
|
|
55
|
-
|
|
56
|
+
let date = moment.default(fieldData[key]);
|
|
57
|
+
date = date
|
|
58
|
+
.utcOffset(this.layout.database.host.timezoneOffsetFunc(date), true)
|
|
56
59
|
.local();
|
|
57
60
|
_field.set(date);
|
|
58
61
|
_field.edited = false;
|
|
@@ -47,8 +47,9 @@ export abstract class RecordBase<T extends RecordFieldsMap> extends EventEmitter
|
|
|
47
47
|
if (!!fieldData[key]) {
|
|
48
48
|
if (_field.metadata.result === "timeStamp") {
|
|
49
49
|
// @ts-ignore
|
|
50
|
-
let date = moment.default(fieldData[key]
|
|
51
|
-
|
|
50
|
+
let date = moment.default(fieldData[key])
|
|
51
|
+
date = date
|
|
52
|
+
.utcOffset(this.layout.database.host.timezoneOffsetFunc(date), true)
|
|
52
53
|
.local()
|
|
53
54
|
_field.set(date)
|
|
54
55
|
_field.edited = false
|
|
@@ -56,16 +57,18 @@ export abstract class RecordBase<T extends RecordFieldsMap> extends EventEmitter
|
|
|
56
57
|
}
|
|
57
58
|
else if (_field.metadata.result === "time") {
|
|
58
59
|
// @ts-ignore
|
|
59
|
-
let date = moment.default(fieldData[key]
|
|
60
|
-
|
|
60
|
+
let date = moment.default(fieldData[key])
|
|
61
|
+
date = date
|
|
62
|
+
.utcOffset(this.layout.database.host.timezoneOffsetFunc(date), true)
|
|
61
63
|
.local()
|
|
62
64
|
_field.set(date)
|
|
63
65
|
_field.edited = false
|
|
64
66
|
}
|
|
65
67
|
else if (_field.metadata.result === "date") {
|
|
66
68
|
// @ts-ignore
|
|
67
|
-
let date = moment.default(fieldData[key]
|
|
68
|
-
|
|
69
|
+
let date = moment.default(fieldData[key])
|
|
70
|
+
date = date
|
|
71
|
+
.utcOffset(this.layout.database.host.timezoneOffsetFunc(date), true)
|
|
69
72
|
.local()
|
|
70
73
|
_field.set(date)
|
|
71
74
|
_field.edited = false
|
package/src/utils/query.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { Moment } from "moment";
|
|
2
2
|
export declare const FindRequestSymbol: unique symbol;
|
|
3
|
-
type
|
|
3
|
+
export type TimestampType = {
|
|
4
|
+
type: "date" | "time" | "timestamp";
|
|
5
|
+
moment: Moment;
|
|
6
|
+
};
|
|
7
|
+
type QueryParameter = string | number | TimestampType;
|
|
4
8
|
export type Query = {
|
|
5
|
-
[FindRequestSymbol]: (string |
|
|
9
|
+
[FindRequestSymbol]: (string | TimestampType)[];
|
|
6
10
|
};
|
|
7
11
|
export declare function queryEscape(str: string): string;
|
|
8
12
|
export declare function query(strings: TemplateStringsArray, ...args: QueryParameter[]): Query;
|
|
13
|
+
export declare function asDate(date: Date | Moment): TimestampType;
|
|
14
|
+
export declare function asTime(date: Date | Moment): TimestampType;
|
|
15
|
+
export declare function asTimestamp(date: Date | Moment): TimestampType;
|
|
9
16
|
export {};
|
package/src/utils/query.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Copyright (c) 2024. See LICENSE file for more information
|
|
3
3
|
*/
|
|
4
|
-
import moment from "moment
|
|
4
|
+
import moment from "moment";
|
|
5
5
|
export const FindRequestSymbol = Symbol("easyfm-findrequest");
|
|
6
6
|
const SPECIAL_CHARACTERS = ["\\", "=", "<", "≤", "≥", ">", "…", "...", "//", "@", "#", "*", "\"", "~"];
|
|
7
7
|
export function queryEscape(str) {
|
|
@@ -12,13 +12,13 @@ export function queryEscape(str) {
|
|
|
12
12
|
}
|
|
13
13
|
export function query(strings, ...args) {
|
|
14
14
|
let argStrings = args.map(item => {
|
|
15
|
-
if (
|
|
16
|
-
return item;
|
|
17
|
-
else if (typeof item === "number") {
|
|
15
|
+
if (typeof item === "number") {
|
|
18
16
|
return queryEscape(item.toString());
|
|
19
17
|
}
|
|
20
|
-
else
|
|
18
|
+
else if (typeof item === "string")
|
|
21
19
|
return queryEscape(item);
|
|
20
|
+
else
|
|
21
|
+
return item;
|
|
22
22
|
});
|
|
23
23
|
// Zip the parameters together
|
|
24
24
|
const query = strings.map((str, index) => {
|
|
@@ -26,3 +26,22 @@ export function query(strings, ...args) {
|
|
|
26
26
|
}).flat(1);
|
|
27
27
|
return { [FindRequestSymbol]: query };
|
|
28
28
|
}
|
|
29
|
+
export function asDate(date) {
|
|
30
|
+
return {
|
|
31
|
+
type: "date",
|
|
32
|
+
moment: moment(date)
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
export function asTime(date) {
|
|
36
|
+
return {
|
|
37
|
+
type: "time",
|
|
38
|
+
moment: moment(date)
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export function asTimestamp(date) {
|
|
42
|
+
return {
|
|
43
|
+
type: "timestamp",
|
|
44
|
+
moment: moment(date)
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
query;
|
package/src/utils/query.ts
CHANGED
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
* Copyright (c) 2024. See LICENSE file for more information
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import {Moment} from "moment";
|
|
6
|
-
import moment from "moment/moment.js";
|
|
5
|
+
import moment, {Moment} from "moment";
|
|
7
6
|
|
|
8
7
|
export const FindRequestSymbol = Symbol("easyfm-findrequest");
|
|
9
8
|
const SPECIAL_CHARACTERS = ["\\", "=", "<", "≤", "≥", ">", "…", "...", "//", "@", "#", "*", "\"", "~"]
|
|
10
|
-
type
|
|
11
|
-
|
|
9
|
+
export type TimestampType = {
|
|
10
|
+
type: "date" | "time" | "timestamp",
|
|
11
|
+
moment: Moment
|
|
12
|
+
}
|
|
13
|
+
type QueryParameter = string | number | TimestampType
|
|
14
|
+
export type Query = {[FindRequestSymbol]: (string | TimestampType)[]}
|
|
12
15
|
|
|
13
16
|
export function queryEscape(str: string) {
|
|
14
17
|
for (let char of SPECIAL_CHARACTERS) {
|
|
@@ -19,11 +22,11 @@ export function queryEscape(str: string) {
|
|
|
19
22
|
|
|
20
23
|
export function query(strings: TemplateStringsArray, ...args: QueryParameter[]): Query {
|
|
21
24
|
let argStrings = args.map(item => {
|
|
22
|
-
if (
|
|
23
|
-
else if (typeof item === "number") {
|
|
25
|
+
if (typeof item === "number") {
|
|
24
26
|
return queryEscape(item.toString())
|
|
25
27
|
}
|
|
26
|
-
else return queryEscape(item)
|
|
28
|
+
else if (typeof item === "string") return queryEscape(item)
|
|
29
|
+
else return item
|
|
27
30
|
})
|
|
28
31
|
|
|
29
32
|
// Zip the parameters together
|
|
@@ -31,4 +34,27 @@ export function query(strings: TemplateStringsArray, ...args: QueryParameter[]):
|
|
|
31
34
|
return [str, (argStrings[index] || '')]
|
|
32
35
|
}).flat(1)
|
|
33
36
|
return {[FindRequestSymbol]: query}
|
|
34
|
-
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function asDate(date: Date | Moment): TimestampType {
|
|
40
|
+
return {
|
|
41
|
+
type: "date",
|
|
42
|
+
moment: moment(date)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function asTime(date: Date | Moment): TimestampType {
|
|
47
|
+
return {
|
|
48
|
+
type: "time",
|
|
49
|
+
moment: moment(date)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function asTimestamp(date: Date | Moment): TimestampType {
|
|
54
|
+
return {
|
|
55
|
+
type: "timestamp",
|
|
56
|
+
moment: moment(date)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
query
|