@rushdb/javascript-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/README.md +119 -0
- package/cjs/api/api.js +328 -0
- package/cjs/api/constants.js +7 -0
- package/cjs/api/create-api.js +258 -0
- package/cjs/api/index.js +8 -0
- package/cjs/api/rest-api-proxy.js +22 -0
- package/cjs/api/types.js +2 -0
- package/cjs/api/utils.js +154 -0
- package/cjs/common/constants.js +10 -0
- package/cjs/common/utils.js +46 -0
- package/cjs/index.cjs.node.js +24 -0
- package/cjs/index.cjs.worker.js +24 -0
- package/cjs/network/FetchHttpClient.js +138 -0
- package/cjs/network/HttpClient.js +59 -0
- package/cjs/network/NodeHttpClient.js +103 -0
- package/cjs/network/index.js +28 -0
- package/cjs/network/types.js +2 -0
- package/cjs/package.json +4 -0
- package/cjs/sdk/constants.js +12 -0
- package/cjs/sdk/errors.js +27 -0
- package/cjs/sdk/index.js +23 -0
- package/cjs/sdk/model.js +147 -0
- package/cjs/sdk/record.js +77 -0
- package/cjs/sdk/sdk.js +46 -0
- package/cjs/sdk/transaction.js +17 -0
- package/cjs/sdk/types.js +2 -0
- package/cjs/sdk/utils.js +103 -0
- package/cjs/types/expressions.js +2 -0
- package/cjs/types/index.js +21 -0
- package/cjs/types/query.js +2 -0
- package/cjs/types/schema.js +2 -0
- package/cjs/types/utils.js +2 -0
- package/cjs/types/value.js +2 -0
- package/esm/api/api.js +324 -0
- package/esm/api/constants.js +4 -0
- package/esm/api/create-api.js +254 -0
- package/esm/api/index.js +2 -0
- package/esm/api/rest-api-proxy.js +18 -0
- package/esm/api/types.js +1 -0
- package/esm/api/utils.js +138 -0
- package/esm/common/constants.js +7 -0
- package/esm/common/utils.js +37 -0
- package/esm/index.esm.node.js +6 -0
- package/esm/index.esm.worker.js +6 -0
- package/esm/network/FetchHttpClient.js +133 -0
- package/esm/network/HttpClient.js +53 -0
- package/esm/network/NodeHttpClient.js +98 -0
- package/esm/network/index.js +24 -0
- package/esm/network/types.js +1 -0
- package/esm/package.json +4 -0
- package/esm/sdk/constants.js +9 -0
- package/esm/sdk/errors.js +21 -0
- package/esm/sdk/index.js +7 -0
- package/esm/sdk/model.js +143 -0
- package/esm/sdk/record.js +70 -0
- package/esm/sdk/sdk.js +42 -0
- package/esm/sdk/transaction.js +13 -0
- package/esm/sdk/types.js +1 -0
- package/esm/sdk/utils.js +93 -0
- package/esm/types/expressions.js +1 -0
- package/esm/types/index.js +5 -0
- package/esm/types/query.js +1 -0
- package/esm/types/schema.js +1 -0
- package/esm/types/utils.js +1 -0
- package/esm/types/value.js +1 -0
- package/package.json +59 -0
- package/types/api/api.d.ts +43 -0
- package/types/api/constants.d.ts +4 -0
- package/types/api/create-api.d.ts +67 -0
- package/types/api/index.d.ts +3 -0
- package/types/api/rest-api-proxy.d.ts +6 -0
- package/types/api/types.d.ts +65 -0
- package/types/api/utils.d.ts +43 -0
- package/types/common/constants.d.ts +7 -0
- package/types/common/utils.d.ts +7 -0
- package/types/index.d.ts +72 -0
- package/types/network/FetchHttpClient.d.ts +26 -0
- package/types/network/HttpClient.d.ts +48 -0
- package/types/network/NodeHttpClient.d.ts +16 -0
- package/types/network/index.d.ts +6 -0
- package/types/network/types.d.ts +4 -0
- package/types/sdk/constants.d.ts +1 -0
- package/types/sdk/errors.d.ts +9 -0
- package/types/sdk/index.d.ts +7 -0
- package/types/sdk/model.d.ts +72 -0
- package/types/sdk/record.d.ts +109 -0
- package/types/sdk/sdk.d.ts +136 -0
- package/types/sdk/transaction.d.ts +11 -0
- package/types/sdk/types.d.ts +19 -0
- package/types/sdk/utils.d.ts +9 -0
- package/types/types/expressions.d.ts +23 -0
- package/types/types/index.d.ts +5 -0
- package/types/types/query.d.ts +102 -0
- package/types/types/schema.d.ts +48 -0
- package/types/types/utils.d.ts +9 -0
- package/types/types/value.d.ts +35 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FetchHttpClientResponse = exports.FetchHttpClient = void 0;
|
|
4
|
+
const constants_js_1 = require("../common/constants.js");
|
|
5
|
+
const HttpClient_js_1 = require("./HttpClient.js");
|
|
6
|
+
/**
|
|
7
|
+
* HTTP client which uses a `fetch` function to issue requests.
|
|
8
|
+
*
|
|
9
|
+
* By default, relies on the global `fetch` function, but an optional function
|
|
10
|
+
* can be passed in. If passing in a function, it is expected to match the Web
|
|
11
|
+
* Fetch API. As an example, this could be the function provided by the
|
|
12
|
+
* node-fetch package (https://github.com/node-fetch/node-fetch).
|
|
13
|
+
*/
|
|
14
|
+
class FetchHttpClient extends HttpClient_js_1.HttpClient {
|
|
15
|
+
constructor(fetchFn) {
|
|
16
|
+
super();
|
|
17
|
+
// Default to global fetch if available
|
|
18
|
+
if (!fetchFn) {
|
|
19
|
+
if (!globalThis.fetch) {
|
|
20
|
+
throw new Error('fetch() function not provided and is not defined in the global scope. ' +
|
|
21
|
+
'You must provide a fetch implementation.');
|
|
22
|
+
}
|
|
23
|
+
fetchFn = globalThis.fetch;
|
|
24
|
+
}
|
|
25
|
+
// Both timeout behaviors differs from Node:
|
|
26
|
+
// - Fetch uses a single timeout for the entire length of the request.
|
|
27
|
+
// - Node is more fine-grained and resets the timeout after each stage of the request.
|
|
28
|
+
if (globalThis.AbortController) {
|
|
29
|
+
// Utilise native AbortController if available
|
|
30
|
+
// AbortController was added in Node v15.0.0, v14.17.0
|
|
31
|
+
this._fetchFn = FetchHttpClient.makeFetchWithAbortTimeout(fetchFn);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
// Fall back to racing against a timeout promise if not available in the runtime
|
|
35
|
+
// This does not actually cancel the underlying fetch operation or resources
|
|
36
|
+
this._fetchFn = FetchHttpClient.makeFetchWithRaceTimeout(fetchFn);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
static makeFetchWithRaceTimeout(fetchFn) {
|
|
40
|
+
return (url, init, timeout) => {
|
|
41
|
+
let pendingTimeoutId;
|
|
42
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
43
|
+
pendingTimeoutId = setTimeout(() => {
|
|
44
|
+
pendingTimeoutId = null;
|
|
45
|
+
reject(HttpClient_js_1.HttpClient.makeTimeoutError());
|
|
46
|
+
}, timeout);
|
|
47
|
+
});
|
|
48
|
+
const fetchPromise = fetchFn(url, init);
|
|
49
|
+
return Promise.race([fetchPromise, timeoutPromise]).finally(() => {
|
|
50
|
+
if (pendingTimeoutId) {
|
|
51
|
+
clearTimeout(pendingTimeoutId);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
static makeFetchWithAbortTimeout(fetchFn) {
|
|
57
|
+
return async (url, init, timeout) => {
|
|
58
|
+
// Use AbortController because AbortSignal.timeout() was added later in Node v17.3.0, v16.14.0
|
|
59
|
+
const abort = new AbortController();
|
|
60
|
+
let timeoutId = setTimeout(() => {
|
|
61
|
+
timeoutId = null;
|
|
62
|
+
abort.abort(HttpClient_js_1.HttpClient.makeTimeoutError());
|
|
63
|
+
}, timeout);
|
|
64
|
+
try {
|
|
65
|
+
return await fetchFn(url, Object.assign(Object.assign({}, init), { signal: abort.signal }));
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
// Some implementations, like node-fetch, do not respect the reason passed to AbortController.abort()
|
|
69
|
+
// and instead it always throws an AbortError
|
|
70
|
+
// We catch this case to normalise all timeout errors
|
|
71
|
+
if (err.name === 'AbortError') {
|
|
72
|
+
throw HttpClient_js_1.HttpClient.makeTimeoutError();
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
if (timeoutId) {
|
|
80
|
+
clearTimeout(timeoutId);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
async makeRequest(url, { headers, method, protocol, requestData, timeout }) {
|
|
86
|
+
// For methods which expect payloads, we should always pass a body value
|
|
87
|
+
// even when it is empty. Without this, some JS runtimes (eg. Deno) will
|
|
88
|
+
// inject a second Content-Length header.
|
|
89
|
+
const methodHasPayload = method == 'POST' || method == 'PUT' || method == 'PATCH';
|
|
90
|
+
const body = JSON.stringify(requestData) || (methodHasPayload ? '' : undefined);
|
|
91
|
+
const res = await this._fetchFn(url, {
|
|
92
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
93
|
+
// @ts-ignore
|
|
94
|
+
body,
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
headers,
|
|
98
|
+
method
|
|
99
|
+
}, timeout !== null && timeout !== void 0 ? timeout : constants_js_1.DEFAULT_TIMEOUT);
|
|
100
|
+
return new FetchHttpClientResponse(res);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.FetchHttpClient = FetchHttpClient;
|
|
104
|
+
class FetchHttpClientResponse extends HttpClient_js_1.HttpClientGenericResponse {
|
|
105
|
+
constructor(res) {
|
|
106
|
+
super(res.status, FetchHttpClientResponse._transformHeadersToObject(res.headers));
|
|
107
|
+
this._res = res;
|
|
108
|
+
}
|
|
109
|
+
getRawResponse() {
|
|
110
|
+
return this._res;
|
|
111
|
+
}
|
|
112
|
+
toStream(streamCompleteCallback) {
|
|
113
|
+
// Unfortunately `fetch` does not have event handlers for when the stream is
|
|
114
|
+
// completely read. We therefore invoke the streamCompleteCallback right
|
|
115
|
+
// away. This callback emits a response event with metadata and completes
|
|
116
|
+
// metrics, so it's ok to do this without waiting for the stream to be
|
|
117
|
+
// completely read.
|
|
118
|
+
streamCompleteCallback();
|
|
119
|
+
// Fetch's `body` property is expected to be a readable stream of the body.
|
|
120
|
+
return this._res.body;
|
|
121
|
+
}
|
|
122
|
+
toJSON() {
|
|
123
|
+
return this._res.json();
|
|
124
|
+
}
|
|
125
|
+
static _transformHeadersToObject(headers) {
|
|
126
|
+
// Fetch uses a Headers instance so this must be converted to a barebones
|
|
127
|
+
// JS object to meet the HttpClient interface.
|
|
128
|
+
const headersObj = {};
|
|
129
|
+
for (const entry of headers) {
|
|
130
|
+
if (!Array.isArray(entry) || entry.length != 2) {
|
|
131
|
+
throw new Error('Response objects produced by the fetch function given to FetchHttpClient do not have an iterable headers map. Response#headers should be an iterable object.');
|
|
132
|
+
}
|
|
133
|
+
headersObj[entry[0]] = entry[1];
|
|
134
|
+
}
|
|
135
|
+
return headersObj;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
exports.FetchHttpClientResponse = FetchHttpClientResponse;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HttpClientResponse = exports.HttpClientGenericResponse = exports.HttpClient = void 0;
|
|
4
|
+
class HttpClient {
|
|
5
|
+
makeRequest(url, { headers, method, protocol, requestData, timeout }) {
|
|
6
|
+
throw new Error('makeRequest not implemented.');
|
|
7
|
+
}
|
|
8
|
+
static makeTimeoutError() {
|
|
9
|
+
const timeoutErr = new TypeError(HttpClient.TIMEOUT_ERROR_CODE);
|
|
10
|
+
timeoutErr.code = HttpClient.TIMEOUT_ERROR_CODE;
|
|
11
|
+
return timeoutErr;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.HttpClient = HttpClient;
|
|
15
|
+
HttpClient.CONNECTION_CLOSED_ERROR_CODES = ['ECONNRESET', 'EPIPE'];
|
|
16
|
+
HttpClient.TIMEOUT_ERROR_CODE = 'ETIMEDOUT';
|
|
17
|
+
class HttpClientGenericResponse {
|
|
18
|
+
constructor(statusCode, headers) {
|
|
19
|
+
this._statusCode = statusCode;
|
|
20
|
+
this._headers = headers;
|
|
21
|
+
}
|
|
22
|
+
getStatusCode() {
|
|
23
|
+
return this._statusCode;
|
|
24
|
+
}
|
|
25
|
+
getHeaders() {
|
|
26
|
+
return this._headers;
|
|
27
|
+
}
|
|
28
|
+
getRawResponse() {
|
|
29
|
+
throw new Error('getRawResponse not implemented.');
|
|
30
|
+
}
|
|
31
|
+
toStream(streamCompleteCallback) {
|
|
32
|
+
throw new Error('toStream not implemented.');
|
|
33
|
+
}
|
|
34
|
+
toJSON() {
|
|
35
|
+
throw new Error('toJSON not implemented.');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.HttpClientGenericResponse = HttpClientGenericResponse;
|
|
39
|
+
class HttpClientResponse {
|
|
40
|
+
constructor(response) {
|
|
41
|
+
this._res = response;
|
|
42
|
+
}
|
|
43
|
+
getStatusCode() {
|
|
44
|
+
throw new Error('getStatusCode not implemented.');
|
|
45
|
+
}
|
|
46
|
+
getHeaders() {
|
|
47
|
+
throw new Error('getHeaders not implemented.');
|
|
48
|
+
}
|
|
49
|
+
getRawResponse() {
|
|
50
|
+
throw new Error('getRawResponse not implemented.');
|
|
51
|
+
}
|
|
52
|
+
toStream(streamCompleteCallback) {
|
|
53
|
+
throw new Error('toStream not implemented.');
|
|
54
|
+
}
|
|
55
|
+
toJSON() {
|
|
56
|
+
throw new Error('toJSON not implemented.');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
exports.HttpClientResponse = HttpClientResponse;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NodeHttpClientResponse = exports.NodeHttpClient = void 0;
|
|
4
|
+
const http_ = require("http");
|
|
5
|
+
const https_ = require("https");
|
|
6
|
+
const constants_js_1 = require("../common/constants.js");
|
|
7
|
+
const HttpClient_js_1 = require("./HttpClient.js");
|
|
8
|
+
// `import * as http_ from 'http'` creates a "Module Namespace Exotic Object"
|
|
9
|
+
// which is immune to monkey-patching, whereas http_.default (in an ES Module context)
|
|
10
|
+
// will resolve to the same thing as require('http'), which is
|
|
11
|
+
// monkey-patchable. We care about this because users in their test
|
|
12
|
+
// suites might be using a library like "nock" which relies on the ability
|
|
13
|
+
// to monkey-patch and intercept calls to http.request.
|
|
14
|
+
const http = http_.default || http_;
|
|
15
|
+
const https = https_.default || https_;
|
|
16
|
+
const defaultHttpAgent = new http.Agent({ keepAlive: true });
|
|
17
|
+
const defaultHttpsAgent = new https.Agent({ keepAlive: true });
|
|
18
|
+
class NodeHttpClient extends HttpClient_js_1.HttpClient {
|
|
19
|
+
constructor(agent) {
|
|
20
|
+
super();
|
|
21
|
+
this._agent = agent;
|
|
22
|
+
}
|
|
23
|
+
makeRequest(urlString, { headers, method, protocol, requestData, timeout }) {
|
|
24
|
+
const url = new URL(urlString);
|
|
25
|
+
const isInsecureConnection = protocol === 'http' || url.protocol === 'http:';
|
|
26
|
+
let agent = this._agent;
|
|
27
|
+
if (!agent) {
|
|
28
|
+
agent = isInsecureConnection ? defaultHttpAgent : defaultHttpsAgent;
|
|
29
|
+
}
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const req = (isInsecureConnection ? http : https).request({
|
|
32
|
+
agent,
|
|
33
|
+
ciphers: 'DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2:!MD5',
|
|
34
|
+
headers,
|
|
35
|
+
host: url.host,
|
|
36
|
+
method,
|
|
37
|
+
path: url.pathname + url.search,
|
|
38
|
+
port: url.port
|
|
39
|
+
});
|
|
40
|
+
req.setTimeout(timeout !== null && timeout !== void 0 ? timeout : constants_js_1.DEFAULT_TIMEOUT, () => {
|
|
41
|
+
req.destroy(HttpClient_js_1.HttpClient.makeTimeoutError());
|
|
42
|
+
});
|
|
43
|
+
req.on('response', (res) => {
|
|
44
|
+
resolve(new NodeHttpClientResponse(res));
|
|
45
|
+
});
|
|
46
|
+
req.on('error', (error) => {
|
|
47
|
+
reject(error);
|
|
48
|
+
});
|
|
49
|
+
req.once('socket', (socket) => {
|
|
50
|
+
const payload = requestData ? JSON.stringify(requestData) : '';
|
|
51
|
+
if (socket.connecting) {
|
|
52
|
+
socket.once(isInsecureConnection ? 'connect' : 'secureConnect', () => {
|
|
53
|
+
// Send payload; we're safe:
|
|
54
|
+
req.write(payload);
|
|
55
|
+
req.end();
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// we're already connected
|
|
60
|
+
req.write(payload);
|
|
61
|
+
req.end();
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
exports.NodeHttpClient = NodeHttpClient;
|
|
68
|
+
class NodeHttpClientResponse extends HttpClient_js_1.HttpClientGenericResponse {
|
|
69
|
+
constructor(res) {
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
71
|
+
// @ts-ignore
|
|
72
|
+
super(res.statusCode, res.headers || {});
|
|
73
|
+
this._res = res;
|
|
74
|
+
}
|
|
75
|
+
getRawResponse() {
|
|
76
|
+
return this._res;
|
|
77
|
+
}
|
|
78
|
+
toStream(streamCompleteCallback) {
|
|
79
|
+
// The raw response is itself the stream, so we just return that. To be
|
|
80
|
+
// backwards compatible, we should invoke the streamCompleteCallback only
|
|
81
|
+
// once the stream has been fully consumed.
|
|
82
|
+
this._res.once('end', () => streamCompleteCallback());
|
|
83
|
+
return this._res;
|
|
84
|
+
}
|
|
85
|
+
toJSON() {
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
let response = '';
|
|
88
|
+
this._res.setEncoding('utf8');
|
|
89
|
+
this._res.on('data', (chunk) => {
|
|
90
|
+
response += chunk;
|
|
91
|
+
});
|
|
92
|
+
this._res.once('end', () => {
|
|
93
|
+
try {
|
|
94
|
+
resolve(JSON.parse(response));
|
|
95
|
+
}
|
|
96
|
+
catch (e) {
|
|
97
|
+
reject(e);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.NodeHttpClientResponse = NodeHttpClientResponse;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
3
|
+
var t = {};
|
|
4
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
5
|
+
t[p] = s[p];
|
|
6
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
7
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
8
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
9
|
+
t[p[i]] = s[p[i]];
|
|
10
|
+
}
|
|
11
|
+
return t;
|
|
12
|
+
};
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.createFetcher = void 0;
|
|
15
|
+
const defaultHeaders = {
|
|
16
|
+
'Content-Type': 'application/json'
|
|
17
|
+
};
|
|
18
|
+
const createFetcher = ({ httpClient, token, url }) => async (input, _a) => {
|
|
19
|
+
var { headers: initHeaders } = _a, init = __rest(_a, ["headers"]);
|
|
20
|
+
const response = await httpClient.makeRequest(`${url}${input}`, Object.assign({ credentials: 'omit', headers: Object.assign(Object.assign(Object.assign({}, defaultHeaders), initHeaders), typeof token !== 'undefined' ? { token } : {}) }, init));
|
|
21
|
+
if (response.getStatusCode() >= 200 && response.getStatusCode() < 300) {
|
|
22
|
+
const data = await response.toJSON();
|
|
23
|
+
return data;
|
|
24
|
+
}
|
|
25
|
+
// @TODO: Make it more useful
|
|
26
|
+
throw new Error(`${response.getStatusCode()}`);
|
|
27
|
+
};
|
|
28
|
+
exports.createFetcher = createFetcher;
|
package/cjs/package.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ALLOWED_CONFIG_PROPERTIES = void 0;
|
|
4
|
+
exports.ALLOWED_CONFIG_PROPERTIES = [
|
|
5
|
+
'httpClient',
|
|
6
|
+
'timeout',
|
|
7
|
+
'host',
|
|
8
|
+
'port',
|
|
9
|
+
'protocol',
|
|
10
|
+
'url',
|
|
11
|
+
'validator'
|
|
12
|
+
];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NonUniqueResultError = exports.EmptyTargetError = exports.UniquenessError = void 0;
|
|
4
|
+
class UniquenessError extends Error {
|
|
5
|
+
constructor(label, properties) {
|
|
6
|
+
super(`Record with label "${label}" and properties ${JSON.stringify(properties)} already exists`);
|
|
7
|
+
this.name = 'UniquenessError';
|
|
8
|
+
Object.setPrototypeOf(this, UniquenessError.prototype);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
exports.UniquenessError = UniquenessError;
|
|
12
|
+
class EmptyTargetError extends Error {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.name = 'EmptyTarget';
|
|
16
|
+
Object.setPrototypeOf(this, EmptyTargetError.prototype);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.EmptyTargetError = EmptyTargetError;
|
|
20
|
+
class NonUniqueResultError extends Error {
|
|
21
|
+
constructor(duplicateCount, searchParams) {
|
|
22
|
+
super(`Expected a unique result but found ${duplicateCount} matches for the provided search parameters: ${JSON.stringify(searchParams)}. Ensure your search parameters uniquely identify a single result.`);
|
|
23
|
+
this.name = 'NonUniqueResultError';
|
|
24
|
+
Object.setPrototypeOf(this, NonUniqueResultError.prototype);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
exports.NonUniqueResultError = NonUniqueResultError;
|
package/cjs/sdk/index.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./sdk.js"), exports);
|
|
18
|
+
__exportStar(require("./types.js"), exports);
|
|
19
|
+
__exportStar(require("./errors.js"), exports);
|
|
20
|
+
__exportStar(require("./transaction.js"), exports);
|
|
21
|
+
__exportStar(require("./utils.js"), exports);
|
|
22
|
+
__exportStar(require("./record.js"), exports);
|
|
23
|
+
__exportStar(require("./model.js"), exports);
|
package/cjs/sdk/model.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Model = void 0;
|
|
4
|
+
const rest_api_proxy_js_1 = require("../api/rest-api-proxy.js");
|
|
5
|
+
const utils_js_1 = require("../common/utils.js");
|
|
6
|
+
const errors_js_1 = require("./errors.js");
|
|
7
|
+
const utils_js_2 = require("./utils.js");
|
|
8
|
+
class Model extends rest_api_proxy_js_1.RestApiProxy {
|
|
9
|
+
constructor(modelName, schema, RushDBInstance) {
|
|
10
|
+
super();
|
|
11
|
+
this.label = modelName;
|
|
12
|
+
this.schema = schema;
|
|
13
|
+
RushDBInstance === null || RushDBInstance === void 0 ? void 0 : RushDBInstance.registerModel(this);
|
|
14
|
+
}
|
|
15
|
+
getLabel() {
|
|
16
|
+
return this.label;
|
|
17
|
+
}
|
|
18
|
+
async find(params = {}, transaction) {
|
|
19
|
+
var _a;
|
|
20
|
+
return (_a = this.apiProxy) === null || _a === void 0 ? void 0 : _a.records.find(this.label, params, transaction);
|
|
21
|
+
}
|
|
22
|
+
async findOne(params = {}, transaction) {
|
|
23
|
+
var _a;
|
|
24
|
+
return (_a = this.apiProxy) === null || _a === void 0 ? void 0 : _a.records.findOne(this.label, Object.assign({}, params), transaction);
|
|
25
|
+
}
|
|
26
|
+
async findById(id, transaction) {
|
|
27
|
+
return this.findOne({ where: { $id: id } }, transaction);
|
|
28
|
+
}
|
|
29
|
+
async findUniq(params = {}, transaction) {
|
|
30
|
+
var _a;
|
|
31
|
+
return (_a = this.apiProxy) === null || _a === void 0 ? void 0 : _a.records.findUniq(this.label, Object.assign({}, params), transaction);
|
|
32
|
+
}
|
|
33
|
+
async create(record, transaction) {
|
|
34
|
+
var _a;
|
|
35
|
+
const data = await (0, utils_js_2.mergeDefaultsWithPayload)(this.schema, record);
|
|
36
|
+
const uniqFields = (0, utils_js_2.pickUniqFieldsFromRecord)(this.schema, data);
|
|
37
|
+
if (!(0, utils_js_1.isEmptyObject)(uniqFields)) {
|
|
38
|
+
const tx = transaction !== null && transaction !== void 0 ? transaction : (await this.apiProxy.tx.begin());
|
|
39
|
+
const matchingRecords = await this.find({ where: uniqFields }, tx);
|
|
40
|
+
const hasOwnTransaction = typeof transaction !== 'undefined';
|
|
41
|
+
const canCreate = !((_a = matchingRecords === null || matchingRecords === void 0 ? void 0 : matchingRecords.data) === null || _a === void 0 ? void 0 : _a.length);
|
|
42
|
+
if (canCreate) {
|
|
43
|
+
const result = await this.apiProxy.records.create(this.label, data, tx);
|
|
44
|
+
if (!hasOwnTransaction) {
|
|
45
|
+
await tx.commit();
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
if (!hasOwnTransaction) {
|
|
51
|
+
await tx.commit();
|
|
52
|
+
}
|
|
53
|
+
// @TODO: Make it optional
|
|
54
|
+
throw new errors_js_1.UniquenessError(this.label, uniqFields);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return await this.apiProxy.records.create(this.label, data, transaction);
|
|
58
|
+
}
|
|
59
|
+
attach(sourceId, target, options, transaction) {
|
|
60
|
+
return this.apiProxy.records.attach(sourceId, target, options, transaction);
|
|
61
|
+
}
|
|
62
|
+
detach(sourceId, target, options, transaction) {
|
|
63
|
+
return this.apiProxy.records.detach(sourceId, target, options, transaction);
|
|
64
|
+
}
|
|
65
|
+
async handleSetOrUpdate(id, record, method, transaction) {
|
|
66
|
+
var _a;
|
|
67
|
+
const data = await (0, utils_js_2.mergeDefaultsWithPayload)(this.schema, record);
|
|
68
|
+
const uniqFields = (0, utils_js_2.pickUniqFieldsFromRecord)(this.schema, data);
|
|
69
|
+
if (!(0, utils_js_1.isEmptyObject)(uniqFields)) {
|
|
70
|
+
const tx = transaction !== null && transaction !== void 0 ? transaction : (await this.apiProxy.tx.begin());
|
|
71
|
+
const matchingRecords = await this.find({ where: uniqFields }, tx);
|
|
72
|
+
const hasOwnTransaction = typeof transaction !== 'undefined';
|
|
73
|
+
const canUpdate = !((_a = matchingRecords === null || matchingRecords === void 0 ? void 0 : matchingRecords.data) === null || _a === void 0 ? void 0 : _a.length) ||
|
|
74
|
+
(matchingRecords.data.length === 1 && matchingRecords.data[0].__id === id);
|
|
75
|
+
if (canUpdate) {
|
|
76
|
+
const result = await this.apiProxy.records[method](id, data, tx);
|
|
77
|
+
if (!hasOwnTransaction) {
|
|
78
|
+
await tx.commit();
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
if (!hasOwnTransaction) {
|
|
84
|
+
await tx.commit();
|
|
85
|
+
}
|
|
86
|
+
throw new errors_js_1.UniquenessError(this.label, uniqFields);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return await this.apiProxy.records[method](id, data, transaction);
|
|
90
|
+
}
|
|
91
|
+
async set(id, record, transaction) {
|
|
92
|
+
return await this.handleSetOrUpdate(id, record, 'set', transaction);
|
|
93
|
+
}
|
|
94
|
+
async update(id, record, transaction) {
|
|
95
|
+
return await this.handleSetOrUpdate(id, record, 'update', transaction);
|
|
96
|
+
}
|
|
97
|
+
async createMany(records, transaction) {
|
|
98
|
+
var _a;
|
|
99
|
+
// Begin a transaction if one isn't provided.
|
|
100
|
+
const hasOwnTransaction = typeof transaction !== 'undefined';
|
|
101
|
+
const tx = transaction !== null && transaction !== void 0 ? transaction : (await this.apiProxy.tx.begin());
|
|
102
|
+
try {
|
|
103
|
+
// Apply defaults in parallel
|
|
104
|
+
const recordsToStore = await Promise.all(records.map(async (record) => {
|
|
105
|
+
return await (0, utils_js_2.mergeDefaultsWithPayload)(this.schema, record);
|
|
106
|
+
}));
|
|
107
|
+
// Check uniqueness
|
|
108
|
+
const uniqProperties = (0, utils_js_2.pickUniqFieldsFromRecords)(recordsToStore, this.schema, this.label);
|
|
109
|
+
if (!(0, utils_js_1.isEmptyObject)(uniqProperties)) {
|
|
110
|
+
const criteria = Object.entries(uniqProperties).map(([key, values]) => ({
|
|
111
|
+
[key]: { $in: values }
|
|
112
|
+
}));
|
|
113
|
+
const matchingRecords = await this.find({
|
|
114
|
+
where: {
|
|
115
|
+
$or: criteria
|
|
116
|
+
}
|
|
117
|
+
}, tx);
|
|
118
|
+
if ((_a = matchingRecords === null || matchingRecords === void 0 ? void 0 : matchingRecords.data) === null || _a === void 0 ? void 0 : _a.length) {
|
|
119
|
+
throw new errors_js_1.UniquenessError(this.label, Object.keys(uniqProperties));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Create records in the database
|
|
123
|
+
const createdRecords = await this.apiProxy.records.createMany(this.label, recordsToStore, tx);
|
|
124
|
+
// Commit the transaction if it was created internally
|
|
125
|
+
if (!hasOwnTransaction) {
|
|
126
|
+
await tx.commit();
|
|
127
|
+
}
|
|
128
|
+
return createdRecords;
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
if (!hasOwnTransaction) {
|
|
132
|
+
await tx.rollback();
|
|
133
|
+
}
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
async delete(searchParams, transaction) {
|
|
138
|
+
if ((0, utils_js_1.isEmptyObject)(searchParams.where)) {
|
|
139
|
+
throw new errors_js_1.EmptyTargetError(`You must specify criteria to delete records of type '${this.label}'. Empty criteria are not allowed. If this was intentional, use the Dashboard instead.`);
|
|
140
|
+
}
|
|
141
|
+
return await this.apiProxy.records.delete(Object.assign(Object.assign({}, searchParams), { labels: [this.label] }), transaction);
|
|
142
|
+
}
|
|
143
|
+
async deleteById(idOrIds, transaction) {
|
|
144
|
+
return await this.apiProxy.records.deleteById(idOrIds, transaction);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.Model = Model;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DBRecordsArrayInstance = exports.DBRecordInstance = exports.DBRecordDraft = exports.DBRecordsBatchDraft = void 0;
|
|
4
|
+
const rest_api_proxy_js_1 = require("../api/rest-api-proxy.js");
|
|
5
|
+
class DBRecordsBatchDraft {
|
|
6
|
+
constructor({ label, options = {
|
|
7
|
+
returnResult: true,
|
|
8
|
+
suggestTypes: true
|
|
9
|
+
}, payload }) {
|
|
10
|
+
this.label = label;
|
|
11
|
+
this.options = options;
|
|
12
|
+
this.payload = payload;
|
|
13
|
+
}
|
|
14
|
+
toJson() {
|
|
15
|
+
return {
|
|
16
|
+
label: this.label,
|
|
17
|
+
options: this.options,
|
|
18
|
+
payload: this.payload
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.DBRecordsBatchDraft = DBRecordsBatchDraft;
|
|
23
|
+
class DBRecordDraft {
|
|
24
|
+
constructor({ label, properties = [] }) {
|
|
25
|
+
this.label = label;
|
|
26
|
+
this.properties = properties;
|
|
27
|
+
}
|
|
28
|
+
toJson() {
|
|
29
|
+
return {
|
|
30
|
+
label: this.label,
|
|
31
|
+
properties: this.properties
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
exports.DBRecordDraft = DBRecordDraft;
|
|
36
|
+
class DBRecordInstance extends rest_api_proxy_js_1.RestApiProxy {
|
|
37
|
+
constructor(data, searchParams) {
|
|
38
|
+
super();
|
|
39
|
+
this.data = data;
|
|
40
|
+
this.searchParams = searchParams;
|
|
41
|
+
}
|
|
42
|
+
async delete(transaction) {
|
|
43
|
+
if (this.data) {
|
|
44
|
+
return await this.apiProxy.records.deleteById(this.data.__id, transaction);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async update(partialData, transaction) {
|
|
48
|
+
if (this.data) {
|
|
49
|
+
return this.apiProxy.records.update(this.data.__id, partialData, transaction);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
async set(data, transaction) {
|
|
53
|
+
if (this.data) {
|
|
54
|
+
return this.apiProxy.records.set(this.data.__id, data, transaction);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async attach(target, options, transaction) {
|
|
58
|
+
if (this.data) {
|
|
59
|
+
return this.apiProxy.records.attach(this.data.__id, target, options, transaction);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async detach(target, options, transaction) {
|
|
63
|
+
if (this.data) {
|
|
64
|
+
return this.apiProxy.records.detach(this.data.__id, target, options, transaction);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
exports.DBRecordInstance = DBRecordInstance;
|
|
69
|
+
class DBRecordsArrayInstance extends rest_api_proxy_js_1.RestApiProxy {
|
|
70
|
+
constructor(data, total, searchParams) {
|
|
71
|
+
super();
|
|
72
|
+
this.data = data;
|
|
73
|
+
this.total = total;
|
|
74
|
+
this.searchParams = searchParams;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
exports.DBRecordsArrayInstance = DBRecordsArrayInstance;
|
package/cjs/sdk/sdk.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initSDK = void 0;
|
|
4
|
+
const api_js_1 = require("../api/api.js");
|
|
5
|
+
const constants_js_1 = require("../common/constants.js");
|
|
6
|
+
const record_js_1 = require("./record.js");
|
|
7
|
+
const utils_js_1 = require("./utils.js");
|
|
8
|
+
const initSDK = (httpClient) => {
|
|
9
|
+
class RushDB extends api_js_1.RestAPI {
|
|
10
|
+
constructor(token, config) {
|
|
11
|
+
var _a;
|
|
12
|
+
const props = (0, utils_js_1.parseConfig)(config);
|
|
13
|
+
super(token, Object.assign(Object.assign({}, props), { httpClient: (_a = props.httpClient) !== null && _a !== void 0 ? _a : httpClient }));
|
|
14
|
+
this.state = {
|
|
15
|
+
debug: false,
|
|
16
|
+
timeout: (0, utils_js_1.validateInteger)('timeout', props.timeout, constants_js_1.DEFAULT_TIMEOUT),
|
|
17
|
+
token
|
|
18
|
+
};
|
|
19
|
+
this.models = new Map();
|
|
20
|
+
RushDB.instance = this;
|
|
21
|
+
}
|
|
22
|
+
static getInstance() {
|
|
23
|
+
return RushDB.instance;
|
|
24
|
+
}
|
|
25
|
+
registerModel(model) {
|
|
26
|
+
const label = model.getLabel();
|
|
27
|
+
// Inject the API into the model
|
|
28
|
+
model.init(this);
|
|
29
|
+
this.models.set(label, model);
|
|
30
|
+
return model; //as unknown as Model<T['schema']> & Omit<RestAPI, 'find'>
|
|
31
|
+
}
|
|
32
|
+
getModels() {
|
|
33
|
+
return this.models;
|
|
34
|
+
}
|
|
35
|
+
getModel(label) {
|
|
36
|
+
return this.models.get(label);
|
|
37
|
+
}
|
|
38
|
+
toInstance(record) {
|
|
39
|
+
const result = new record_js_1.DBRecordInstance(record);
|
|
40
|
+
result.init(this);
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return RushDB;
|
|
45
|
+
};
|
|
46
|
+
exports.initSDK = initSDK;
|