@effectuate/cubejs-mongosql-driver 1.0.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/dist/config.js ADDED
@@ -0,0 +1,298 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveUriConfig = resolveUriConfig;
4
+ exports.parseDurationToMillis = parseDurationToMillis;
5
+ const TLS_ENV = {
6
+ envVar: 'CUBEJS_DB_SSL',
7
+ uriParam: 'tls',
8
+ parse: parseBoolToString,
9
+ };
10
+ /**
11
+ * Mongo-specific tunables. The mongodb Rust crate matches URI keys
12
+ * case-insensitively (`options.rs:2262` `key.to_lowercase()`), but we
13
+ * emit standard MongoDB camelCase per
14
+ * https://www.mongodb.com/docs/manual/reference/connection-string-options/
15
+ * for readability and to match what users find in MongoDB docs.
16
+ */
17
+ const URI_PARAM_SPECS = [
18
+ TLS_ENV,
19
+ { envVar: 'CUBEJS_DB_MAX_POOL', uriParam: 'maxPoolSize', parse: parsePositiveInteger },
20
+ { envVar: 'CUBEJS_DB_MIN_POOL', uriParam: 'minPoolSize', parse: parseNonNegativeInteger },
21
+ { envVar: 'CUBEJS_DB_IDLE_TIMEOUT', uriParam: 'maxIdleTimeMS', parse: parseDurationToMillisString },
22
+ { envVar: 'CUBEJS_MONGOSQL_MAX_CONNECTING', uriParam: 'maxConnecting', parse: parsePositiveInteger },
23
+ { envVar: 'CUBEJS_MONGOSQL_WAIT_QUEUE_TIMEOUT_MS', uriParam: 'waitQueueTimeoutMS', parse: parseNonNegativeInteger },
24
+ { envVar: 'CUBEJS_MONGOSQL_CONNECT_TIMEOUT_MS', uriParam: 'connectTimeoutMS', parse: parseNonNegativeInteger },
25
+ { envVar: 'CUBEJS_MONGOSQL_SOCKET_TIMEOUT_MS', uriParam: 'socketTimeoutMS', parse: parseNonNegativeInteger },
26
+ {
27
+ envVar: 'CUBEJS_MONGOSQL_SERVER_SELECTION_TIMEOUT_MS',
28
+ uriParam: 'serverSelectionTimeoutMS',
29
+ parse: parseNonNegativeInteger,
30
+ },
31
+ {
32
+ envVar: 'CUBEJS_MONGOSQL_HEARTBEAT_FREQUENCY_MS',
33
+ uriParam: 'heartbeatFrequencyMS',
34
+ parse: parseNonNegativeInteger,
35
+ },
36
+ { envVar: 'CUBEJS_MONGOSQL_APP_NAME', uriParam: 'appName', parse: parseNonEmpty },
37
+ { envVar: 'CUBEJS_MONGOSQL_RETRY_WRITES', uriParam: 'retryWrites', parse: parseBoolToString },
38
+ { envVar: 'CUBEJS_MONGOSQL_RETRY_READS', uriParam: 'retryReads', parse: parseBoolToString },
39
+ { envVar: 'CUBEJS_MONGOSQL_COMPRESSORS', uriParam: 'compressors', parse: parseNonEmpty },
40
+ ];
41
+ /**
42
+ * Resolve `(uri, queryTimeoutMs)` from constructor overrides + env.
43
+ *
44
+ * Throws `MONGOSQL_CONFIG_INVALID` when:
45
+ * - neither explicit uri / `CUBEJS_DB_URL` / `CUBEJS_DB_URI` is set
46
+ * AND `CUBEJS_DB_HOST` is also unset;
47
+ * - a duration env var is malformed (e.g. `"forever"`);
48
+ * - a numeric env var fails to parse.
49
+ */
50
+ function resolveUriConfig(overrideUri, env) {
51
+ // Step 1: pick the base URI.
52
+ const baseUri = overrideUri ?? env.CUBEJS_DB_URL ?? env.CUBEJS_DB_URI ?? composeUriFromParts(env);
53
+ // Step 2: enrich with env-driven URI params (only if not already in URI).
54
+ const finalUri = applyUriParams(baseUri, env);
55
+ // Step 3: resolve effective query-timeout-ms. CUBEJS_DB_QUERY_TIMEOUT
56
+ // (duration-aware) wins over the legacy CUBEJS_MONGOSQL_QUERY_TIMEOUT_MS
57
+ // (bare number). Both still recognised for back-compat.
58
+ const cubeStandardTimeout = env.CUBEJS_DB_QUERY_TIMEOUT;
59
+ const queryTimeoutMs = cubeStandardTimeout !== undefined && cubeStandardTimeout !== ''
60
+ ? parseDurationToMillis(cubeStandardTimeout, 'CUBEJS_DB_QUERY_TIMEOUT')
61
+ : parseLegacyTimeoutMs(env.CUBEJS_MONGOSQL_QUERY_TIMEOUT_MS);
62
+ return { uri: finalUri, queryTimeoutMs };
63
+ }
64
+ /**
65
+ * Build `mongodb://[user:pass@]host[:port]/[db]` from discrete env
66
+ * pieces. Used when neither `CUBEJS_DB_URL` nor `CUBEJS_DB_URI` is set.
67
+ *
68
+ * - `CUBEJS_DB_HOST` is required (clear error if missing).
69
+ * - `CUBEJS_DB_PORT` appended if set.
70
+ * - `CUBEJS_DB_USER` / `CUBEJS_DB_PASS` URL-encoded so `@` `:` `/`
71
+ * `?` `#` in passwords don't break the userinfo parser.
72
+ * - `CUBEJS_DB_NAME` appended as the path segment. Not load-bearing
73
+ * (the driver also reads it separately into `MongoSqlConfig.database`),
74
+ * but the mongodb crate parses it so we include it for consistency
75
+ * with the URL/URI shape — and any auth-database fallback the crate
76
+ * does.
77
+ *
78
+ * Host strings with commas (replica-set seed lists like `a:27017,b:27017`)
79
+ * pass through verbatim.
80
+ */
81
+ function composeUriFromParts(env) {
82
+ const host = env.CUBEJS_DB_HOST;
83
+ if (!host) {
84
+ throw configInvalid('missing required config: uri (set CUBEJS_DB_URL / CUBEJS_DB_URI or pass `uri` to the constructor; or set CUBEJS_DB_HOST to compose one)');
85
+ }
86
+ const port = env.CUBEJS_DB_PORT;
87
+ const user = env.CUBEJS_DB_USER;
88
+ const pass = env.CUBEJS_DB_PASS;
89
+ const db = env.CUBEJS_DB_NAME;
90
+ let userinfo = '';
91
+ if (user !== undefined && user !== '') {
92
+ userinfo = encodeURIComponent(user);
93
+ if (pass !== undefined && pass !== '') {
94
+ userinfo += `:${encodeURIComponent(pass)}`;
95
+ }
96
+ userinfo += '@';
97
+ }
98
+ else if (pass !== undefined && pass !== '') {
99
+ throw configInvalid('CUBEJS_DB_PASS is set but CUBEJS_DB_USER is not — credentials require both');
100
+ }
101
+ // host may itself be a seed list ("h1,h2:27017") or a hostname.
102
+ // Port is only meaningful when host is a single hostname; we append
103
+ // it conservatively if the host string has no ':' AND no ','.
104
+ let hostPart = host;
105
+ if (port !== undefined && port !== '' && !host.includes(':') && !host.includes(',')) {
106
+ hostPart = `${host}:${port}`;
107
+ }
108
+ const dbPart = db !== undefined && db !== '' ? `/${encodeURIComponent(db)}` : '/';
109
+ return `mongodb://${userinfo}${hostPart}${dbPart}`;
110
+ }
111
+ /**
112
+ * Append env-driven URI params to the base URI, skipping any key that
113
+ * already appears in the URI's query string.
114
+ *
115
+ * Implemented via `new URL` — Node's parser handles both `mongodb://`
116
+ * and `mongodb+srv://` schemes correctly (verified: see commit message).
117
+ * We reconstruct the URI by string concatenation rather than reading
118
+ * `URL.href` back because Node's URL normalisation otherwise drops
119
+ * authentication-related characters (e.g. `+` in passwords) and we
120
+ * want byte-identical pass-through of any URI the user provides.
121
+ */
122
+ function applyUriParams(baseUri, env) {
123
+ const existingKeys = extractExistingParamKeys(baseUri);
124
+ const additions = [];
125
+ for (const spec of URI_PARAM_SPECS) {
126
+ const raw = env[spec.envVar];
127
+ if (raw === undefined || raw === '')
128
+ continue;
129
+ if (existingKeys.has(spec.uriParam.toLowerCase()))
130
+ continue;
131
+ const value = spec.parse ? spec.parse(raw) : raw;
132
+ if (value === undefined) {
133
+ throw configInvalid(`${spec.envVar} has invalid value: '${raw}'`);
134
+ }
135
+ additions.push([spec.uriParam, value]);
136
+ }
137
+ if (additions.length === 0)
138
+ return baseUri;
139
+ // Determine separator: `?` if URI has no query, else `&`.
140
+ // `existingKeys.size > 0` is equivalent to "URI has a `?`" except for
141
+ // the empty-query-string edge case (`mongodb://h/db?`) which is not
142
+ // produced by us and would be parsed as a query by `new URL` anyway.
143
+ const queryStart = findQueryStart(baseUri);
144
+ const separator = queryStart === -1 ? '?' : '&';
145
+ const tail = additions.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&');
146
+ // Insert before any URL fragment (`#...`), although MongoDB URIs do
147
+ // not normally have one — defensive only.
148
+ const hashAt = baseUri.indexOf('#');
149
+ if (hashAt === -1)
150
+ return `${baseUri}${separator}${tail}`;
151
+ return `${baseUri.slice(0, hashAt)}${separator}${tail}${baseUri.slice(hashAt)}`;
152
+ }
153
+ /**
154
+ * Pull the set of param keys (lowercased) already present in the URI's
155
+ * query string. Returns an empty set for URIs with no query.
156
+ */
157
+ function extractExistingParamKeys(uri) {
158
+ const start = findQueryStart(uri);
159
+ if (start === -1)
160
+ return new Set();
161
+ const end = uri.indexOf('#', start + 1);
162
+ const query = uri.slice(start + 1, end === -1 ? undefined : end);
163
+ if (!query)
164
+ return new Set();
165
+ const keys = new Set();
166
+ for (const part of query.split('&')) {
167
+ if (!part)
168
+ continue;
169
+ const eq = part.indexOf('=');
170
+ const rawKey = eq === -1 ? part : part.slice(0, eq);
171
+ // URI keys aren't expected to be percent-encoded, but be tolerant.
172
+ try {
173
+ keys.add(decodeURIComponent(rawKey).toLowerCase());
174
+ }
175
+ catch {
176
+ keys.add(rawKey.toLowerCase());
177
+ }
178
+ }
179
+ return keys;
180
+ }
181
+ function findQueryStart(uri) {
182
+ // Skip the protocol-relative `//` — those are not the query.
183
+ return uri.indexOf('?');
184
+ }
185
+ // ---------- value parsers ----------
186
+ /**
187
+ * Accepts `"true"` / `"false"` (case-insensitive) or `"1"` / `"0"`.
188
+ * Returns the canonical `"true"` / `"false"` MongoDB URI form.
189
+ */
190
+ function parseBoolToString(raw) {
191
+ const v = raw.trim().toLowerCase();
192
+ if (v === 'true' || v === '1')
193
+ return 'true';
194
+ if (v === 'false' || v === '0')
195
+ return 'false';
196
+ return undefined;
197
+ }
198
+ function parseNonEmpty(raw) {
199
+ const v = raw.trim();
200
+ return v === '' ? undefined : v;
201
+ }
202
+ function parsePositiveInteger(raw) {
203
+ const n = parseStrictInteger(raw);
204
+ if (n === undefined || n <= 0)
205
+ return undefined;
206
+ return String(n);
207
+ }
208
+ function parseNonNegativeInteger(raw) {
209
+ const n = parseStrictInteger(raw);
210
+ if (n === undefined || n < 0)
211
+ return undefined;
212
+ return String(n);
213
+ }
214
+ function parseStrictInteger(raw) {
215
+ const v = raw.trim();
216
+ if (!/^-?\d+$/.test(v))
217
+ return undefined;
218
+ const n = Number(v);
219
+ if (!Number.isFinite(n) || !Number.isInteger(n))
220
+ return undefined;
221
+ return n;
222
+ }
223
+ /**
224
+ * Convert a duration-or-number string to a millisecond integer string.
225
+ *
226
+ * Accepts a bare number (treated as **milliseconds**) or a unit
227
+ * suffix: `ms`, `s`, `m`, `h`. Whitespace inside is trimmed.
228
+ *
229
+ * Returns the canonical `"<N>"` ms representation as a string (URI
230
+ * param values are strings). Returns `undefined` for unparseable
231
+ * input so the caller can produce a `MONGOSQL_CONFIG_INVALID` error
232
+ * naming the offending env var.
233
+ */
234
+ function parseDurationToMillisString(raw) {
235
+ const ms = parseDurationToMillisOrUndefined(raw);
236
+ return ms === undefined ? undefined : String(ms);
237
+ }
238
+ /** Same as `parseDurationToMillisString` but returns the integer directly. Throws on malformed input. */
239
+ function parseDurationToMillis(raw, envVarName) {
240
+ const ms = parseDurationToMillisOrUndefined(raw);
241
+ if (ms === undefined) {
242
+ throw configInvalid(`${envVarName} has invalid duration: '${raw}'. Accepted: bare ms (e.g. '60000'), or with unit suffix '<N>ms' / '<N>s' / '<N>m' / '<N>h'`);
243
+ }
244
+ return ms;
245
+ }
246
+ function parseDurationToMillisOrUndefined(raw) {
247
+ const v = raw.trim();
248
+ if (v === '')
249
+ return undefined;
250
+ // Most specific suffix first so `"500ms"` doesn't match the `s`
251
+ // branch — `ms` must be tested before bare `s`.
252
+ const match = v.match(/^(\d+(?:\.\d+)?)\s*(ms|s|m|h)?$/i);
253
+ if (!match)
254
+ return undefined;
255
+ const n = Number(match[1]);
256
+ if (!Number.isFinite(n) || n < 0)
257
+ return undefined;
258
+ const unit = (match[2] ?? 'ms').toLowerCase();
259
+ let multiplier;
260
+ switch (unit) {
261
+ case 'ms':
262
+ multiplier = 1;
263
+ break;
264
+ case 's':
265
+ multiplier = 1_000;
266
+ break;
267
+ case 'm':
268
+ multiplier = 60_000;
269
+ break;
270
+ case 'h':
271
+ multiplier = 3_600_000;
272
+ break;
273
+ default:
274
+ return undefined;
275
+ }
276
+ // Round to nearest ms to keep fractional inputs (`0.5s`) usable.
277
+ return Math.round(n * multiplier);
278
+ }
279
+ /**
280
+ * Legacy `CUBEJS_MONGOSQL_QUERY_TIMEOUT_MS` is documented as a bare
281
+ * number-of-milliseconds. Preserve the old behaviour: empty/invalid
282
+ * returns `undefined` (so the native default takes over) — we do NOT
283
+ * throw on invalid here, matching the pre-this-change behaviour where
284
+ * `numEnv` silently returned `undefined`.
285
+ */
286
+ function parseLegacyTimeoutMs(raw) {
287
+ if (raw === undefined || raw === '')
288
+ return undefined;
289
+ const n = Number(raw);
290
+ return Number.isFinite(n) ? n : undefined;
291
+ }
292
+ function configInvalid(detail) {
293
+ const err = new Error(`MONGOSQL_CONFIG_INVALID: ${detail}`);
294
+ err.code = 'MONGOSQL_CONFIG_INVALID';
295
+ err.name = 'MongoSqlError';
296
+ return err;
297
+ }
298
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Public exports for mongosql-cubejs-driver.
3
+ * See SPEC.md §5.1.
4
+ */
5
+ export { MongoSqlDriver } from './MongoSqlDriver.js';
6
+ export { MongoSqlQuery } from './MongoSqlQuery.js';
7
+ export type { MongoSqlConfig, SchemaSource, ErrorCode, MongoSqlError } from './types.js';
8
+ export { ERROR_CODES } from './types.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ERROR_CODES = exports.MongoSqlQuery = exports.MongoSqlDriver = void 0;
4
+ /**
5
+ * Public exports for mongosql-cubejs-driver.
6
+ * See SPEC.md §5.1.
7
+ */
8
+ var MongoSqlDriver_js_1 = require("./MongoSqlDriver.js");
9
+ Object.defineProperty(exports, "MongoSqlDriver", { enumerable: true, get: function () { return MongoSqlDriver_js_1.MongoSqlDriver; } });
10
+ var MongoSqlQuery_js_1 = require("./MongoSqlQuery.js");
11
+ Object.defineProperty(exports, "MongoSqlQuery", { enumerable: true, get: function () { return MongoSqlQuery_js_1.MongoSqlQuery; } });
12
+ var types_js_1 = require("./types.js");
13
+ Object.defineProperty(exports, "ERROR_CODES", { enumerable: true, get: function () { return types_js_1.ERROR_CODES; } });
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA;;;GAGG;AACH,yDAAqD;AAA5C,mHAAA,cAAc,OAAA;AACvB,uDAAmD;AAA1C,iHAAA,aAAa,OAAA;AAEtB,uCAAyC;AAAhC,uGAAA,WAAW,OAAA"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Type-safe wrapper around the napi-rs `.node` module.
3
+ *
4
+ * Native errors carry the SPEC §6 code prefixed in the message, e.g.
5
+ * `"MONGOSQL_CONFIG_INVALID: ..."`. This wrapper parses that prefix and
6
+ * rethrows as `MongoSqlError` with `code`/`name` set. Errors without a
7
+ * recognised prefix are passed through unchanged.
8
+ */
9
+ import type { MongoSqlConfig } from './types.js';
10
+ interface NativeAbortHandle {
11
+ abort(): void;
12
+ aborted(): boolean;
13
+ }
14
+ interface NativeMongoSqlClient {
15
+ testConnection(signal?: NativeAbortHandle | null): Promise<void>;
16
+ query(sql: string, signal?: NativeAbortHandle | null): Promise<unknown>;
17
+ tablesSchema(signal?: NativeAbortHandle | null): Promise<unknown>;
18
+ close(): Promise<void>;
19
+ }
20
+ /**
21
+ * Authoritative `(name, type)` column descriptor produced by the native
22
+ * layer from `mongosql::Translation::{select_order, result_set_schema}`.
23
+ * Used by `downloadQueryResults` to drive Cube Store's LOAD ROWS column
24
+ * list, replacing the old value-sniffing heuristic.
25
+ */
26
+ export interface ColumnType {
27
+ name: string;
28
+ /** Cube generic-type string: `timestamp` | `int` | `bigint` | `decimal` | `boolean` | `string` | `text`. */
29
+ type: string;
30
+ }
31
+ /** Shape returned by the native `query()` napi binding. */
32
+ export interface NativeQueryResult {
33
+ rows: unknown[];
34
+ types: ColumnType[];
35
+ }
36
+ interface NativeModule {
37
+ MongoSqlClient: new (config: MongoSqlConfig) => NativeMongoSqlClient;
38
+ AbortHandle?: new () => NativeAbortHandle;
39
+ }
40
+ /** Column descriptor returned by `tablesSchema()`. Mirrors the Rust shape. */
41
+ export interface ColumnInfo {
42
+ name: string;
43
+ type: string;
44
+ attributes: string[];
45
+ }
46
+ /** `tablesSchema()` shape: `{ <db>: { <coll>: ColumnInfo[] } }`. */
47
+ export type TablesSchema = Record<string, Record<string, ColumnInfo[]>>;
48
+ /** Test hook: reset the cached native-module reference. */
49
+ export declare function _resetNativeModuleForTests(): void;
50
+ /** Test hook: inject a mock native module. */
51
+ export declare function _setNativeModuleForTests(mod: NativeModule): void;
52
+ /**
53
+ * Type-safe TypeScript wrapper around the napi-rs `MongoSqlClient`.
54
+ * One-to-one method mapping; errors are normalised into `MongoSqlError`.
55
+ *
56
+ * **Cancellation contract.** Each cancellable method takes an optional
57
+ * `AbortSignal`. Internally we lazily allocate a native `AbortHandle` and
58
+ * wire `signal.addEventListener('abort', () => handle.abort())`. The
59
+ * native side races the work future against the handle's
60
+ * `CancelToken::cancelled()` future and rejects with
61
+ * `MONGOSQL_CANCELLED` if it fires first. Pre-aborted signals are
62
+ * special-cased so they reject immediately without crossing the napi
63
+ * boundary at all.
64
+ *
65
+ * napi-rs 2.16's first-class `AbortSignal` only integrates with
66
+ * `AsyncTask` (libuv async-work pattern), not `#[napi] async fn`. The
67
+ * Rust side therefore exposes its own opaque `AbortHandle` class
68
+ * (`crates/native/src/cancel.rs`) and we bridge here.
69
+ */
70
+ export declare class MongoSqlClient {
71
+ private readonly inner;
72
+ private readonly nativeAbortHandleCtor;
73
+ constructor(config: MongoSqlConfig);
74
+ testConnection(signal?: AbortSignal): Promise<void>;
75
+ query<R = Record<string, unknown>>(sql: string, signal?: AbortSignal): Promise<R[]>;
76
+ /**
77
+ * Like `query()` but returns the authoritative `(name, type)` list
78
+ * alongside the rows. Used by `downloadQueryResults` to drive Cube
79
+ * Store's column-list payload; replaces the value-sniffed inference
80
+ * the driver used pre-fix.
81
+ *
82
+ * The shape mirrors the native binding exactly:
83
+ * `{ rows: R[], types: Array<{name, type}> }`.
84
+ * `types` is empty when (and only when) `mongosql::select_order` is
85
+ * empty — a degenerate case in practice but possible if upstream
86
+ * doesn't parse a projection list.
87
+ */
88
+ queryWithTypes<R = Record<string, unknown>>(sql: string, signal?: AbortSignal): Promise<{
89
+ rows: R[];
90
+ types: ColumnType[];
91
+ }>;
92
+ tablesSchema(signal?: AbortSignal): Promise<TablesSchema>;
93
+ close(): Promise<void>;
94
+ /**
95
+ * Bridge a JS `AbortSignal` to a native `AbortHandle` for the duration
96
+ * of one call. If `signal` is undefined, the call runs un-cancelled
97
+ * (the native side still wires the parent close-token, so `close()`
98
+ * can still cancel it). If `signal` is already aborted, we throw
99
+ * `MONGOSQL_CANCELLED` synchronously without invoking the native side.
100
+ */
101
+ private runCancellable;
102
+ }
103
+ export {};
104
+ //# sourceMappingURL=native.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAA4B,MAAM,YAAY,CAAC;AAG3E,UAAU,iBAAiB;IACzB,KAAK,IAAI,IAAI,CAAC;IACd,OAAO,IAAI,OAAO,CAAC;CACpB;AAED,UAAU,oBAAoB;IAC5B,cAAc,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACxE,YAAY,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,4GAA4G;IAC5G,IAAI,EAAE,MAAM,CAAC;CACd;AAED,2DAA2D;AAC3D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,UAAU,YAAY;IACpB,cAAc,EAAE,KAAK,MAAM,EAAE,cAAc,KAAK,oBAAoB,CAAC;IAIrE,WAAW,CAAC,EAAE,UAAU,iBAAiB,CAAC;CAC3C;AAED,8EAA8E;AAC9E,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,oEAAoE;AACpE,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC;AAiBxE,2DAA2D;AAC3D,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED,8CAA8C;AAC9C,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAEhE;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAuB;IAC7C,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA4C;gBAEtE,MAAM,EAAE,cAAc;IAc5B,cAAc,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAInD,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAQzF;;;;;;;;;;;OAWG;IACG,cAAc,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9C,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC;QAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QAAC,KAAK,EAAE,UAAU,EAAE,CAAA;KAAE,CAAC;IAWxC,YAAY,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAKzD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B;;;;;;OAMG;YACW,cAAc;CA6B7B"}
package/dist/native.js ADDED
@@ -0,0 +1,192 @@
1
+ "use strict";
2
+ /**
3
+ * Type-safe wrapper around the napi-rs `.node` module.
4
+ *
5
+ * Native errors carry the SPEC §6 code prefixed in the message, e.g.
6
+ * `"MONGOSQL_CONFIG_INVALID: ..."`. This wrapper parses that prefix and
7
+ * rethrows as `MongoSqlError` with `code`/`name` set. Errors without a
8
+ * recognised prefix are passed through unchanged.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.MongoSqlClient = void 0;
12
+ exports._resetNativeModuleForTests = _resetNativeModuleForTests;
13
+ exports._setNativeModuleForTests = _setNativeModuleForTests;
14
+ const types_js_1 = require("./types.js");
15
+ let nativeModule;
16
+ function loadNative() {
17
+ if (nativeModule)
18
+ return nativeModule;
19
+ // napi-rs's `index.js` lives at project root. From `src/native.ts` (vitest)
20
+ // it's `../index.js`; from `dist/src/native.js` (built consumer) it's
21
+ // `../../index.js`. Try both.
22
+ try {
23
+ nativeModule = require('../index.js');
24
+ }
25
+ catch {
26
+ nativeModule = require('../../index.js');
27
+ }
28
+ return nativeModule;
29
+ }
30
+ /** Test hook: reset the cached native-module reference. */
31
+ function _resetNativeModuleForTests() {
32
+ nativeModule = undefined;
33
+ }
34
+ /** Test hook: inject a mock native module. */
35
+ function _setNativeModuleForTests(mod) {
36
+ nativeModule = mod;
37
+ }
38
+ /**
39
+ * Type-safe TypeScript wrapper around the napi-rs `MongoSqlClient`.
40
+ * One-to-one method mapping; errors are normalised into `MongoSqlError`.
41
+ *
42
+ * **Cancellation contract.** Each cancellable method takes an optional
43
+ * `AbortSignal`. Internally we lazily allocate a native `AbortHandle` and
44
+ * wire `signal.addEventListener('abort', () => handle.abort())`. The
45
+ * native side races the work future against the handle's
46
+ * `CancelToken::cancelled()` future and rejects with
47
+ * `MONGOSQL_CANCELLED` if it fires first. Pre-aborted signals are
48
+ * special-cased so they reject immediately without crossing the napi
49
+ * boundary at all.
50
+ *
51
+ * napi-rs 2.16's first-class `AbortSignal` only integrates with
52
+ * `AsyncTask` (libuv async-work pattern), not `#[napi] async fn`. The
53
+ * Rust side therefore exposes its own opaque `AbortHandle` class
54
+ * (`crates/native/src/cancel.rs`) and we bridge here.
55
+ */
56
+ class MongoSqlClient {
57
+ inner;
58
+ nativeAbortHandleCtor;
59
+ constructor(config) {
60
+ const native = loadNative();
61
+ this.nativeAbortHandleCtor = native.AbortHandle;
62
+ this.inner = new native.MongoSqlClient({
63
+ uri: config.uri,
64
+ database: config.database,
65
+ schemaSource: config.schemaSource,
66
+ schemaRefreshSec: config.schemaRefreshSec,
67
+ schemaFailOpen: config.schemaFailOpen,
68
+ queryTimeoutMs: config.queryTimeoutMs,
69
+ maxRows: config.maxRows,
70
+ });
71
+ }
72
+ async testConnection(signal) {
73
+ return this.runCancellable(signal, (handle) => this.inner.testConnection(handle));
74
+ }
75
+ async query(sql, signal) {
76
+ // `query()` keeps its historical `R[]` signature for ergonomic
77
+ // consumption — pre-aggregation paths that need the type list call
78
+ // `queryWithTypes` instead and pay the extra unwrap.
79
+ const { rows } = await this.queryWithTypes(sql, signal);
80
+ return rows;
81
+ }
82
+ /**
83
+ * Like `query()` but returns the authoritative `(name, type)` list
84
+ * alongside the rows. Used by `downloadQueryResults` to drive Cube
85
+ * Store's column-list payload; replaces the value-sniffed inference
86
+ * the driver used pre-fix.
87
+ *
88
+ * The shape mirrors the native binding exactly:
89
+ * `{ rows: R[], types: Array<{name, type}> }`.
90
+ * `types` is empty when (and only when) `mongosql::select_order` is
91
+ * empty — a degenerate case in practice but possible if upstream
92
+ * doesn't parse a projection list.
93
+ */
94
+ async queryWithTypes(sql, signal) {
95
+ const result = await this.runCancellable(signal, (handle) => this.inner.query(sql, handle));
96
+ if (!isQueryResult(result)) {
97
+ throw createError('MONGOSQL_EXECUTE_FAILED', `expected query result to be an object with rows + types arrays, got ${describe(result)}`);
98
+ }
99
+ return { rows: result.rows, types: result.types };
100
+ }
101
+ async tablesSchema(signal) {
102
+ const result = await this.runCancellable(signal, (handle) => this.inner.tablesSchema(handle));
103
+ return result;
104
+ }
105
+ async close() {
106
+ return wrapErrors(() => this.inner.close());
107
+ }
108
+ /**
109
+ * Bridge a JS `AbortSignal` to a native `AbortHandle` for the duration
110
+ * of one call. If `signal` is undefined, the call runs un-cancelled
111
+ * (the native side still wires the parent close-token, so `close()`
112
+ * can still cancel it). If `signal` is already aborted, we throw
113
+ * `MONGOSQL_CANCELLED` synchronously without invoking the native side.
114
+ */
115
+ async runCancellable(signal, op) {
116
+ if (signal === undefined) {
117
+ return wrapErrors(() => op(null));
118
+ }
119
+ if (signal.aborted) {
120
+ // Pre-aborted: skip the napi round-trip entirely. Mirror the
121
+ // wire-format of MONGOSQL_CANCELLED that the Rust side produces
122
+ // so callers see one consistent error shape.
123
+ throw createError('MONGOSQL_CANCELLED', 'signal was aborted before call');
124
+ }
125
+ if (!this.nativeAbortHandleCtor) {
126
+ // Defensive: production builds always export AbortHandle; this
127
+ // branch only fires under test mocks that didn't stub it. Run
128
+ // un-cancellable rather than crashing — the caller still gets
129
+ // their result.
130
+ return wrapErrors(() => op(null));
131
+ }
132
+ const handle = new this.nativeAbortHandleCtor();
133
+ const onAbort = () => handle.abort();
134
+ signal.addEventListener('abort', onAbort, { once: true });
135
+ try {
136
+ return await wrapErrors(() => op(handle));
137
+ }
138
+ finally {
139
+ signal.removeEventListener('abort', onAbort);
140
+ }
141
+ }
142
+ }
143
+ exports.MongoSqlClient = MongoSqlClient;
144
+ const ERROR_CODE_RE = /^(MONGOSQL_[A-Z_]+):\s*(.*)$/s;
145
+ async function wrapErrors(op) {
146
+ try {
147
+ return await op();
148
+ }
149
+ catch (err) {
150
+ if (err instanceof Error) {
151
+ const match = ERROR_CODE_RE.exec(err.message);
152
+ if (match) {
153
+ const [, code, message] = match;
154
+ if (types_js_1.ERROR_CODES.includes(code)) {
155
+ throw createError(code, message);
156
+ }
157
+ }
158
+ }
159
+ throw err;
160
+ }
161
+ }
162
+ function createError(code, message) {
163
+ const err = new Error(message);
164
+ err.code = code;
165
+ err.name = 'MongoSqlError';
166
+ return err;
167
+ }
168
+ function isQueryResult(value) {
169
+ if (typeof value !== 'object' || value === null)
170
+ return false;
171
+ const v = value;
172
+ if (!Array.isArray(v.rows))
173
+ return false;
174
+ if (!Array.isArray(v.types))
175
+ return false;
176
+ for (const t of v.types) {
177
+ if (typeof t !== 'object' || t === null)
178
+ return false;
179
+ const ct = t;
180
+ if (typeof ct.name !== 'string' || typeof ct.type !== 'string')
181
+ return false;
182
+ }
183
+ return true;
184
+ }
185
+ function describe(value) {
186
+ if (value === null)
187
+ return 'null';
188
+ if (Array.isArray(value))
189
+ return 'array';
190
+ return typeof value;
191
+ }
192
+ //# sourceMappingURL=native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"native.js","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"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"}