@noormdev/sdk 1.0.0-alpha.17 → 1.0.0-alpha.18
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/{chunk-BTXUEWYQ.js → chunk-KF7GE2VM.js} +4 -6
- package/dist/chunk-KF7GE2VM.js.map +1 -0
- package/dist/engine-IFYFFWFR.js +4 -0
- package/dist/{engine-5K7FA66A.js.map → engine-IFYFFWFR.js.map} +1 -1
- package/dist/index.d.ts +2498 -2410
- package/dist/index.js +524 -307
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-BTXUEWYQ.js.map +0 -1
- package/dist/engine-5K7FA66A.js +0 -4
package/dist/index.js
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import { processFile, DtReader, isTemplate, FORMAT_VERSION, DT_EXTENSIONS, encryptWithPassphrase, ENCODED_TYPES
|
|
1
|
+
import { processFile, DtReader, isTemplate, FORMAT_VERSION, DT_EXTENSIONS, encryptWithPassphrase, ENCODED_TYPES } from './chunk-KF7GE2VM.js';
|
|
2
2
|
import { initializeVault, getVaultStatus, setVaultSecret, getVaultSecret, getAllVaultSecrets, listVaultSecretKeys, deleteVaultSecret, vaultSecretExists, getVaultKey, noormDb, getNoormTables, encryptVaultKey } from './chunk-LJDHQEWW.js';
|
|
3
3
|
import { observer } from './chunk-4HW4CS2C.js';
|
|
4
4
|
import { constants, existsSync, readFileSync, mkdirSync, writeFileSync, createWriteStream } from 'fs';
|
|
5
|
-
import path, { join, dirname } from 'path';
|
|
5
|
+
import path, { join, dirname, resolve } from 'path';
|
|
6
6
|
import { makeNestedConfig, gigabytes, attempt, retry, clone, merge, attemptSync } from '@logosdx/utils';
|
|
7
|
-
import { homedir, userInfo } from 'os';
|
|
7
|
+
import { homedir, availableParallelism, userInfo } from 'os';
|
|
8
8
|
import { stat, mkdir, writeFile, unlink, rename, rm, readdir, readFile, access } from 'fs/promises';
|
|
9
|
-
import { createHash, createDecipheriv, randomBytes, createCipheriv, hkdfSync } from 'crypto';
|
|
9
|
+
import { createHash, createDecipheriv, randomBytes, createCipheriv, randomUUID, hkdfSync } from 'crypto';
|
|
10
10
|
import { z } from 'zod';
|
|
11
11
|
import { parse, stringify } from 'yaml';
|
|
12
12
|
import { execSync } from 'child_process';
|
|
13
13
|
import { sql } from 'kysely';
|
|
14
14
|
import 'dayjs';
|
|
15
15
|
import ansis from 'ansis';
|
|
16
|
-
import {
|
|
16
|
+
import { Worker, parentPort, workerData } from 'worker_threads';
|
|
17
|
+
import { ObserverRelay } from '@logosdx/observer';
|
|
18
|
+
import { fileURLToPath } from 'url';
|
|
19
|
+
import { createGzip } from 'zlib';
|
|
17
20
|
import { pipeline } from 'stream/promises';
|
|
18
21
|
import { PassThrough } from 'stream';
|
|
19
22
|
import JSON5 from 'json5';
|
|
@@ -1672,6 +1675,7 @@ async function loadExistingIdentity() {
|
|
|
1672
1675
|
var ConnectionManager = class {
|
|
1673
1676
|
#cached = /* @__PURE__ */ new Map();
|
|
1674
1677
|
#tracked = /* @__PURE__ */ new Map();
|
|
1678
|
+
#bridges = /* @__PURE__ */ new Map();
|
|
1675
1679
|
#nextId = 1;
|
|
1676
1680
|
#shuttingDown = false;
|
|
1677
1681
|
#unsubscribe = null;
|
|
@@ -1755,7 +1759,7 @@ var ConnectionManager = class {
|
|
|
1755
1759
|
for (const [id, entry] of trackedEntries) {
|
|
1756
1760
|
const destroyWithTimeout = Promise.race([
|
|
1757
1761
|
entry.conn.destroy(),
|
|
1758
|
-
new Promise((
|
|
1762
|
+
new Promise((resolve2) => setTimeout(resolve2, CLOSE_TIMEOUT))
|
|
1759
1763
|
]);
|
|
1760
1764
|
const [, err] = await attempt(() => destroyWithTimeout);
|
|
1761
1765
|
this.#tracked.delete(id);
|
|
@@ -1765,6 +1769,28 @@ var ConnectionManager = class {
|
|
|
1765
1769
|
observer.emit("connection:close", { configName: entry.configName });
|
|
1766
1770
|
}
|
|
1767
1771
|
}
|
|
1772
|
+
const bridgeNames = Array.from(this.#bridges.keys());
|
|
1773
|
+
for (const name of bridgeNames) {
|
|
1774
|
+
await this.closeBridge(name);
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
/**
|
|
1778
|
+
* Track a WorkerBridge connection for a config.
|
|
1779
|
+
*
|
|
1780
|
+
* The bridge is shut down alongside regular connections on app:shutdown.
|
|
1781
|
+
*/
|
|
1782
|
+
trackBridge(configName, bridge) {
|
|
1783
|
+
this.#bridges.set(configName, bridge);
|
|
1784
|
+
}
|
|
1785
|
+
/**
|
|
1786
|
+
* Close a specific bridge by config name.
|
|
1787
|
+
*/
|
|
1788
|
+
async closeBridge(configName) {
|
|
1789
|
+
const bridge = this.#bridges.get(configName);
|
|
1790
|
+
if (bridge) {
|
|
1791
|
+
await bridge.shutdown();
|
|
1792
|
+
this.#bridges.delete(configName);
|
|
1793
|
+
}
|
|
1768
1794
|
}
|
|
1769
1795
|
/**
|
|
1770
1796
|
* Check if a cached connection exists for a config name.
|
|
@@ -1776,7 +1802,7 @@ var ConnectionManager = class {
|
|
|
1776
1802
|
* Get total number of active connections.
|
|
1777
1803
|
*/
|
|
1778
1804
|
get size() {
|
|
1779
|
-
return this.#cached.size + this.#tracked.size;
|
|
1805
|
+
return this.#cached.size + this.#tracked.size + this.#bridges.size;
|
|
1780
1806
|
}
|
|
1781
1807
|
/**
|
|
1782
1808
|
* Check if shutdown is in progress.
|
|
@@ -4546,7 +4572,7 @@ function getLockManager() {
|
|
|
4546
4572
|
return instance3;
|
|
4547
4573
|
}
|
|
4548
4574
|
function sleep(ms) {
|
|
4549
|
-
return new Promise((
|
|
4575
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
4550
4576
|
}
|
|
4551
4577
|
|
|
4552
4578
|
// src/core/change/executor.ts
|
|
@@ -9494,7 +9520,7 @@ async function copyVaultSecrets(sourceConfig, destConfig, keys, identityHash, pr
|
|
|
9494
9520
|
throw new Error(`No vault access on source config "${sourceConfig.name}"`);
|
|
9495
9521
|
}
|
|
9496
9522
|
const destStatus = await getVaultStatus(ctx.destination.db, identityHash, ctx.destination.dialect);
|
|
9497
|
-
let destVaultKey
|
|
9523
|
+
let destVaultKey;
|
|
9498
9524
|
if (!destStatus.isInitialized) {
|
|
9499
9525
|
const [newKey, initErr] = await initializeVault(
|
|
9500
9526
|
ctx.destination.db,
|
|
@@ -10681,16 +10707,16 @@ async function planTransfer(ctx, options = {}) {
|
|
|
10681
10707
|
const orderedNames = sortErr ? allTables.map((t) => t.name) : sortedNames;
|
|
10682
10708
|
const tablePlans = [];
|
|
10683
10709
|
for (const name of orderedNames) {
|
|
10684
|
-
const
|
|
10685
|
-
if (!
|
|
10710
|
+
const meta2 = tablesByName[name];
|
|
10711
|
+
if (!meta2) continue;
|
|
10686
10712
|
tablePlans.push({
|
|
10687
|
-
name:
|
|
10688
|
-
schema:
|
|
10689
|
-
rowCount:
|
|
10690
|
-
hasIdentity:
|
|
10691
|
-
identityColumn:
|
|
10692
|
-
primaryKey:
|
|
10693
|
-
columns:
|
|
10713
|
+
name: meta2.name,
|
|
10714
|
+
schema: meta2.schema,
|
|
10715
|
+
rowCount: meta2.rowCount,
|
|
10716
|
+
hasIdentity: meta2.hasIdentity,
|
|
10717
|
+
identityColumn: meta2.identityColumn,
|
|
10718
|
+
primaryKey: meta2.primaryKey,
|
|
10719
|
+
columns: meta2.columns,
|
|
10694
10720
|
dependsOn: dependencyMap.get(name) ?? []
|
|
10695
10721
|
});
|
|
10696
10722
|
}
|
|
@@ -11234,8 +11260,8 @@ async function executeTransfer(ctx, plan, options = {}) {
|
|
|
11234
11260
|
const strategy = options.onConflict ?? "fail";
|
|
11235
11261
|
const useSameServer = plan.sameServer && strategy === "fail" && !plan.crossDialect;
|
|
11236
11262
|
const useCrossDialect = plan.crossDialect && tablePlan.columnTypes;
|
|
11237
|
-
let tableResult
|
|
11238
|
-
let tableErr
|
|
11263
|
+
let tableResult;
|
|
11264
|
+
let tableErr;
|
|
11239
11265
|
if (useSameServer) {
|
|
11240
11266
|
[tableResult, tableErr] = await transferTableSameServer(
|
|
11241
11267
|
ctx,
|
|
@@ -11864,6 +11890,174 @@ var TransferNamespace = class {
|
|
|
11864
11890
|
return getTransferPlan(this.#state.config, destConfig, options);
|
|
11865
11891
|
}
|
|
11866
11892
|
};
|
|
11893
|
+
|
|
11894
|
+
// src/core/worker-bridge/pool.ts
|
|
11895
|
+
var WorkerPool = class {
|
|
11896
|
+
#workers;
|
|
11897
|
+
#nextIndex = 0;
|
|
11898
|
+
#isShutdown = false;
|
|
11899
|
+
constructor(script, options) {
|
|
11900
|
+
const size = Math.max(1, options.size);
|
|
11901
|
+
this.#workers = Array.from(
|
|
11902
|
+
{ length: size },
|
|
11903
|
+
() => new WorkerBridge(script)
|
|
11904
|
+
);
|
|
11905
|
+
}
|
|
11906
|
+
/**
|
|
11907
|
+
* Returns the number of workers in the pool.
|
|
11908
|
+
*/
|
|
11909
|
+
get size() {
|
|
11910
|
+
return this.#workers.length;
|
|
11911
|
+
}
|
|
11912
|
+
/**
|
|
11913
|
+
* Returns true if the pool has been shut down.
|
|
11914
|
+
*/
|
|
11915
|
+
get isShutdown() {
|
|
11916
|
+
return this.#isShutdown;
|
|
11917
|
+
}
|
|
11918
|
+
/**
|
|
11919
|
+
* Sends a request to the next available worker (round-robin) and awaits its response.
|
|
11920
|
+
*
|
|
11921
|
+
* Injects a correlation ID so concurrent requests on the same event type
|
|
11922
|
+
* can be matched to their originating worker.
|
|
11923
|
+
*
|
|
11924
|
+
* @example
|
|
11925
|
+
* const { values } = await pool.request('serialize', { row, columns, index: 0 })
|
|
11926
|
+
*/
|
|
11927
|
+
async request(event, data2, options) {
|
|
11928
|
+
const worker = this.#workers[this.#nextIndex];
|
|
11929
|
+
this.#nextIndex = (this.#nextIndex + 1) % this.#workers.length;
|
|
11930
|
+
return worker.request(event, data2, options);
|
|
11931
|
+
}
|
|
11932
|
+
/**
|
|
11933
|
+
* Registers a listener on all workers for the given event.
|
|
11934
|
+
*
|
|
11935
|
+
* Useful for broadcast-style events that every worker may emit.
|
|
11936
|
+
*
|
|
11937
|
+
* @example
|
|
11938
|
+
* pool.on('serialize:res', ({ data }) => console.log(data.values))
|
|
11939
|
+
*/
|
|
11940
|
+
on(event, callback, options) {
|
|
11941
|
+
for (const worker of this.#workers) {
|
|
11942
|
+
worker.on(event, callback, options);
|
|
11943
|
+
}
|
|
11944
|
+
}
|
|
11945
|
+
/**
|
|
11946
|
+
* Terminates all workers in the pool.
|
|
11947
|
+
*
|
|
11948
|
+
* Marks the pool as shut down and waits for every worker thread to exit
|
|
11949
|
+
* before resolving.
|
|
11950
|
+
*
|
|
11951
|
+
* @example
|
|
11952
|
+
* await pool.shutdown()
|
|
11953
|
+
*/
|
|
11954
|
+
async shutdown() {
|
|
11955
|
+
this.#isShutdown = true;
|
|
11956
|
+
await Promise.all(this.#workers.map((w) => w.shutdown()));
|
|
11957
|
+
}
|
|
11958
|
+
};
|
|
11959
|
+
|
|
11960
|
+
// src/core/worker-bridge/types.ts
|
|
11961
|
+
function isTransferable(data2) {
|
|
11962
|
+
return !!data2 && typeof data2 === "object" && "__transfer" in data2;
|
|
11963
|
+
}
|
|
11964
|
+
|
|
11965
|
+
// src/core/worker-bridge/bridge.ts
|
|
11966
|
+
var WorkerBridge = class extends ObserverRelay {
|
|
11967
|
+
#port;
|
|
11968
|
+
#ownsWorker;
|
|
11969
|
+
constructor(script, data2) {
|
|
11970
|
+
const isParent = !!script;
|
|
11971
|
+
super({ name: isParent ? "bridge:parent" : "bridge:worker" });
|
|
11972
|
+
if (script) {
|
|
11973
|
+
this.#port = new Worker(script, { workerData: data2 });
|
|
11974
|
+
this.#ownsWorker = true;
|
|
11975
|
+
this.#port.on("exit", (code) => {
|
|
11976
|
+
if (!this.isShutdown && code !== 0) {
|
|
11977
|
+
this.receive("worker:exit", { code, error: `Worker exited with code ${code}` }, {});
|
|
11978
|
+
}
|
|
11979
|
+
});
|
|
11980
|
+
} else {
|
|
11981
|
+
if (!parentPort) {
|
|
11982
|
+
throw new Error(
|
|
11983
|
+
"WorkerBridge: no script provided and not in a worker thread"
|
|
11984
|
+
);
|
|
11985
|
+
}
|
|
11986
|
+
this.#port = parentPort;
|
|
11987
|
+
this.#ownsWorker = false;
|
|
11988
|
+
}
|
|
11989
|
+
this.#port.on("message", (msg) => {
|
|
11990
|
+
this.receive(msg.event, msg.data, {});
|
|
11991
|
+
});
|
|
11992
|
+
}
|
|
11993
|
+
send(event, data2) {
|
|
11994
|
+
if (isTransferable(data2)) {
|
|
11995
|
+
this.#port.postMessage({ event, data: data2 }, data2.__transfer);
|
|
11996
|
+
} else {
|
|
11997
|
+
this.#port.postMessage({ event, data: data2 }, []);
|
|
11998
|
+
}
|
|
11999
|
+
}
|
|
12000
|
+
async request(event, data2, options) {
|
|
12001
|
+
const cid = randomUUID();
|
|
12002
|
+
const pending = this.once(new RegExp(`^${event}:res:${cid}$`), options);
|
|
12003
|
+
this.send(event, { ...data2, __cid: cid });
|
|
12004
|
+
const { data: { data: result } } = await pending;
|
|
12005
|
+
return result;
|
|
12006
|
+
}
|
|
12007
|
+
transfer(event, data2, transferables) {
|
|
12008
|
+
this.#port.postMessage({ event, data: data2 }, transferables);
|
|
12009
|
+
}
|
|
12010
|
+
static pool(script, options) {
|
|
12011
|
+
return new WorkerPool(script, options);
|
|
12012
|
+
}
|
|
12013
|
+
static get workerData() {
|
|
12014
|
+
return workerData;
|
|
12015
|
+
}
|
|
12016
|
+
async shutdown() {
|
|
12017
|
+
super.shutdown();
|
|
12018
|
+
if (this.#ownsWorker && "terminate" in this.#port) {
|
|
12019
|
+
await this.#port.terminate();
|
|
12020
|
+
}
|
|
12021
|
+
}
|
|
12022
|
+
};
|
|
12023
|
+
|
|
12024
|
+
// src/core/worker-bridge/order-buffer.ts
|
|
12025
|
+
var OrderBuffer = class {
|
|
12026
|
+
#buffer = /* @__PURE__ */ new Map();
|
|
12027
|
+
#nextIndex = 0;
|
|
12028
|
+
#flush;
|
|
12029
|
+
constructor(flush) {
|
|
12030
|
+
this.#flush = flush;
|
|
12031
|
+
}
|
|
12032
|
+
get nextIndex() {
|
|
12033
|
+
return this.#nextIndex;
|
|
12034
|
+
}
|
|
12035
|
+
get pending() {
|
|
12036
|
+
return this.#buffer.size;
|
|
12037
|
+
}
|
|
12038
|
+
add(index, item) {
|
|
12039
|
+
this.#buffer.set(index, item);
|
|
12040
|
+
this.#drain();
|
|
12041
|
+
}
|
|
12042
|
+
#drain() {
|
|
12043
|
+
while (this.#buffer.has(this.#nextIndex)) {
|
|
12044
|
+
const item = this.#buffer.get(this.#nextIndex);
|
|
12045
|
+
this.#buffer.delete(this.#nextIndex);
|
|
12046
|
+
this.#nextIndex++;
|
|
12047
|
+
this.#flush(item);
|
|
12048
|
+
}
|
|
12049
|
+
}
|
|
12050
|
+
};
|
|
12051
|
+
var IS_COMPILED = import.meta.url.includes("$bunfs");
|
|
12052
|
+
var meta = import.meta;
|
|
12053
|
+
var MODULE_DIR = typeof meta.dir === "string" ? meta.dir : dirname(fileURLToPath(import.meta.url));
|
|
12054
|
+
var WORKER_DIR = resolve(MODULE_DIR, "../../workers");
|
|
12055
|
+
function resolveWorker(name) {
|
|
12056
|
+
if (IS_COMPILED) {
|
|
12057
|
+
return new URL(`./workers/${name}.js`, import.meta.url);
|
|
12058
|
+
}
|
|
12059
|
+
return resolve(WORKER_DIR, `${name}.js`);
|
|
12060
|
+
}
|
|
11867
12061
|
var DtWriter = class {
|
|
11868
12062
|
#filepath;
|
|
11869
12063
|
#schema;
|
|
@@ -11967,8 +12161,8 @@ var DtWriter = class {
|
|
|
11967
12161
|
this.#passthrough.end();
|
|
11968
12162
|
await this.#pipelinePromise;
|
|
11969
12163
|
} else if (this.#stream) {
|
|
11970
|
-
await new Promise((
|
|
11971
|
-
this.#stream.end(() =>
|
|
12164
|
+
await new Promise((resolve2, reject) => {
|
|
12165
|
+
this.#stream.end(() => resolve2());
|
|
11972
12166
|
this.#stream.on("error", reject);
|
|
11973
12167
|
});
|
|
11974
12168
|
}
|
|
@@ -11985,211 +12179,26 @@ var DtWriter = class {
|
|
|
11985
12179
|
this.#stream.write(buf);
|
|
11986
12180
|
}
|
|
11987
12181
|
};
|
|
11988
|
-
|
|
11989
|
-
|
|
11990
|
-
|
|
11991
|
-
|
|
11992
|
-
|
|
11993
|
-
|
|
11994
|
-
|
|
11995
|
-
|
|
11996
|
-
}
|
|
11997
|
-
function serializeValue(value, column) {
|
|
11998
|
-
if (value === null || value === void 0) {
|
|
11999
|
-
return null;
|
|
12000
|
-
}
|
|
12001
|
-
if (isEncodedType(column.type)) {
|
|
12002
|
-
return encodeValue(value, column.type);
|
|
12003
|
-
}
|
|
12004
|
-
return serializeSimple(value, column.type);
|
|
12005
|
-
}
|
|
12006
|
-
function serializeSimple(value, type) {
|
|
12007
|
-
switch (type) {
|
|
12008
|
-
case "bigint":
|
|
12009
|
-
return String(value);
|
|
12010
|
-
case "decimal":
|
|
12011
|
-
return String(value);
|
|
12012
|
-
case "bool":
|
|
12013
|
-
if (typeof value === "number") return value !== 0;
|
|
12014
|
-
if (typeof value === "string") return value === "1" || value.toLowerCase() === "true";
|
|
12015
|
-
return Boolean(value);
|
|
12016
|
-
case "timestamp": {
|
|
12017
|
-
if (value instanceof Date) return value.toISOString();
|
|
12018
|
-
return String(value);
|
|
12019
|
-
}
|
|
12020
|
-
case "date": {
|
|
12021
|
-
if (value instanceof Date) return value.toISOString().split("T")[0];
|
|
12022
|
-
return String(value);
|
|
12023
|
-
}
|
|
12024
|
-
case "uuid":
|
|
12025
|
-
return String(value);
|
|
12026
|
-
case "int":
|
|
12027
|
-
case "float":
|
|
12028
|
-
return typeof value === "string" ? Number(value) : value;
|
|
12029
|
-
case "string":
|
|
12030
|
-
default:
|
|
12031
|
-
return String(value);
|
|
12032
|
-
}
|
|
12033
|
-
}
|
|
12034
|
-
function encodeValue(value, type) {
|
|
12035
|
-
if (type === "binary") {
|
|
12036
|
-
return encodeBinary(value);
|
|
12037
|
-
}
|
|
12038
|
-
return encodeJsonLike(value);
|
|
12039
|
-
}
|
|
12040
|
-
function encodeBinary(value) {
|
|
12041
|
-
const buf = toBuffer(value);
|
|
12042
|
-
const byteLength = buf.length;
|
|
12043
|
-
if (byteLength < GZIP_THRESHOLD) {
|
|
12044
|
-
return [buf.toString("base64"), "b64"];
|
|
12045
|
-
}
|
|
12046
|
-
const compressed = gzipSync(buf);
|
|
12047
|
-
if (compressed.length < byteLength * GZIP_RATIO_THRESHOLD) {
|
|
12048
|
-
return [compressed.toString("base64"), "gz64"];
|
|
12049
|
-
}
|
|
12050
|
-
return [buf.toString("base64"), "b64"];
|
|
12051
|
-
}
|
|
12052
|
-
function encodeJsonLike(value) {
|
|
12053
|
-
const jsonStr = JSON.stringify(value);
|
|
12054
|
-
const byteLength = Buffer.byteLength(jsonStr, "utf8");
|
|
12055
|
-
if (byteLength < GZIP_THRESHOLD) {
|
|
12056
|
-
return [value, "raw"];
|
|
12057
|
-
}
|
|
12058
|
-
const buf = Buffer.from(jsonStr, "utf8");
|
|
12059
|
-
const compressed = gzipSync(buf);
|
|
12060
|
-
if (compressed.length < byteLength * GZIP_RATIO_THRESHOLD) {
|
|
12061
|
-
return [compressed.toString("base64"), "gz64"];
|
|
12062
|
-
}
|
|
12063
|
-
return [value, "raw"];
|
|
12064
|
-
}
|
|
12065
|
-
function toBuffer(value) {
|
|
12066
|
-
if (Buffer.isBuffer(value)) return value;
|
|
12067
|
-
if (value instanceof Uint8Array) return Buffer.from(value);
|
|
12068
|
-
if (typeof value === "string") return Buffer.from(value, "base64");
|
|
12069
|
-
return Buffer.from(String(value), "utf8");
|
|
12070
|
-
}
|
|
12071
|
-
function deserializeRow(options) {
|
|
12072
|
-
const { values, columns, targetDialect, targetVersion } = options;
|
|
12073
|
-
const result = {};
|
|
12074
|
-
for (let i = 0; i < columns.length; i++) {
|
|
12075
|
-
const col = columns[i];
|
|
12076
|
-
const value = values[i];
|
|
12077
|
-
result[col.name] = deserializeValue(value, col, targetDialect, targetVersion);
|
|
12078
|
-
}
|
|
12079
|
-
return result;
|
|
12080
|
-
}
|
|
12081
|
-
function deserializeValue(value, column, targetDialect, targetVersion) {
|
|
12082
|
-
if (value === null || value === void 0) {
|
|
12083
|
-
return null;
|
|
12084
|
-
}
|
|
12085
|
-
if (isEncodedType(column.type)) {
|
|
12086
|
-
const decoded = decodeTuple(value);
|
|
12087
|
-
return convertEncodedForTarget(decoded, column.type, targetDialect, targetVersion);
|
|
12088
|
-
}
|
|
12089
|
-
return convertSimpleForTarget(value, column.type, targetDialect);
|
|
12090
|
-
}
|
|
12091
|
-
function decodeTuple(tuple) {
|
|
12092
|
-
if (!Array.isArray(tuple) || tuple.length < 2) {
|
|
12093
|
-
return tuple;
|
|
12094
|
-
}
|
|
12095
|
-
const [value, encoding] = tuple;
|
|
12096
|
-
switch (encoding) {
|
|
12097
|
-
case "raw":
|
|
12098
|
-
return value;
|
|
12099
|
-
case "b64":
|
|
12100
|
-
return Buffer.from(value, "base64");
|
|
12101
|
-
case "gz64": {
|
|
12102
|
-
const compressed = Buffer.from(value, "base64");
|
|
12103
|
-
const decompressed = gunzipSync(compressed);
|
|
12104
|
-
const str = decompressed.toString("utf8");
|
|
12105
|
-
if (/^[[{"\d]/.test(str)) {
|
|
12106
|
-
return JSON.parse(str);
|
|
12107
|
-
}
|
|
12108
|
-
return decompressed;
|
|
12109
|
-
}
|
|
12110
|
-
default:
|
|
12111
|
-
return value;
|
|
12112
|
-
}
|
|
12113
|
-
}
|
|
12114
|
-
function convertEncodedForTarget(decoded, type, targetDialect, targetVersion) {
|
|
12115
|
-
switch (type) {
|
|
12116
|
-
case "json":
|
|
12117
|
-
return convertJsonForTarget(decoded, targetDialect, targetVersion);
|
|
12118
|
-
case "text":
|
|
12119
|
-
return decoded;
|
|
12120
|
-
case "binary":
|
|
12121
|
-
return decoded;
|
|
12122
|
-
case "vector":
|
|
12123
|
-
return convertVectorForTarget(decoded, targetDialect, targetVersion);
|
|
12124
|
-
case "array":
|
|
12125
|
-
return convertArrayForTarget(decoded, targetDialect);
|
|
12126
|
-
case "custom":
|
|
12127
|
-
if (typeof decoded === "object") return JSON.stringify(decoded);
|
|
12128
|
-
return decoded;
|
|
12129
|
-
default:
|
|
12130
|
-
return decoded;
|
|
12131
|
-
}
|
|
12132
|
-
}
|
|
12133
|
-
function convertJsonForTarget(decoded, targetDialect, targetVersion) {
|
|
12134
|
-
if (targetDialect === "mssql") {
|
|
12135
|
-
const major = targetVersion?.major ?? 2022;
|
|
12136
|
-
if (major < 2025) {
|
|
12137
|
-
return typeof decoded === "string" ? decoded : JSON.stringify(decoded);
|
|
12138
|
-
}
|
|
12139
|
-
}
|
|
12140
|
-
return decoded;
|
|
12141
|
-
}
|
|
12142
|
-
function convertVectorForTarget(decoded, targetDialect, targetVersion) {
|
|
12143
|
-
const arr = Array.isArray(decoded) ? decoded : decoded;
|
|
12144
|
-
if (targetDialect === "postgres") {
|
|
12145
|
-
return Array.isArray(arr) ? `[${arr.join(",")}]` : String(arr);
|
|
12146
|
-
}
|
|
12147
|
-
if (targetDialect === "mysql") {
|
|
12148
|
-
const major = targetVersion?.major ?? 8;
|
|
12149
|
-
if (major >= 9) {
|
|
12150
|
-
return Array.isArray(arr) ? `[${arr.join(",")}]` : String(arr);
|
|
12151
|
-
}
|
|
12152
|
-
return Array.isArray(arr) ? JSON.stringify(arr) : String(arr);
|
|
12153
|
-
}
|
|
12154
|
-
return Array.isArray(arr) ? JSON.stringify(arr) : String(arr);
|
|
12155
|
-
}
|
|
12156
|
-
function convertArrayForTarget(decoded, targetDialect) {
|
|
12157
|
-
if (targetDialect === "postgres") {
|
|
12158
|
-
return decoded;
|
|
12159
|
-
}
|
|
12160
|
-
return Array.isArray(decoded) ? JSON.stringify(decoded) : String(decoded);
|
|
12182
|
+
|
|
12183
|
+
// src/core/dt/index.ts
|
|
12184
|
+
var CONNECTION_WORKER = resolveWorker("connection");
|
|
12185
|
+
var COMPUTE_WORKER = resolveWorker("compute");
|
|
12186
|
+
function createDefaultComputePool() {
|
|
12187
|
+
return WorkerBridge.pool(COMPUTE_WORKER, {
|
|
12188
|
+
size: Math.max(1, availableParallelism() - 2)
|
|
12189
|
+
});
|
|
12161
12190
|
}
|
|
12162
|
-
function
|
|
12163
|
-
|
|
12164
|
-
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
|
|
12168
|
-
|
|
12169
|
-
|
|
12170
|
-
case "decimal":
|
|
12171
|
-
return value;
|
|
12172
|
-
case "bool":
|
|
12173
|
-
if (targetDialect === "mssql") return value ? 1 : 0;
|
|
12174
|
-
if (targetDialect === "mysql") return value ? 1 : 0;
|
|
12175
|
-
return value;
|
|
12176
|
-
case "timestamp":
|
|
12177
|
-
if (typeof value === "string") return new Date(value);
|
|
12178
|
-
return value;
|
|
12179
|
-
case "date":
|
|
12180
|
-
return value;
|
|
12181
|
-
case "uuid":
|
|
12182
|
-
return value;
|
|
12183
|
-
case "int":
|
|
12184
|
-
case "float":
|
|
12185
|
-
return value;
|
|
12186
|
-
case "string":
|
|
12187
|
-
default:
|
|
12188
|
-
return value;
|
|
12191
|
+
async function createDefaultConnectionBridge(dialect, connectionString) {
|
|
12192
|
+
const bridge = new WorkerBridge(CONNECTION_WORKER);
|
|
12193
|
+
const [, connectErr] = await attempt(
|
|
12194
|
+
() => bridge.request("connect", { dialect, connectionString })
|
|
12195
|
+
);
|
|
12196
|
+
if (connectErr) {
|
|
12197
|
+
await attempt(() => bridge.shutdown());
|
|
12198
|
+
return [null, connectErr];
|
|
12189
12199
|
}
|
|
12200
|
+
return [bridge, null];
|
|
12190
12201
|
}
|
|
12191
|
-
|
|
12192
|
-
// src/core/dt/index.ts
|
|
12193
12202
|
async function exportTable(options) {
|
|
12194
12203
|
const startTime = Date.now();
|
|
12195
12204
|
const { db, dialect, tableName, filepath, passphrase, schema: schemaName } = options;
|
|
@@ -12215,58 +12224,178 @@ async function exportTable(options) {
|
|
|
12215
12224
|
if (openErr) {
|
|
12216
12225
|
return [null, openErr];
|
|
12217
12226
|
}
|
|
12218
|
-
let
|
|
12227
|
+
let ownedConnectionBridge = null;
|
|
12228
|
+
let ownedComputePool = null;
|
|
12229
|
+
let connectionBridge = options.connectionBridge;
|
|
12230
|
+
let computePool = options.computePool;
|
|
12231
|
+
if (!connectionBridge && options.connectionString) {
|
|
12232
|
+
const [bridge, bridgeErr] = await createDefaultConnectionBridge(dialect, options.connectionString);
|
|
12233
|
+
if (bridgeErr) {
|
|
12234
|
+
return [null, bridgeErr];
|
|
12235
|
+
}
|
|
12236
|
+
connectionBridge = bridge;
|
|
12237
|
+
ownedConnectionBridge = bridge;
|
|
12238
|
+
}
|
|
12239
|
+
if (!computePool) {
|
|
12240
|
+
computePool = createDefaultComputePool();
|
|
12241
|
+
ownedComputePool = computePool;
|
|
12242
|
+
}
|
|
12243
|
+
const [result, workerErr] = await exportTableWithWorkers({
|
|
12244
|
+
writer,
|
|
12245
|
+
dtSchema,
|
|
12246
|
+
tableName,
|
|
12247
|
+
filepath,
|
|
12248
|
+
dialect,
|
|
12249
|
+
batchSize,
|
|
12250
|
+
connectionBridge,
|
|
12251
|
+
computePool,
|
|
12252
|
+
kyselyDb
|
|
12253
|
+
});
|
|
12254
|
+
if (ownedComputePool) {
|
|
12255
|
+
await attempt(() => ownedComputePool.shutdown());
|
|
12256
|
+
}
|
|
12257
|
+
if (ownedConnectionBridge) {
|
|
12258
|
+
await attempt(() => ownedConnectionBridge.shutdown());
|
|
12259
|
+
}
|
|
12260
|
+
if (workerErr) {
|
|
12261
|
+
return [null, workerErr];
|
|
12262
|
+
}
|
|
12263
|
+
const durationMs = Date.now() - startTime;
|
|
12264
|
+
observer.emit("dt:export:complete", {
|
|
12265
|
+
filepath,
|
|
12266
|
+
table: tableName,
|
|
12267
|
+
rowsWritten: result.rowsWritten,
|
|
12268
|
+
bytesWritten: result.bytesWritten,
|
|
12269
|
+
durationMs
|
|
12270
|
+
});
|
|
12271
|
+
return [result, null];
|
|
12272
|
+
}
|
|
12273
|
+
function getQuoteIdent(dialect) {
|
|
12274
|
+
if (dialect === "mssql") return (c) => `[${c}]`;
|
|
12275
|
+
if (dialect === "mysql") return (c) => `\`${c}\``;
|
|
12276
|
+
return (c) => `"${c}"`;
|
|
12277
|
+
}
|
|
12278
|
+
function buildBatchSql(dialect, tableName, columnList, orderCol, batchSize, offset) {
|
|
12279
|
+
if (dialect === "mssql") {
|
|
12280
|
+
return `SELECT ${columnList} FROM [${tableName}] ORDER BY ${orderCol} OFFSET ${offset} ROWS FETCH NEXT ${batchSize} ROWS ONLY`;
|
|
12281
|
+
}
|
|
12282
|
+
return `SELECT ${columnList} FROM "${tableName}" LIMIT ${batchSize} OFFSET ${offset}`;
|
|
12283
|
+
}
|
|
12284
|
+
async function exportTableWithWorkers(ctx) {
|
|
12285
|
+
const { writer, dtSchema, tableName, filepath, dialect, batchSize } = ctx;
|
|
12286
|
+
const { connectionBridge, computePool, kyselyDb } = ctx;
|
|
12287
|
+
const backpressureLimit = batchSize * 3;
|
|
12288
|
+
let totalRows = 0;
|
|
12289
|
+
if (connectionBridge) {
|
|
12290
|
+
const countSql = dialect === "mssql" ? `SELECT COUNT(*) AS cnt FROM [${tableName}]` : `SELECT COUNT(*) AS cnt FROM "${tableName}"`;
|
|
12291
|
+
const [countResult, countErr] = await attempt(
|
|
12292
|
+
() => connectionBridge.request("query", { sql: countSql })
|
|
12293
|
+
);
|
|
12294
|
+
if (countErr) {
|
|
12295
|
+
return [null, countErr];
|
|
12296
|
+
}
|
|
12297
|
+
const firstRow = countResult.rows[0];
|
|
12298
|
+
totalRows = Number(firstRow?.["cnt"] ?? 0);
|
|
12299
|
+
}
|
|
12219
12300
|
const columns = dtSchema.columns.map((c) => c.name);
|
|
12220
|
-
const quoteIdent4 =
|
|
12301
|
+
const quoteIdent4 = getQuoteIdent(dialect);
|
|
12221
12302
|
const columnList = columns.map(quoteIdent4).join(", ");
|
|
12303
|
+
const orderCol = quoteIdent4(columns[0]);
|
|
12304
|
+
let globalIndex = 0;
|
|
12305
|
+
let loaded = 0;
|
|
12306
|
+
let processed = 0;
|
|
12307
|
+
let saved = 0;
|
|
12308
|
+
let inFlight = 0;
|
|
12309
|
+
let pipelineError = null;
|
|
12310
|
+
const orderBuffer = new OrderBuffer((values) => {
|
|
12311
|
+
writer.writeRow(values);
|
|
12312
|
+
saved++;
|
|
12313
|
+
inFlight--;
|
|
12314
|
+
observer.emit("dt:export:saved", { table: tableName, saved, totalRows });
|
|
12315
|
+
});
|
|
12316
|
+
let offset = 0;
|
|
12222
12317
|
while (true) {
|
|
12223
|
-
|
|
12224
|
-
|
|
12225
|
-
|
|
12318
|
+
while (inFlight >= backpressureLimit) {
|
|
12319
|
+
await new Promise((resolve2) => setTimeout(resolve2, 1));
|
|
12320
|
+
}
|
|
12321
|
+
let batchRows;
|
|
12322
|
+
if (connectionBridge) {
|
|
12323
|
+
const batchSql = buildBatchSql(dialect, tableName, columnList, orderCol, batchSize, offset);
|
|
12324
|
+
const [queryResult, queryErr] = await attempt(
|
|
12325
|
+
() => connectionBridge.request("query", { sql: batchSql })
|
|
12326
|
+
);
|
|
12327
|
+
if (queryErr) {
|
|
12328
|
+
pipelineError = queryErr;
|
|
12329
|
+
break;
|
|
12330
|
+
}
|
|
12331
|
+
if (queryResult.error) {
|
|
12332
|
+
pipelineError = new Error(queryResult.error);
|
|
12333
|
+
break;
|
|
12334
|
+
}
|
|
12335
|
+
batchRows = queryResult.rows;
|
|
12336
|
+
} else {
|
|
12337
|
+
const [rows, fetchErr] = await attempt(() => {
|
|
12338
|
+
if (dialect === "mssql") {
|
|
12339
|
+
return sql`
|
|
12340
|
+
SELECT ${sql.raw(columnList)}
|
|
12341
|
+
FROM ${sql.table(tableName)}
|
|
12342
|
+
ORDER BY ${sql.raw(orderCol)}
|
|
12343
|
+
OFFSET ${offset} ROWS
|
|
12344
|
+
FETCH NEXT ${batchSize} ROWS ONLY
|
|
12345
|
+
`.execute(kyselyDb);
|
|
12346
|
+
}
|
|
12226
12347
|
return sql`
|
|
12227
12348
|
SELECT ${sql.raw(columnList)}
|
|
12228
12349
|
FROM ${sql.table(tableName)}
|
|
12229
|
-
|
|
12230
|
-
OFFSET ${offset}
|
|
12231
|
-
FETCH NEXT ${batchSize} ROWS ONLY
|
|
12350
|
+
LIMIT ${batchSize}
|
|
12351
|
+
OFFSET ${offset}
|
|
12232
12352
|
`.execute(kyselyDb);
|
|
12353
|
+
});
|
|
12354
|
+
if (fetchErr) {
|
|
12355
|
+
pipelineError = fetchErr;
|
|
12356
|
+
break;
|
|
12233
12357
|
}
|
|
12234
|
-
|
|
12235
|
-
|
|
12236
|
-
|
|
12237
|
-
|
|
12238
|
-
|
|
12239
|
-
|
|
12240
|
-
|
|
12241
|
-
|
|
12242
|
-
|
|
12243
|
-
|
|
12244
|
-
|
|
12245
|
-
|
|
12246
|
-
|
|
12247
|
-
|
|
12358
|
+
batchRows = rows.rows;
|
|
12359
|
+
}
|
|
12360
|
+
if (batchRows.length === 0) break;
|
|
12361
|
+
loaded += batchRows.length;
|
|
12362
|
+
observer.emit("dt:export:loaded", { table: tableName, loaded, totalRows });
|
|
12363
|
+
for (const row of batchRows) {
|
|
12364
|
+
const rowIndex = globalIndex++;
|
|
12365
|
+
inFlight++;
|
|
12366
|
+
computePool.request("serialize", {
|
|
12367
|
+
row,
|
|
12368
|
+
columns: dtSchema.columns,
|
|
12369
|
+
index: rowIndex
|
|
12370
|
+
}).then((result) => {
|
|
12371
|
+
processed++;
|
|
12372
|
+
observer.emit("dt:export:processed", { table: tableName, processed, totalRows });
|
|
12373
|
+
if (result.error) {
|
|
12374
|
+
pipelineError = pipelineError ?? new Error(result.error);
|
|
12375
|
+
return;
|
|
12376
|
+
}
|
|
12377
|
+
orderBuffer.add(result.index, result.values);
|
|
12378
|
+
});
|
|
12248
12379
|
}
|
|
12249
|
-
offset +=
|
|
12380
|
+
offset += batchRows.length;
|
|
12250
12381
|
observer.emit("dt:export:progress", {
|
|
12251
12382
|
filepath,
|
|
12252
12383
|
table: tableName,
|
|
12253
12384
|
rowsWritten: writer.rowsWritten,
|
|
12254
12385
|
bytesWritten: writer.bytesWritten
|
|
12255
12386
|
});
|
|
12256
|
-
if (
|
|
12387
|
+
if (batchRows.length < batchSize) break;
|
|
12388
|
+
}
|
|
12389
|
+
while (inFlight > 0) {
|
|
12390
|
+
await new Promise((resolve2) => setTimeout(resolve2, 1));
|
|
12391
|
+
}
|
|
12392
|
+
if (pipelineError) {
|
|
12393
|
+
return [null, pipelineError];
|
|
12257
12394
|
}
|
|
12258
12395
|
const [, closeErr] = await attempt(() => writer.close());
|
|
12259
12396
|
if (closeErr) {
|
|
12260
12397
|
return [null, closeErr];
|
|
12261
12398
|
}
|
|
12262
|
-
const durationMs = Date.now() - startTime;
|
|
12263
|
-
observer.emit("dt:export:complete", {
|
|
12264
|
-
filepath,
|
|
12265
|
-
table: tableName,
|
|
12266
|
-
rowsWritten: writer.rowsWritten,
|
|
12267
|
-
bytesWritten: writer.bytesWritten,
|
|
12268
|
-
durationMs
|
|
12269
|
-
});
|
|
12270
12399
|
return [{ rowsWritten: writer.rowsWritten, bytesWritten: writer.bytesWritten }, null];
|
|
12271
12400
|
}
|
|
12272
12401
|
async function importDtFile(options) {
|
|
@@ -12326,70 +12455,158 @@ async function importDtFile(options) {
|
|
|
12326
12455
|
return [null, err];
|
|
12327
12456
|
}
|
|
12328
12457
|
}
|
|
12458
|
+
let ownedComputePool = null;
|
|
12459
|
+
let computePool = options.computePool;
|
|
12460
|
+
if (!computePool) {
|
|
12461
|
+
computePool = createDefaultComputePool();
|
|
12462
|
+
ownedComputePool = computePool;
|
|
12463
|
+
}
|
|
12464
|
+
const [result, workerErr] = await importFileWithWorkers({
|
|
12465
|
+
reader,
|
|
12466
|
+
dtSchema,
|
|
12467
|
+
tableName,
|
|
12468
|
+
filepath,
|
|
12469
|
+
dialect,
|
|
12470
|
+
version,
|
|
12471
|
+
batchSize,
|
|
12472
|
+
onConflict: options.onConflict ?? "fail",
|
|
12473
|
+
computePool,
|
|
12474
|
+
kyselyDb
|
|
12475
|
+
});
|
|
12476
|
+
if (ownedComputePool) {
|
|
12477
|
+
await attempt(() => ownedComputePool.shutdown());
|
|
12478
|
+
}
|
|
12479
|
+
if (workerErr) {
|
|
12480
|
+
reader.close();
|
|
12481
|
+
observer.emit("error", { source: "dt:import", error: workerErr, context: { filepath, table: tableName } });
|
|
12482
|
+
return [null, workerErr];
|
|
12483
|
+
}
|
|
12484
|
+
reader.close();
|
|
12485
|
+
const durationMs = Date.now() - startTime;
|
|
12486
|
+
observer.emit("dt:import:complete", {
|
|
12487
|
+
filepath,
|
|
12488
|
+
table: tableName,
|
|
12489
|
+
rowsImported: result.rowsImported,
|
|
12490
|
+
rowsSkipped: result.rowsSkipped,
|
|
12491
|
+
durationMs
|
|
12492
|
+
});
|
|
12493
|
+
return [result, null];
|
|
12494
|
+
}
|
|
12495
|
+
async function importFileWithWorkers(ctx) {
|
|
12496
|
+
const { reader, dtSchema, tableName, filepath, dialect, version, batchSize } = ctx;
|
|
12497
|
+
const { onConflict, computePool, kyselyDb } = ctx;
|
|
12329
12498
|
let rowsImported = 0;
|
|
12330
12499
|
let rowsSkipped = 0;
|
|
12331
|
-
let
|
|
12332
|
-
|
|
12333
|
-
|
|
12334
|
-
|
|
12335
|
-
|
|
12336
|
-
|
|
12337
|
-
|
|
12338
|
-
|
|
12339
|
-
|
|
12340
|
-
|
|
12341
|
-
|
|
12342
|
-
const [batchResult, insertErr] = await insertImportBatch(
|
|
12343
|
-
kyselyDb,
|
|
12344
|
-
tableName,
|
|
12345
|
-
batch,
|
|
12346
|
-
options.onConflict ?? "fail",
|
|
12347
|
-
dialect,
|
|
12348
|
-
columnNames
|
|
12349
|
-
);
|
|
12350
|
-
if (insertErr) {
|
|
12351
|
-
reader.close();
|
|
12352
|
-
observer.emit("error", { source: "dt:import", error: insertErr, context: { filepath, table: tableName } });
|
|
12353
|
-
return [null, insertErr];
|
|
12354
|
-
}
|
|
12355
|
-
rowsImported += batchResult.inserted + batchResult.updated;
|
|
12356
|
-
rowsSkipped += batchResult.skipped;
|
|
12357
|
-
batch = [];
|
|
12358
|
-
observer.emit("dt:import:progress", {
|
|
12359
|
-
filepath,
|
|
12360
|
-
table: tableName,
|
|
12361
|
-
rowsImported,
|
|
12362
|
-
rowsSkipped
|
|
12363
|
-
});
|
|
12364
|
-
}
|
|
12365
|
-
}
|
|
12366
|
-
if (batch.length > 0) {
|
|
12367
|
-
const columnNames = dtSchema.columns.map((c) => c.name);
|
|
12500
|
+
let loaded = 0;
|
|
12501
|
+
let processed = 0;
|
|
12502
|
+
let saved = 0;
|
|
12503
|
+
let globalIndex = 0;
|
|
12504
|
+
let inFlight = 0;
|
|
12505
|
+
let pipelineError = null;
|
|
12506
|
+
let totalRows = 0;
|
|
12507
|
+
let insertBatch2 = [];
|
|
12508
|
+
const columnNames = dtSchema.columns.map((c) => c.name);
|
|
12509
|
+
const flushInsertBatch = async () => {
|
|
12510
|
+
if (insertBatch2.length === 0) return null;
|
|
12368
12511
|
const [batchResult, insertErr] = await insertImportBatch(
|
|
12369
12512
|
kyselyDb,
|
|
12370
12513
|
tableName,
|
|
12371
|
-
|
|
12372
|
-
|
|
12514
|
+
insertBatch2,
|
|
12515
|
+
onConflict,
|
|
12373
12516
|
dialect,
|
|
12374
12517
|
columnNames
|
|
12375
12518
|
);
|
|
12376
12519
|
if (insertErr) {
|
|
12377
|
-
|
|
12378
|
-
observer.emit("error", { source: "dt:import", error: insertErr, context: { filepath, table: tableName } });
|
|
12379
|
-
return [null, insertErr];
|
|
12520
|
+
return insertErr;
|
|
12380
12521
|
}
|
|
12381
12522
|
rowsImported += batchResult.inserted + batchResult.updated;
|
|
12382
12523
|
rowsSkipped += batchResult.skipped;
|
|
12383
|
-
|
|
12384
|
-
|
|
12385
|
-
|
|
12386
|
-
|
|
12387
|
-
|
|
12388
|
-
|
|
12389
|
-
|
|
12390
|
-
|
|
12391
|
-
|
|
12524
|
+
insertBatch2 = [];
|
|
12525
|
+
observer.emit("dt:import:progress", {
|
|
12526
|
+
filepath,
|
|
12527
|
+
table: tableName,
|
|
12528
|
+
rowsImported,
|
|
12529
|
+
rowsSkipped
|
|
12530
|
+
});
|
|
12531
|
+
return null;
|
|
12532
|
+
};
|
|
12533
|
+
const orderBuffer = new OrderBuffer((record) => {
|
|
12534
|
+
insertBatch2.push(record);
|
|
12535
|
+
saved++;
|
|
12536
|
+
inFlight--;
|
|
12537
|
+
observer.emit("dt:import:saved", { table: tableName, saved, totalRows });
|
|
12392
12538
|
});
|
|
12539
|
+
let readBatch = [];
|
|
12540
|
+
for await (const values of reader.rows()) {
|
|
12541
|
+
readBatch.push(values);
|
|
12542
|
+
loaded++;
|
|
12543
|
+
totalRows = Math.max(totalRows, loaded);
|
|
12544
|
+
if (readBatch.length >= batchSize) {
|
|
12545
|
+
observer.emit("dt:import:loaded", { table: tableName, loaded, totalRows });
|
|
12546
|
+
for (const rowValues of readBatch) {
|
|
12547
|
+
const rowIndex = globalIndex++;
|
|
12548
|
+
inFlight++;
|
|
12549
|
+
computePool.request("deserialize", {
|
|
12550
|
+
values: rowValues,
|
|
12551
|
+
columns: dtSchema.columns,
|
|
12552
|
+
targetDialect: dialect,
|
|
12553
|
+
targetVersion: version ? `${version.major}.${version.minor}` : void 0,
|
|
12554
|
+
index: rowIndex
|
|
12555
|
+
}).then((result) => {
|
|
12556
|
+
processed++;
|
|
12557
|
+
observer.emit("dt:import:processed", { table: tableName, processed, totalRows });
|
|
12558
|
+
if (result.error) {
|
|
12559
|
+
pipelineError = pipelineError ?? new Error(result.error);
|
|
12560
|
+
return;
|
|
12561
|
+
}
|
|
12562
|
+
orderBuffer.add(result.index, result.record);
|
|
12563
|
+
});
|
|
12564
|
+
}
|
|
12565
|
+
readBatch = [];
|
|
12566
|
+
while (inFlight > 0) {
|
|
12567
|
+
await new Promise((resolve2) => setTimeout(resolve2, 1));
|
|
12568
|
+
}
|
|
12569
|
+
if (pipelineError) {
|
|
12570
|
+
return [null, pipelineError];
|
|
12571
|
+
}
|
|
12572
|
+
const flushErr = await flushInsertBatch();
|
|
12573
|
+
if (flushErr) {
|
|
12574
|
+
return [null, flushErr];
|
|
12575
|
+
}
|
|
12576
|
+
}
|
|
12577
|
+
}
|
|
12578
|
+
if (readBatch.length > 0) {
|
|
12579
|
+
observer.emit("dt:import:loaded", { table: tableName, loaded, totalRows });
|
|
12580
|
+
for (const rowValues of readBatch) {
|
|
12581
|
+
const rowIndex = globalIndex++;
|
|
12582
|
+
inFlight++;
|
|
12583
|
+
computePool.request("deserialize", {
|
|
12584
|
+
values: rowValues,
|
|
12585
|
+
columns: dtSchema.columns,
|
|
12586
|
+
targetDialect: dialect,
|
|
12587
|
+
targetVersion: version ? `${version.major}.${version.minor}` : void 0,
|
|
12588
|
+
index: rowIndex
|
|
12589
|
+
}).then((result) => {
|
|
12590
|
+
processed++;
|
|
12591
|
+
observer.emit("dt:import:processed", { table: tableName, processed, totalRows });
|
|
12592
|
+
if (result.error) {
|
|
12593
|
+
pipelineError = pipelineError ?? new Error(result.error);
|
|
12594
|
+
return;
|
|
12595
|
+
}
|
|
12596
|
+
orderBuffer.add(result.index, result.record);
|
|
12597
|
+
});
|
|
12598
|
+
}
|
|
12599
|
+
while (inFlight > 0) {
|
|
12600
|
+
await new Promise((resolve2) => setTimeout(resolve2, 1));
|
|
12601
|
+
}
|
|
12602
|
+
if (pipelineError) {
|
|
12603
|
+
return [null, pipelineError];
|
|
12604
|
+
}
|
|
12605
|
+
const flushErr = await flushInsertBatch();
|
|
12606
|
+
if (flushErr) {
|
|
12607
|
+
return [null, flushErr];
|
|
12608
|
+
}
|
|
12609
|
+
}
|
|
12393
12610
|
return [{ rowsImported, rowsSkipped }, null];
|
|
12394
12611
|
}
|
|
12395
12612
|
async function insertImportBatch(db, table, rows, onConflict, dialect, columns) {
|