@verdant-web/server 3.3.10 → 4.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/bin/server.mjs +110 -107
- package/dist/esm/TokenVerifier.d.ts +1 -0
- package/dist/esm/TokenVerifier.js +3 -0
- package/dist/esm/TokenVerifier.js.map +1 -1
- package/dist/esm/adapters/node/errorHandler.d.ts +2 -0
- package/dist/esm/adapters/node/errorHandler.js +12 -0
- package/dist/esm/adapters/node/errorHandler.js.map +1 -0
- package/dist/esm/adapters/node/getRequestToken.d.ts +1 -0
- package/dist/esm/adapters/node/getRequestToken.js +25 -0
- package/dist/esm/adapters/node/getRequestToken.js.map +1 -0
- package/dist/esm/adapters/node/httpRouter.d.ts +47 -0
- package/dist/esm/adapters/node/httpRouter.js +88 -0
- package/dist/esm/adapters/node/httpRouter.js.map +1 -0
- package/dist/esm/adapters/node/index.d.ts +5 -0
- package/dist/esm/adapters/node/index.js +6 -0
- package/dist/esm/adapters/node/index.js.map +1 -0
- package/dist/esm/adapters/node/tokenMiddleware.d.ts +7 -0
- package/dist/esm/adapters/node/tokenMiddleware.js +22 -0
- package/dist/esm/adapters/node/tokenMiddleware.js.map +1 -0
- package/dist/esm/adapters/node/websocketHandler.d.ts +4 -0
- package/dist/esm/adapters/node/websocketHandler.js +54 -0
- package/dist/esm/adapters/node/websocketHandler.js.map +1 -0
- package/dist/esm/connections/ClientConnection.d.ts +25 -0
- package/dist/esm/{ClientConnection.js → connections/ClientConnection.js} +47 -38
- package/dist/esm/connections/ClientConnection.js.map +1 -0
- package/dist/esm/connections/MessageSender.d.ts +5 -0
- package/dist/esm/connections/MessageSender.js.map +1 -0
- package/dist/esm/connections/Presence.d.ts +23 -0
- package/dist/esm/connections/Presence.js +65 -0
- package/dist/esm/connections/Presence.js.map +1 -0
- package/dist/esm/core.d.ts +15 -0
- package/dist/esm/core.js +15 -0
- package/dist/esm/core.js.map +1 -0
- package/dist/esm/defaults.d.ts +2 -0
- package/dist/esm/defaults.js +3 -0
- package/dist/esm/defaults.js.map +1 -0
- package/dist/esm/files/FileStorage.d.ts +12 -3
- package/dist/esm/files/FileStorage.js +20 -0
- package/dist/esm/files/FileStorage.js.map +1 -1
- package/dist/esm/index.d.ts +7 -7
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internals.d.ts +14 -0
- package/dist/esm/internals.js +12 -0
- package/dist/esm/internals.js.map +1 -0
- package/dist/esm/libraries/Library.d.ts +78 -0
- package/dist/esm/{ServerLibrary.js → libraries/Library.js} +153 -144
- package/dist/esm/libraries/Library.js.map +1 -0
- package/dist/esm/{ServerLibrary.test.js → libraries/Library.test.js} +42 -33
- package/dist/esm/libraries/Library.test.js.map +1 -0
- package/dist/esm/libraries/generic.d.ts +8 -0
- package/dist/esm/libraries/generic.js +2 -0
- package/dist/esm/libraries/generic.js.map +1 -0
- package/dist/esm/libraries/singleNode.d.ts +53 -0
- package/dist/esm/libraries/singleNode.js +88 -0
- package/dist/esm/libraries/singleNode.js.map +1 -0
- package/dist/esm/logger.d.ts +1 -0
- package/dist/esm/logger.js +2 -0
- package/dist/esm/logger.js.map +1 -0
- package/dist/esm/storage/Storage.d.ts +39 -38
- package/dist/esm/storage/StorageManager.d.ts +11 -0
- package/dist/esm/storage/StorageManager.js +32 -0
- package/dist/esm/storage/StorageManager.js.map +1 -0
- package/dist/esm/storage/index.d.ts +1 -2
- package/dist/esm/storage/index.js +1 -2
- package/dist/esm/storage/index.js.map +1 -1
- package/dist/esm/storage/sqlShard/Databases.d.ts +5 -3
- package/dist/esm/storage/sqlShard/Databases.js +11 -7
- package/dist/esm/storage/sqlShard/Databases.js.map +1 -1
- package/dist/esm/storage/sqlShard/SqlBaselines.d.ts +16 -17
- package/dist/esm/storage/sqlShard/SqlBaselines.js +55 -59
- package/dist/esm/storage/sqlShard/SqlBaselines.js.map +1 -1
- package/dist/esm/storage/sqlShard/SqlFileMetadata.d.ts +13 -13
- package/dist/esm/storage/sqlShard/SqlFileMetadata.js +44 -57
- package/dist/esm/storage/sqlShard/SqlFileMetadata.js.map +1 -1
- package/dist/esm/storage/sqlShard/SqlOperations.d.ts +12 -12
- package/dist/esm/storage/sqlShard/SqlOperations.js +38 -73
- package/dist/esm/storage/sqlShard/SqlOperations.js.map +1 -1
- package/dist/esm/storage/sqlShard/SqlReplicas.d.ts +18 -17
- package/dist/esm/storage/sqlShard/SqlReplicas.js +63 -100
- package/dist/esm/storage/sqlShard/SqlReplicas.js.map +1 -1
- package/dist/esm/storage/sqlShard/database.d.ts +25 -5
- package/dist/esm/storage/sqlShard/database.js +47 -15
- package/dist/esm/storage/sqlShard/database.js.map +1 -1
- package/dist/esm/storage/sqlShard/migrations/v1.d.ts +2 -3
- package/dist/esm/storage/sqlShard/migrations/v1.js +42 -47
- package/dist/esm/storage/sqlShard/migrations/v1.js.map +1 -1
- package/dist/esm/storage/sqlShard/migrations/v2.d.ts +2 -3
- package/dist/esm/storage/sqlShard/migrations/v2.js +5 -15
- package/dist/esm/storage/sqlShard/migrations/v2.js.map +1 -1
- package/dist/esm/storage/sqlShard/migrations.d.ts +5 -7
- package/dist/esm/storage/sqlShard/migrations.js +48 -1
- package/dist/esm/storage/sqlShard/migrations.js.map +1 -1
- package/dist/esm/storage/sqlShard/sqlShardStorage.d.ts +25 -4
- package/dist/esm/storage/sqlShard/sqlShardStorage.js +43 -40
- package/dist/esm/storage/sqlShard/sqlShardStorage.js.map +1 -1
- package/dist/esm/storage/sqlShard/tables.d.ts +9 -6
- package/dist/esm/types.d.ts +1 -2
- package/package.json +24 -13
- package/src/TokenVerifier.ts +4 -0
- package/src/adapters/node/errorHandler.ts +18 -0
- package/src/adapters/node/getRequestToken.ts +34 -0
- package/src/adapters/node/httpRouter.ts +139 -0
- package/src/adapters/node/index.ts +5 -0
- package/src/adapters/node/tokenMiddleware.ts +32 -0
- package/src/adapters/node/websocketHandler.ts +79 -0
- package/src/{ClientConnection.ts → connections/ClientConnection.ts} +64 -57
- package/src/connections/MessageSender.ts +6 -0
- package/src/connections/Presence.ts +95 -0
- package/src/core.ts +36 -0
- package/src/defaults.ts +2 -0
- package/src/files/FileStorage.ts +36 -3
- package/src/index.ts +7 -7
- package/src/internals.ts +14 -0
- package/src/{ServerLibrary.test.ts → libraries/Library.test.ts} +51 -49
- package/src/{ServerLibrary.ts → libraries/Library.ts} +203 -206
- package/src/libraries/generic.ts +9 -0
- package/src/libraries/singleNode.ts +145 -0
- package/src/logger.ts +4 -0
- package/src/storage/Storage.ts +37 -66
- package/src/storage/StorageManager.ts +39 -0
- package/src/storage/index.ts +1 -2
- package/src/storage/sqlShard/Databases.ts +26 -13
- package/src/storage/sqlShard/SqlBaselines.ts +58 -67
- package/src/storage/sqlShard/SqlFileMetadata.ts +51 -72
- package/src/storage/sqlShard/SqlOperations.ts +57 -81
- package/src/storage/sqlShard/SqlReplicas.ts +80 -121
- package/src/storage/sqlShard/database.ts +82 -18
- package/src/storage/sqlShard/migrations/v1.ts +42 -52
- package/src/storage/sqlShard/migrations/v2.ts +5 -19
- package/src/storage/sqlShard/migrations.ts +66 -1
- package/src/storage/sqlShard/sqlShardStorage.ts +56 -55
- package/src/storage/sqlShard/tables.ts +6 -6
- package/src/types.ts +1 -2
- package/dist/esm/ClientConnection.d.ts +0 -19
- package/dist/esm/ClientConnection.js.map +0 -1
- package/dist/esm/MessageSender.d.ts +0 -5
- package/dist/esm/MessageSender.js.map +0 -1
- package/dist/esm/Presence.d.ts +0 -18
- package/dist/esm/Presence.js +0 -65
- package/dist/esm/Presence.js.map +0 -1
- package/dist/esm/ReplicaKeepaliveTimers.d.ts +0 -17
- package/dist/esm/ReplicaKeepaliveTimers.js +0 -27
- package/dist/esm/ReplicaKeepaliveTimers.js.map +0 -1
- package/dist/esm/Server.d.ts +0 -166
- package/dist/esm/Server.js +0 -572
- package/dist/esm/Server.js.map +0 -1
- package/dist/esm/ServerLibrary.d.ts +0 -64
- package/dist/esm/ServerLibrary.js.map +0 -1
- package/dist/esm/ServerLibrary.test.js.map +0 -1
- package/dist/esm/storage/sql/SqlBaselines.d.ts +0 -22
- package/dist/esm/storage/sql/SqlBaselines.js +0 -107
- package/dist/esm/storage/sql/SqlBaselines.js.map +0 -1
- package/dist/esm/storage/sql/SqlFileMetadata.d.ts +0 -18
- package/dist/esm/storage/sql/SqlFileMetadata.js +0 -69
- package/dist/esm/storage/sql/SqlFileMetadata.js.map +0 -1
- package/dist/esm/storage/sql/SqlOperations.d.ts +0 -19
- package/dist/esm/storage/sql/SqlOperations.js +0 -122
- package/dist/esm/storage/sql/SqlOperations.js.map +0 -1
- package/dist/esm/storage/sql/SqlReplicas.d.ts +0 -32
- package/dist/esm/storage/sql/SqlReplicas.js +0 -163
- package/dist/esm/storage/sql/SqlReplicas.js.map +0 -1
- package/dist/esm/storage/sql/database.d.ts +0 -9
- package/dist/esm/storage/sql/database.js +0 -24
- package/dist/esm/storage/sql/database.js.map +0 -1
- package/dist/esm/storage/sql/migrations/v1.d.ts +0 -3
- package/dist/esm/storage/sql/migrations/v1.js +0 -59
- package/dist/esm/storage/sql/migrations/v1.js.map +0 -1
- package/dist/esm/storage/sql/migrations/v2.d.ts +0 -3
- package/dist/esm/storage/sql/migrations/v2.js +0 -16
- package/dist/esm/storage/sql/migrations/v2.js.map +0 -1
- package/dist/esm/storage/sql/migrations.d.ts +0 -7
- package/dist/esm/storage/sql/migrations.js +0 -4
- package/dist/esm/storage/sql/migrations.js.map +0 -1
- package/dist/esm/storage/sql/sqlStorage.d.ts +0 -6
- package/dist/esm/storage/sql/sqlStorage.js +0 -35
- package/dist/esm/storage/sql/sqlStorage.js.map +0 -1
- package/dist/esm/storage/sql/tables.d.ts +0 -44
- package/dist/esm/storage/sql/tables.js +0 -2
- package/dist/esm/storage/sql/tables.js.map +0 -1
- package/dist/esm/storage/sqlShard/transfer.d.ts +0 -7
- package/dist/esm/storage/sqlShard/transfer.js +0 -90
- package/dist/esm/storage/sqlShard/transfer.js.map +0 -1
- package/dist/esm/storage/sqlShard/transfer.test.d.ts +0 -1
- package/dist/esm/storage/sqlShard/transfer.test.js +0 -109
- package/dist/esm/storage/sqlShard/transfer.test.js.map +0 -1
- package/src/MessageSender.ts +0 -10
- package/src/Presence.ts +0 -86
- package/src/ReplicaKeepaliveTimers.ts +0 -34
- package/src/Server.ts +0 -859
- package/src/storage/sql/SqlBaselines.ts +0 -147
- package/src/storage/sql/SqlFileMetadata.ts +0 -94
- package/src/storage/sql/SqlOperations.ts +0 -160
- package/src/storage/sql/SqlReplicas.ts +0 -234
- package/src/storage/sql/database.ts +0 -32
- package/src/storage/sql/migrations/v1.ts +0 -64
- package/src/storage/sql/migrations/v2.ts +0 -20
- package/src/storage/sql/migrations.ts +0 -4
- package/src/storage/sql/sqlStorage.ts +0 -57
- package/src/storage/sql/tables.ts +0 -51
- package/src/storage/sqlShard/transfer.test.ts +0 -149
- package/src/storage/sqlShard/transfer.ts +0 -123
- /package/dist/esm/{MessageSender.js → connections/MessageSender.js} +0 -0
- /package/dist/esm/{ServerLibrary.test.d.ts → libraries/Library.test.d.ts} +0 -0
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { Kysely } from 'kysely';
|
|
2
|
-
|
|
3
|
-
export async function up(db: Kysely<any>) {
|
|
4
|
-
await db.schema
|
|
5
|
-
.createTable('DocumentBaseline')
|
|
6
|
-
.ifNotExists()
|
|
7
|
-
.addColumn('oid', 'text')
|
|
8
|
-
.addColumn('snapshot', 'text')
|
|
9
|
-
.addColumn('timestamp', 'text', (cb) => cb.notNull())
|
|
10
|
-
.addColumn('libraryId', 'text', (cb) => cb.notNull())
|
|
11
|
-
.addPrimaryKeyConstraint('DocumentBaseline_primaryKey', [
|
|
12
|
-
'libraryId',
|
|
13
|
-
'oid',
|
|
14
|
-
])
|
|
15
|
-
.execute();
|
|
16
|
-
|
|
17
|
-
await db.schema
|
|
18
|
-
.createTable('OperationHistory')
|
|
19
|
-
.ifNotExists()
|
|
20
|
-
.addColumn('oid', 'text', (cb) => cb.notNull())
|
|
21
|
-
.addColumn('timestamp', 'text', (cb) => cb.notNull())
|
|
22
|
-
.addColumn('data', 'text', (cb) => cb.notNull())
|
|
23
|
-
.addColumn('serverOrder', 'integer', (cb) => cb.notNull().defaultTo(0))
|
|
24
|
-
.addColumn('replicaId', 'text', (cb) => cb.notNull())
|
|
25
|
-
.addColumn('libraryId', 'text', (cb) => cb.notNull())
|
|
26
|
-
.addPrimaryKeyConstraint('OperationHistory_primaryKey', [
|
|
27
|
-
'libraryId',
|
|
28
|
-
'replicaId',
|
|
29
|
-
'oid',
|
|
30
|
-
'timestamp',
|
|
31
|
-
])
|
|
32
|
-
.execute();
|
|
33
|
-
|
|
34
|
-
await db.schema
|
|
35
|
-
.createTable('ReplicaInfo')
|
|
36
|
-
.ifNotExists()
|
|
37
|
-
.addColumn('id', 'text')
|
|
38
|
-
.addColumn('libraryId', 'text', (cb) => cb.notNull())
|
|
39
|
-
.addColumn('clientId', 'text', (cb) => cb.notNull())
|
|
40
|
-
.addColumn('lastSeenWallClockTime', 'integer')
|
|
41
|
-
.addColumn('ackedLogicalTime', 'text')
|
|
42
|
-
.addColumn('type', 'integer', (cb) => cb.notNull().defaultTo(0))
|
|
43
|
-
.addColumn('ackedServerOrder', 'integer', (cb) => cb.notNull().defaultTo(0))
|
|
44
|
-
.addPrimaryKeyConstraint('ReplicaInfo_primaryKey', ['libraryId', 'id'])
|
|
45
|
-
.execute();
|
|
46
|
-
|
|
47
|
-
await db.schema
|
|
48
|
-
.createTable('FileMetadata')
|
|
49
|
-
.ifNotExists()
|
|
50
|
-
.addColumn('libraryId', 'text', (cb) => cb.notNull())
|
|
51
|
-
.addColumn('fileId', 'text', (cb) => cb.notNull())
|
|
52
|
-
.addColumn('name', 'text', (cb) => cb.notNull())
|
|
53
|
-
.addColumn('type', 'text', (cb) => cb.notNull())
|
|
54
|
-
.addColumn('pendingDeleteAt', 'integer')
|
|
55
|
-
.addPrimaryKeyConstraint('FileMetadata_primaryKey', ['libraryId', 'fileId'])
|
|
56
|
-
.execute();
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export async function down(db: Kysely<any>) {
|
|
60
|
-
await db.schema.dropTable('DocumentBaseline').execute();
|
|
61
|
-
await db.schema.dropTable('OperationHistory').execute();
|
|
62
|
-
await db.schema.dropTable('ReplicaInfo').execute();
|
|
63
|
-
await db.schema.dropTable('FileMetadata').execute();
|
|
64
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { Kysely } from 'kysely';
|
|
2
|
-
|
|
3
|
-
export async function up(db: Kysely<any>) {
|
|
4
|
-
// add authz column to OperationHistory and DocumentBaseline
|
|
5
|
-
await db.schema
|
|
6
|
-
.alterTable('OperationHistory')
|
|
7
|
-
.addColumn('authz', 'text', (cb) => cb.defaultTo(null))
|
|
8
|
-
.execute();
|
|
9
|
-
|
|
10
|
-
await db.schema
|
|
11
|
-
.alterTable('DocumentBaseline')
|
|
12
|
-
.addColumn('authz', 'text', (cb) => cb.defaultTo(null))
|
|
13
|
-
.execute();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export async function down(db: Kysely<any>) {
|
|
17
|
-
await db.schema.alterTable('OperationHistory').dropColumn('authz').execute();
|
|
18
|
-
|
|
19
|
-
await db.schema.alterTable('DocumentBaseline').dropColumn('authz').execute();
|
|
20
|
-
}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import Database from 'better-sqlite3';
|
|
2
|
-
import { Kysely, SqliteDialect } from 'kysely';
|
|
3
|
-
import { StorageFactory } from '../Storage.js';
|
|
4
|
-
import { SqlBaselines } from './SqlBaselines.js';
|
|
5
|
-
import { SqlOperations } from './SqlOperations.js';
|
|
6
|
-
import { SqlReplicas } from './SqlReplicas.js';
|
|
7
|
-
import { Database as DatabaseTypes } from './tables.js';
|
|
8
|
-
import { SqlFileMetadata } from './SqlFileMetadata.js';
|
|
9
|
-
import { migrateToLatest } from '@a-type/kysely';
|
|
10
|
-
import migrations from './migrations.js';
|
|
11
|
-
import { openDatabase } from './database.js';
|
|
12
|
-
|
|
13
|
-
export const sqlStorage = ({
|
|
14
|
-
databaseFile: dbFile,
|
|
15
|
-
skipMigrations,
|
|
16
|
-
disableWal,
|
|
17
|
-
}: {
|
|
18
|
-
databaseFile: string;
|
|
19
|
-
skipMigrations?: boolean;
|
|
20
|
-
disableWal?: boolean;
|
|
21
|
-
}): StorageFactory => {
|
|
22
|
-
const { db, ready } = openDatabase(dbFile, {
|
|
23
|
-
skipMigrations,
|
|
24
|
-
disableWal,
|
|
25
|
-
});
|
|
26
|
-
return (options) => {
|
|
27
|
-
const baselines = new SqlBaselines(db, 'sqlite');
|
|
28
|
-
const operations = new SqlOperations(db, 'sqlite');
|
|
29
|
-
const replicas = new SqlReplicas(
|
|
30
|
-
db,
|
|
31
|
-
options.replicaTruancyMinutes,
|
|
32
|
-
'sqlite',
|
|
33
|
-
);
|
|
34
|
-
const fileMetadata = new SqlFileMetadata(
|
|
35
|
-
db,
|
|
36
|
-
options.fileDeleteExpirationDays,
|
|
37
|
-
'sqlite',
|
|
38
|
-
);
|
|
39
|
-
const close = async () => {
|
|
40
|
-
storage.open = false;
|
|
41
|
-
await db.destroy();
|
|
42
|
-
};
|
|
43
|
-
const storage = {
|
|
44
|
-
baselines,
|
|
45
|
-
operations,
|
|
46
|
-
replicas,
|
|
47
|
-
fileMetadata,
|
|
48
|
-
close,
|
|
49
|
-
open: false,
|
|
50
|
-
ready,
|
|
51
|
-
};
|
|
52
|
-
ready.then(() => {
|
|
53
|
-
storage.open = true;
|
|
54
|
-
});
|
|
55
|
-
return storage;
|
|
56
|
-
};
|
|
57
|
-
};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import { ReplicaType } from '@verdant-web/common';
|
|
2
|
-
import { Generated, Selectable } from 'kysely';
|
|
3
|
-
|
|
4
|
-
export interface Database {
|
|
5
|
-
OperationHistory: OperationHistoryTable;
|
|
6
|
-
DocumentBaseline: DocumentBaselineTable;
|
|
7
|
-
ReplicaInfo: ReplicaInfoTable;
|
|
8
|
-
FileMetadata: FileMetadataTable;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface OperationHistoryTable {
|
|
12
|
-
oid: string;
|
|
13
|
-
timestamp: string;
|
|
14
|
-
data: string;
|
|
15
|
-
serverOrder: number;
|
|
16
|
-
replicaId: string;
|
|
17
|
-
libraryId: string;
|
|
18
|
-
authz: string | null;
|
|
19
|
-
}
|
|
20
|
-
export type OperationHistoryRow = Selectable<OperationHistoryTable>;
|
|
21
|
-
|
|
22
|
-
export interface DocumentBaselineTable {
|
|
23
|
-
oid: string;
|
|
24
|
-
snapshot: string;
|
|
25
|
-
timestamp: string;
|
|
26
|
-
libraryId: string;
|
|
27
|
-
authz: string | null;
|
|
28
|
-
}
|
|
29
|
-
export type DocumentBaselineRow = Selectable<DocumentBaselineTable>;
|
|
30
|
-
|
|
31
|
-
export interface ReplicaInfoTable {
|
|
32
|
-
id: string;
|
|
33
|
-
libraryId: string;
|
|
34
|
-
clientId: string;
|
|
35
|
-
lastSeenWallClockTime: number | null;
|
|
36
|
-
ackedLogicalTime: string | null;
|
|
37
|
-
type: ReplicaType;
|
|
38
|
-
ackedServerOrder: Generated<number>;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export type ReplicaInfoRow = Selectable<ReplicaInfoTable>;
|
|
42
|
-
|
|
43
|
-
export interface FileMetadataTable {
|
|
44
|
-
libraryId: string;
|
|
45
|
-
fileId: string;
|
|
46
|
-
name: string;
|
|
47
|
-
type: string;
|
|
48
|
-
pendingDeleteAt: number | null;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export type FileMetadataRow = Selectable<FileMetadataTable>;
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
2
|
-
import { openDatabase as openUnifiedDatabase } from '../sql/database.js';
|
|
3
|
-
import {
|
|
4
|
-
randomBaselines,
|
|
5
|
-
randomFileMetadata,
|
|
6
|
-
randomOperations,
|
|
7
|
-
randomReplicaInfo,
|
|
8
|
-
} from './_testData/unifiedData.js';
|
|
9
|
-
import { join, dirname } from 'path';
|
|
10
|
-
import { transferToShards } from './transfer.js';
|
|
11
|
-
import { rm, mkdir } from 'fs/promises';
|
|
12
|
-
import { fileURLToPath } from 'url';
|
|
13
|
-
import {
|
|
14
|
-
DocumentBaselineRow,
|
|
15
|
-
FileMetadataRow,
|
|
16
|
-
OperationHistoryRow,
|
|
17
|
-
ReplicaInfoRow,
|
|
18
|
-
} from '../sql/tables.js';
|
|
19
|
-
import { Kysely } from 'kysely';
|
|
20
|
-
|
|
21
|
-
const testTempDir = join(
|
|
22
|
-
dirname(fileURLToPath(import.meta.url)),
|
|
23
|
-
'_testData',
|
|
24
|
-
'tmp',
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
describe('sql-shard storage transfer utility', () => {
|
|
28
|
-
const databases = new Array<Kysely<any>>();
|
|
29
|
-
beforeAll(async () => {
|
|
30
|
-
try {
|
|
31
|
-
await rm(testTempDir, { recursive: true });
|
|
32
|
-
} catch (err) {}
|
|
33
|
-
// create a temp dir
|
|
34
|
-
await mkdir(testTempDir, { recursive: true });
|
|
35
|
-
});
|
|
36
|
-
afterAll(async () => {
|
|
37
|
-
try {
|
|
38
|
-
await Promise.all(databases.map((db) => db.destroy()));
|
|
39
|
-
// empty the temp dir
|
|
40
|
-
await rm(testTempDir, { recursive: true });
|
|
41
|
-
} catch (err) {
|
|
42
|
-
// what can you do...
|
|
43
|
-
console.error(err);
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should transfer data from unified database to shards', async () => {
|
|
48
|
-
const unifiedFile = join(testTempDir, 'unified.sqlite');
|
|
49
|
-
const { db: unifiedDb, ready } = openUnifiedDatabase(unifiedFile);
|
|
50
|
-
databases.push(unifiedDb);
|
|
51
|
-
await ready;
|
|
52
|
-
const libraryIds = ['library-1', 'library-2', 'library-3'];
|
|
53
|
-
const randomData = {} as Record<
|
|
54
|
-
string,
|
|
55
|
-
{
|
|
56
|
-
operations: OperationHistoryRow[];
|
|
57
|
-
baselines: DocumentBaselineRow[];
|
|
58
|
-
replicas: ReplicaInfoRow[];
|
|
59
|
-
fileMetadata: FileMetadataRow[];
|
|
60
|
-
}
|
|
61
|
-
>;
|
|
62
|
-
for (const libraryId of libraryIds) {
|
|
63
|
-
randomData[libraryId] = {
|
|
64
|
-
// test a lot of them - more than max sqlite var count.
|
|
65
|
-
// only doing operations here to reduce test time.
|
|
66
|
-
operations: randomOperations(libraryId, 6000),
|
|
67
|
-
baselines: randomBaselines(libraryId),
|
|
68
|
-
replicas: randomReplicaInfo(libraryId),
|
|
69
|
-
fileMetadata: randomFileMetadata(libraryId),
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
// have to batch these...
|
|
73
|
-
for (let i = 0; i < randomData[libraryId].operations.length; i += 1000) {
|
|
74
|
-
const toInsert = randomData[libraryId].operations.slice(i, i + 1000);
|
|
75
|
-
await unifiedDb
|
|
76
|
-
.insertInto('OperationHistory')
|
|
77
|
-
.values(toInsert)
|
|
78
|
-
.execute();
|
|
79
|
-
}
|
|
80
|
-
for (let i = 0; i < randomData[libraryId].baselines.length; i += 1000) {
|
|
81
|
-
const toInsert = randomData[libraryId].baselines.slice(i, i + 1000);
|
|
82
|
-
await unifiedDb
|
|
83
|
-
.insertInto('DocumentBaseline')
|
|
84
|
-
.values(toInsert)
|
|
85
|
-
.execute();
|
|
86
|
-
}
|
|
87
|
-
for (
|
|
88
|
-
let i = 0;
|
|
89
|
-
i < randomData[libraryId].fileMetadata.length;
|
|
90
|
-
i += 1000
|
|
91
|
-
) {
|
|
92
|
-
const toInsert = randomData[libraryId].fileMetadata.slice(i, i + 1000);
|
|
93
|
-
await unifiedDb.insertInto('FileMetadata').values(toInsert).execute();
|
|
94
|
-
}
|
|
95
|
-
for (let i = 0; i < randomData[libraryId].replicas.length; i += 1000) {
|
|
96
|
-
const toInsert = randomData[libraryId].replicas.slice(i, i + 1000);
|
|
97
|
-
await unifiedDb.insertInto('ReplicaInfo').values(toInsert).execute();
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const shards = await transferToShards({
|
|
102
|
-
directory: testTempDir,
|
|
103
|
-
file: unifiedFile,
|
|
104
|
-
});
|
|
105
|
-
Object.values(shards).map((db) => databases.push(db));
|
|
106
|
-
|
|
107
|
-
expect(Object.keys(shards).sort()).toEqual(libraryIds.sort());
|
|
108
|
-
|
|
109
|
-
for (const [libraryId, db] of Object.entries(shards)) {
|
|
110
|
-
const operations = await db
|
|
111
|
-
.selectFrom('OperationHistory')
|
|
112
|
-
.selectAll()
|
|
113
|
-
.execute();
|
|
114
|
-
const baselines = await db
|
|
115
|
-
.selectFrom('DocumentBaseline')
|
|
116
|
-
.selectAll()
|
|
117
|
-
.execute();
|
|
118
|
-
const replicas = await db.selectFrom('ReplicaInfo').selectAll().execute();
|
|
119
|
-
const fileMetadata = await db
|
|
120
|
-
.selectFrom('FileMetadata')
|
|
121
|
-
.selectAll()
|
|
122
|
-
.execute();
|
|
123
|
-
|
|
124
|
-
expect(operations.length).toBe(randomData[libraryId].operations.length);
|
|
125
|
-
expect(baselines.length).toBe(randomData[libraryId].baselines.length);
|
|
126
|
-
expect(replicas.length).toBe(randomData[libraryId].replicas.length);
|
|
127
|
-
expect(fileMetadata.length).toBe(
|
|
128
|
-
randomData[libraryId].fileMetadata.length,
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
for (const { oid } of randomData[libraryId].operations) {
|
|
132
|
-
expect(operations.find((op) => op.oid === oid)).toBeDefined();
|
|
133
|
-
}
|
|
134
|
-
for (const { oid } of randomData[libraryId].baselines) {
|
|
135
|
-
expect(
|
|
136
|
-
baselines.find((baseline) => baseline.oid === oid),
|
|
137
|
-
).toBeDefined();
|
|
138
|
-
}
|
|
139
|
-
for (const { id } of randomData[libraryId].replicas) {
|
|
140
|
-
expect(replicas.find((replica) => replica.id === id)).toBeDefined();
|
|
141
|
-
}
|
|
142
|
-
for (const { fileId } of randomData[libraryId].fileMetadata) {
|
|
143
|
-
expect(
|
|
144
|
-
fileMetadata.find((file) => file.fileId === fileId),
|
|
145
|
-
).toBeDefined();
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
});
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { Kysely } from 'kysely';
|
|
2
|
-
import { openDatabase as openUnifiedDatabase } from '../sql/database.js';
|
|
3
|
-
import { Database as UnifiedDatabase } from '../sql/tables.js';
|
|
4
|
-
import { Database } from './tables.js';
|
|
5
|
-
import { openDatabase } from './database.js';
|
|
6
|
-
|
|
7
|
-
const DEFAULT_BATCH_SIZE = 1000;
|
|
8
|
-
|
|
9
|
-
export async function transferToShards({
|
|
10
|
-
file,
|
|
11
|
-
directory,
|
|
12
|
-
batchSize = DEFAULT_BATCH_SIZE,
|
|
13
|
-
}: {
|
|
14
|
-
file: string;
|
|
15
|
-
directory: string;
|
|
16
|
-
batchSize?: number;
|
|
17
|
-
}) {
|
|
18
|
-
console.info(
|
|
19
|
-
`Transferring from unified database (${file}) to shards (${directory})...`,
|
|
20
|
-
);
|
|
21
|
-
const { db: unifiedDb, ready } = openUnifiedDatabase(file);
|
|
22
|
-
await ready;
|
|
23
|
-
const libraries = await unifiedDb
|
|
24
|
-
.selectFrom('ReplicaInfo')
|
|
25
|
-
.select('ReplicaInfo.libraryId')
|
|
26
|
-
.distinct()
|
|
27
|
-
.execute();
|
|
28
|
-
|
|
29
|
-
const dbs = await Promise.all(
|
|
30
|
-
libraries.map(async ({ libraryId }) => {
|
|
31
|
-
const db = await openDatabase(directory, libraryId);
|
|
32
|
-
await copyLibrary(libraryId, unifiedDb, db, batchSize);
|
|
33
|
-
return db;
|
|
34
|
-
}),
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
return libraries.reduce(
|
|
38
|
-
(acc, { libraryId }, i) => {
|
|
39
|
-
acc[libraryId] = dbs[i];
|
|
40
|
-
return acc;
|
|
41
|
-
},
|
|
42
|
-
{} as Record<string, Kysely<Database>>,
|
|
43
|
-
);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async function copyLibrary(
|
|
47
|
-
libraryId: string,
|
|
48
|
-
source: Kysely<UnifiedDatabase>,
|
|
49
|
-
dest: Kysely<Database>,
|
|
50
|
-
batchSize: number,
|
|
51
|
-
) {
|
|
52
|
-
const operations = await source
|
|
53
|
-
.selectFrom('OperationHistory')
|
|
54
|
-
.where('libraryId', '=', libraryId)
|
|
55
|
-
.selectAll()
|
|
56
|
-
.execute();
|
|
57
|
-
const baselines = await source
|
|
58
|
-
.selectFrom('DocumentBaseline')
|
|
59
|
-
.where('libraryId', '=', libraryId)
|
|
60
|
-
.selectAll()
|
|
61
|
-
.execute();
|
|
62
|
-
const replicas = await source
|
|
63
|
-
.selectFrom('ReplicaInfo')
|
|
64
|
-
.where('libraryId', '=', libraryId)
|
|
65
|
-
.selectAll()
|
|
66
|
-
.execute();
|
|
67
|
-
const fileMetadata = await source
|
|
68
|
-
.selectFrom('FileMetadata')
|
|
69
|
-
.where('libraryId', '=', libraryId)
|
|
70
|
-
.selectAll()
|
|
71
|
-
.execute();
|
|
72
|
-
|
|
73
|
-
for (const operation of operations) {
|
|
74
|
-
// @ts-expect-error
|
|
75
|
-
delete operation.libraryId;
|
|
76
|
-
}
|
|
77
|
-
for (const baseline of baselines) {
|
|
78
|
-
// @ts-expect-error
|
|
79
|
-
delete baseline.libraryId;
|
|
80
|
-
}
|
|
81
|
-
for (const replica of replicas) {
|
|
82
|
-
// @ts-expect-error
|
|
83
|
-
delete replica.libraryId;
|
|
84
|
-
}
|
|
85
|
-
for (const metadata of fileMetadata) {
|
|
86
|
-
// @ts-expect-error
|
|
87
|
-
delete metadata.libraryId;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
await dest.transaction().execute(async (trx) => {
|
|
91
|
-
const actions: Promise<any>[] = [];
|
|
92
|
-
// batch insert data to avoid maximum vars limits
|
|
93
|
-
if (operations.length) {
|
|
94
|
-
for (let i = 0; i < operations.length; i += batchSize) {
|
|
95
|
-
const toInsert = operations.slice(i, i + batchSize);
|
|
96
|
-
actions.push(
|
|
97
|
-
trx.insertInto('OperationHistory').values(toInsert).execute(),
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
if (baselines.length) {
|
|
102
|
-
for (let i = 0; i < baselines.length; i += batchSize) {
|
|
103
|
-
const toInsert = baselines.slice(i, i + batchSize);
|
|
104
|
-
actions.push(
|
|
105
|
-
trx.insertInto('DocumentBaseline').values(toInsert).execute(),
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
if (replicas.length) {
|
|
110
|
-
for (let i = 0; i < replicas.length; i += batchSize) {
|
|
111
|
-
const toInsert = replicas.slice(i, i + batchSize);
|
|
112
|
-
actions.push(trx.insertInto('ReplicaInfo').values(toInsert).execute());
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
if (fileMetadata.length) {
|
|
116
|
-
for (let i = 0; i < fileMetadata.length; i += batchSize) {
|
|
117
|
-
const toInsert = fileMetadata.slice(i, i + batchSize);
|
|
118
|
-
actions.push(trx.insertInto('FileMetadata').values(toInsert).execute());
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
await Promise.all(actions);
|
|
122
|
-
});
|
|
123
|
-
}
|
|
File without changes
|
|
File without changes
|