@peers-app/peers-sdk 0.14.0 → 0.15.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/context/data-context.d.ts +4 -4
- package/dist/context/data-context.js +1 -1
- package/dist/context/index.d.ts +3 -3
- package/dist/context/index.js +4 -0
- package/dist/context/user-context-singleton.js +13 -14
- package/dist/context/user-context.d.ts +4 -4
- package/dist/context/user-context.js +48 -31
- package/dist/data/assistants.d.ts +1 -1
- package/dist/data/assistants.js +35 -24
- package/dist/data/change-tracking.d.ts +8 -8
- package/dist/data/change-tracking.js +45 -39
- package/dist/data/channels.js +5 -5
- package/dist/data/data-locks.d.ts +2 -2
- package/dist/data/data-locks.js +21 -23
- package/dist/data/data-locks.test.js +73 -75
- package/dist/data/device-sync-info.d.ts +1 -1
- package/dist/data/device-sync-info.js +4 -4
- package/dist/data/devices.d.ts +1 -1
- package/dist/data/devices.js +9 -12
- package/dist/data/embeddings.js +14 -11
- package/dist/data/files/file-read-stream.d.ts +2 -2
- package/dist/data/files/file-read-stream.js +23 -14
- package/dist/data/files/file-write-stream.d.ts +2 -2
- package/dist/data/files/file-write-stream.js +8 -8
- package/dist/data/files/file.types.d.ts +2 -2
- package/dist/data/files/file.types.js +17 -11
- package/dist/data/files/files.d.ts +6 -6
- package/dist/data/files/files.js +17 -19
- package/dist/data/files/files.test.js +213 -214
- package/dist/data/files/index.d.ts +4 -4
- package/dist/data/files/index.js +4 -4
- package/dist/data/group-member-roles.js +2 -2
- package/dist/data/group-members.d.ts +5 -5
- package/dist/data/group-members.js +27 -18
- package/dist/data/group-members.test.js +73 -73
- package/dist/data/group-permissions.d.ts +3 -3
- package/dist/data/group-permissions.js +13 -11
- package/dist/data/group-share.d.ts +2 -2
- package/dist/data/group-share.js +29 -24
- package/dist/data/groups.d.ts +4 -4
- package/dist/data/groups.js +27 -19
- package/dist/data/groups.test.js +44 -44
- package/dist/data/index.d.ts +6 -6
- package/dist/data/index.js +6 -6
- package/dist/data/knowledge/peer-types.js +9 -9
- package/dist/data/messages.d.ts +5 -5
- package/dist/data/messages.js +43 -30
- package/dist/data/orm/client-proxy.data-source.d.ts +4 -4
- package/dist/data/orm/client-proxy.data-source.js +10 -12
- package/dist/data/orm/cursor.d.ts +1 -1
- package/dist/data/orm/cursor.js +2 -2
- package/dist/data/orm/cursor.test.js +92 -93
- package/dist/data/orm/data-query.d.ts +3 -3
- package/dist/data/orm/data-query.js +24 -18
- package/dist/data/orm/data-query.mongo.d.ts +1 -1
- package/dist/data/orm/data-query.mongo.js +49 -51
- package/dist/data/orm/data-query.mongo.test.js +173 -204
- package/dist/data/orm/data-query.sqlite.d.ts +1 -1
- package/dist/data/orm/data-query.sqlite.js +84 -73
- package/dist/data/orm/data-query.sqlite.test.js +164 -176
- package/dist/data/orm/data-query.test.js +216 -224
- package/dist/data/orm/decorators.js +3 -3
- package/dist/data/orm/dependency-injection.test.js +53 -56
- package/dist/data/orm/doc.d.ts +4 -4
- package/dist/data/orm/doc.js +17 -21
- package/dist/data/orm/event-registry.d.ts +1 -1
- package/dist/data/orm/event-registry.test.js +16 -16
- package/dist/data/orm/factory.d.ts +2 -2
- package/dist/data/orm/factory.js +33 -33
- package/dist/data/orm/index.d.ts +10 -10
- package/dist/data/orm/index.js +10 -10
- package/dist/data/orm/multi-cursors.d.ts +1 -1
- package/dist/data/orm/multi-cursors.js +6 -6
- package/dist/data/orm/multi-cursors.test.js +152 -144
- package/dist/data/orm/sql.data-source.d.ts +7 -7
- package/dist/data/orm/sql.data-source.js +88 -93
- package/dist/data/orm/sql.data-source.test.js +109 -101
- package/dist/data/orm/subscribable.data-source.d.ts +4 -4
- package/dist/data/orm/subscribable.data-source.js +5 -5
- package/dist/data/orm/table-container-events.test.js +34 -26
- package/dist/data/orm/table-container.d.ts +6 -6
- package/dist/data/orm/table-container.js +33 -21
- package/dist/data/orm/table-container.test.js +64 -53
- package/dist/data/orm/table-definitions.system.d.ts +3 -3
- package/dist/data/orm/table-definitions.system.js +3 -3
- package/dist/data/orm/table-definitions.type.d.ts +5 -5
- package/dist/data/orm/table-dependencies.d.ts +2 -2
- package/dist/data/orm/table.d.ts +5 -5
- package/dist/data/orm/table.event-source.test.js +105 -115
- package/dist/data/orm/table.js +35 -34
- package/dist/data/orm/types.d.ts +3 -3
- package/dist/data/orm/types.js +26 -25
- package/dist/data/orm/types.test.js +166 -92
- package/dist/data/package-permissions.d.ts +1 -1
- package/dist/data/package-permissions.js +2 -2
- package/dist/data/package-version-permissions.d.ts +1 -1
- package/dist/data/package-version-permissions.js +2 -2
- package/dist/data/package-versions.d.ts +9 -9
- package/dist/data/package-versions.js +47 -33
- package/dist/data/packages.d.ts +2 -2
- package/dist/data/packages.js +36 -18
- package/dist/data/packages.utils.d.ts +2 -2
- package/dist/data/packages.utils.js +4 -4
- package/dist/data/persistent-vars.d.ts +15 -15
- package/dist/data/persistent-vars.js +165 -154
- package/dist/data/table-definitions-table.d.ts +5 -5
- package/dist/data/table-definitions-table.js +13 -12
- package/dist/data/tool-tests.js +6 -6
- package/dist/data/tools.js +29 -19
- package/dist/data/user-permissions.d.ts +1 -1
- package/dist/data/user-permissions.js +5 -5
- package/dist/data/user-permissions.test.js +90 -88
- package/dist/data/user-trust-levels.js +10 -10
- package/dist/data/users.d.ts +4 -4
- package/dist/data/users.js +16 -15
- package/dist/data/voice-messages.d.ts +2 -2
- package/dist/data/voice-messages.js +13 -13
- package/dist/data/welcome-modal.pvar.js +3 -1
- package/dist/data/workflow-logs.js +26 -18
- package/dist/data/workflow-runs.d.ts +6 -6
- package/dist/data/workflow-runs.js +70 -44
- package/dist/data/workflows.d.ts +2 -2
- package/dist/data/workflows.js +7 -9
- package/dist/device/binary-peer-connection-v2.d.ts +7 -7
- package/dist/device/binary-peer-connection-v2.js +32 -28
- package/dist/device/binary-peer-connection-v2.test.js +80 -67
- package/dist/device/binary-peer-connection.d.ts +7 -7
- package/dist/device/binary-peer-connection.js +29 -28
- package/dist/device/binary-peer-connection.test.js +35 -31
- package/dist/device/connection.d.ts +5 -5
- package/dist/device/connection.js +59 -48
- package/dist/device/connection.test.js +74 -68
- package/dist/device/device-election.d.ts +2 -2
- package/dist/device/device-election.js +25 -20
- package/dist/device/device-election.test.js +35 -36
- package/dist/device/device.d.ts +2 -2
- package/dist/device/device.js +10 -4
- package/dist/device/device.test.js +16 -17
- package/dist/device/get-trust-level-fn.d.ts +2 -2
- package/dist/device/get-trust-level-fn.js +22 -11
- package/dist/device/get-trust-level-fn.test.js +58 -58
- package/dist/device/socket-io-binary-peer.d.ts +1 -1
- package/dist/device/socket-io-binary-peer.js +16 -13
- package/dist/device/socket.type.d.ts +2 -2
- package/dist/device/streamed-socket.d.ts +2 -2
- package/dist/device/streamed-socket.js +8 -8
- package/dist/device/streamed-socket.test.js +40 -40
- package/dist/device/tx-encoding.test.js +77 -77
- package/dist/events.d.ts +1 -1
- package/dist/events.js +5 -2
- package/dist/group-invite/group-invite.js +110 -19
- package/dist/group-invite/group-invite.pvars.d.ts +2 -2
- package/dist/group-invite/group-invite.pvars.js +21 -13
- package/dist/group-invite/group-invite.types.d.ts +1 -1
- package/dist/group-invite/index.d.ts +3 -3
- package/dist/group-invite/index.js +1 -1
- package/dist/index.d.ts +25 -24
- package/dist/index.js +30 -25
- package/dist/keys.d.ts +3 -3
- package/dist/keys.js +31 -30
- package/dist/keys.test.js +69 -61
- package/dist/logging/console-logger.d.ts +1 -1
- package/dist/logging/console-logger.js +35 -40
- package/dist/logging/console-logger.test.js +115 -115
- package/dist/logging/console-logs.table.d.ts +3 -3
- package/dist/logging/console-logs.table.js +28 -23
- package/dist/mentions.js +16 -12
- package/dist/observable.d.ts +2 -2
- package/dist/observable.js +15 -9
- package/dist/observable.test.js +47 -47
- package/dist/package-loader/get-require.js +3 -4
- package/dist/package-loader/package-loader.d.ts +2 -2
- package/dist/package-loader/package-loader.js +52 -34
- package/dist/peers-ui/peers-ui.d.ts +2 -2
- package/dist/peers-ui/peers-ui.js +2 -4
- package/dist/peers-ui/peers-ui.types.d.ts +3 -3
- package/dist/peers-ui/peers-ui.types.js +0 -1
- package/dist/rpc-types.d.ts +61 -59
- package/dist/rpc-types.js +61 -55
- package/dist/serial-json.d.ts +1 -1
- package/dist/serial-json.js +50 -43
- package/dist/serial-json.test.js +22 -22
- package/dist/system-ids.js +8 -8
- package/dist/tools/index.d.ts +1 -1
- package/dist/tools/tools-factory.d.ts +1 -1
- package/dist/tools/tools-factory.js +2 -2
- package/dist/types/assistant-runner-args.d.ts +3 -3
- package/dist/types/peer-device.d.ts +1 -1
- package/dist/types/peers-package.d.ts +3 -3
- package/dist/types/workflow-logger.d.ts +1 -1
- package/dist/types/workflow-run-context.d.ts +4 -4
- package/dist/types/workflow.d.ts +4 -4
- package/dist/types/workflow.js +27 -14
- package/dist/types/zod-types.d.ts +2 -1
- package/dist/types/zod-types.js +9 -3
- package/dist/user-connect/connection-code.d.ts +1 -1
- package/dist/user-connect/connection-code.js +7 -7
- package/dist/user-connect/connection-code.test.js +106 -106
- package/dist/user-connect/index.d.ts +3 -3
- package/dist/user-connect/index.js +1 -1
- package/dist/user-connect/user-connect.pvars.js +13 -11
- package/dist/user-connect/user-connect.types.d.ts +3 -3
- package/dist/users.query.d.ts +2 -2
- package/dist/users.query.js +40 -30
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +34 -32
- package/dist/utils.test.js +12 -8
- package/dist/workflow-log-formatter.d.ts +1 -1
- package/dist/workflow-log-formatter.js +17 -18
- package/package.json +14 -8
|
@@ -3,17 +3,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
const SQLiteDB = require("better-sqlite3");
|
|
4
4
|
const lodash_1 = require("lodash");
|
|
5
5
|
const zod_1 = require("zod");
|
|
6
|
-
const utils_1 = require("../../utils");
|
|
7
6
|
const field_type_1 = require("../../types/field-type");
|
|
8
7
|
const zod_types_1 = require("../../types/zod-types");
|
|
8
|
+
const utils_1 = require("../../utils");
|
|
9
9
|
const sql_data_source_1 = require("./sql.data-source");
|
|
10
10
|
const types_1 = require("./types");
|
|
11
11
|
class DBHarness {
|
|
12
12
|
_db = null;
|
|
13
13
|
get db() {
|
|
14
14
|
if (!this._db) {
|
|
15
|
-
this._db = new SQLiteDB(
|
|
16
|
-
this._db.pragma(
|
|
15
|
+
this._db = new SQLiteDB(":memory:");
|
|
16
|
+
this._db.pragma("journal_mode = WAL");
|
|
17
17
|
}
|
|
18
18
|
return this._db;
|
|
19
19
|
}
|
|
@@ -32,52 +32,52 @@ class DBHarness {
|
|
|
32
32
|
this._db = null;
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
-
|
|
36
|
-
describe(
|
|
35
|
+
const db = new DBHarness();
|
|
36
|
+
describe("table", () => {
|
|
37
37
|
const fiveMinutesMs = 5 * 60 * 1000; // 5 minutes in milliseconds
|
|
38
38
|
jest.setTimeout(fiveMinutesMs);
|
|
39
39
|
afterAll(async () => {
|
|
40
40
|
db.db?.close();
|
|
41
41
|
});
|
|
42
|
-
describe(
|
|
42
|
+
describe("when type is defined in code", () => {
|
|
43
43
|
const taskSchema = zod_1.z.object({
|
|
44
44
|
taskId: zod_types_1.zodPeerId.default(() => (0, utils_1.newid)()),
|
|
45
45
|
title: zod_1.z.string(),
|
|
46
|
-
body: zod_1.z.string().default(
|
|
46
|
+
body: zod_1.z.string().default(""),
|
|
47
47
|
dueDate: zod_1.z.date().optional(),
|
|
48
48
|
completeDT: zod_1.z.date().optional(),
|
|
49
49
|
parentTaskId: zod_types_1.zodPeerId.optional(),
|
|
50
50
|
});
|
|
51
51
|
const taskFields = (0, types_1.schemaToFields)(taskSchema);
|
|
52
52
|
const tasksTableType = {
|
|
53
|
-
name:
|
|
54
|
-
description:
|
|
55
|
-
primaryKeyName:
|
|
53
|
+
name: "test_tasks_code_driven",
|
|
54
|
+
description: "Task",
|
|
55
|
+
primaryKeyName: "taskId",
|
|
56
56
|
fields: taskFields,
|
|
57
57
|
indexes: [
|
|
58
|
-
{ fields: [
|
|
59
|
-
{ unique: true, fields: [
|
|
58
|
+
{ fields: ["title"] },
|
|
59
|
+
{ unique: true, fields: ["taskId", { name: "parentTaskId", order: "DESC" }] },
|
|
60
60
|
],
|
|
61
61
|
};
|
|
62
62
|
const TasksTable = new sql_data_source_1.SQLDataSource(db, tasksTableType);
|
|
63
63
|
beforeAll(async () => {
|
|
64
64
|
await TasksTable.dropTableIfExists();
|
|
65
65
|
});
|
|
66
|
-
it(
|
|
66
|
+
it("should do compile time checks and runtime typechecks", async () => {
|
|
67
67
|
const badSavePromise = TasksTable.save({
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
body:
|
|
68
|
+
id: "test",
|
|
69
|
+
title: 1,
|
|
70
|
+
body: "This is a test task",
|
|
71
71
|
dueDate: new Date(),
|
|
72
72
|
});
|
|
73
73
|
// await expect(badSavePromise).rejects.toThrow(`SQLITE_ERROR: table ${tableName} has no column named id`);
|
|
74
74
|
await expect(badSavePromise).rejects.toThrow(/validation.*failed.*title.*expected string, received number/ims);
|
|
75
75
|
});
|
|
76
|
-
it(
|
|
76
|
+
it("should do all CRUD operations", async () => {
|
|
77
77
|
const task1 = {
|
|
78
78
|
taskId: (0, utils_1.newid)(),
|
|
79
|
-
title:
|
|
80
|
-
body:
|
|
79
|
+
title: "Test Task",
|
|
80
|
+
body: "This is a test task",
|
|
81
81
|
dueDate: new Date(),
|
|
82
82
|
};
|
|
83
83
|
// CREATE
|
|
@@ -86,7 +86,7 @@ describe('table', () => {
|
|
|
86
86
|
let task1Db = await TasksTable.get(task1.taskId);
|
|
87
87
|
expect(task1Db).toEqual(task1);
|
|
88
88
|
// UPDATE
|
|
89
|
-
task1.title =
|
|
89
|
+
task1.title = "Updated Task";
|
|
90
90
|
await TasksTable.save(task1);
|
|
91
91
|
task1Db = await TasksTable.get(task1.taskId);
|
|
92
92
|
expect(task1Db).toEqual(task1);
|
|
@@ -95,24 +95,24 @@ describe('table', () => {
|
|
|
95
95
|
task1Db = await TasksTable.get(task1.taskId);
|
|
96
96
|
expect(task1Db).toBeUndefined();
|
|
97
97
|
});
|
|
98
|
-
it(
|
|
98
|
+
it("should enable type-checked queries", async () => {
|
|
99
99
|
const task1 = {
|
|
100
100
|
taskId: (0, utils_1.newid)(),
|
|
101
|
-
title:
|
|
102
|
-
body:
|
|
101
|
+
title: "Test Task",
|
|
102
|
+
body: "This is a test task",
|
|
103
103
|
dueDate: new Date(),
|
|
104
104
|
};
|
|
105
105
|
// CREATE
|
|
106
106
|
await TasksTable.save(task1);
|
|
107
107
|
// query
|
|
108
|
-
const results = await TasksTable.list({ title:
|
|
108
|
+
const results = await TasksTable.list({ title: "Test Task" });
|
|
109
109
|
expect(results[0]).toEqual(task1);
|
|
110
|
-
// // @ts-expect-error - making sure type checking is working
|
|
110
|
+
// // @ts-expect-error - making sure type checking is working
|
|
111
111
|
// const badQueryResults = await TasksTable.list({ id: 'test' });
|
|
112
112
|
// // note that sqlite does not check that columns exist, so this query succeeds with no matches
|
|
113
113
|
// expect(badQueryResults).toEqual([]);
|
|
114
114
|
// @ts-expect-error - making sure type checking is working
|
|
115
|
-
const badQueryPromise = TasksTable.list({ id:
|
|
115
|
+
const badQueryPromise = TasksTable.list({ id: "test" });
|
|
116
116
|
// SQLite error messages vary by version - some throw "no such column", others succeed with empty results
|
|
117
117
|
// The important thing is that TypeScript catches this at compile time with @ts-expect-error
|
|
118
118
|
// await expect(badQueryPromise).rejects.toThrow(`SQLITE_ERROR: table ${tableName} has no column named id`);
|
|
@@ -130,35 +130,35 @@ describe('table', () => {
|
|
|
130
130
|
expect(error.message).toMatch(/id|column/i);
|
|
131
131
|
}
|
|
132
132
|
});
|
|
133
|
-
it(
|
|
133
|
+
it("should validate the data before saving", async () => {
|
|
134
134
|
// test validates a bad date
|
|
135
135
|
{
|
|
136
136
|
const badTask = {
|
|
137
137
|
taskId: (0, utils_1.newid)(),
|
|
138
|
-
title:
|
|
139
|
-
body:
|
|
140
|
-
dueDate:
|
|
138
|
+
title: "Test Task",
|
|
139
|
+
body: "This is a test task",
|
|
140
|
+
dueDate: "not a date",
|
|
141
141
|
};
|
|
142
142
|
const badSavePromise = TasksTable.save(badTask);
|
|
143
|
-
await expect(badSavePromise).rejects.toThrow(
|
|
143
|
+
await expect(badSavePromise).rejects.toThrow("Expected date, received string");
|
|
144
144
|
}
|
|
145
145
|
// test validates a bad id
|
|
146
146
|
{
|
|
147
147
|
const badTask = {
|
|
148
|
-
taskId:
|
|
149
|
-
title:
|
|
150
|
-
body:
|
|
148
|
+
taskId: "not an id",
|
|
149
|
+
title: "Test Task",
|
|
150
|
+
body: "This is a test task",
|
|
151
151
|
dueDate: new Date(),
|
|
152
152
|
};
|
|
153
153
|
const badSavePromise = TasksTable.save(badTask);
|
|
154
|
-
await expect(badSavePromise).rejects.toThrow(
|
|
154
|
+
await expect(badSavePromise).rejects.toThrow("Invalid id");
|
|
155
155
|
}
|
|
156
156
|
// add task to database
|
|
157
157
|
const existingTaskId = (0, utils_1.newid)();
|
|
158
158
|
const task1 = {
|
|
159
159
|
taskId: existingTaskId,
|
|
160
|
-
title:
|
|
161
|
-
body:
|
|
160
|
+
title: "Test Task",
|
|
161
|
+
body: "This is a test task",
|
|
162
162
|
dueDate: new Date(),
|
|
163
163
|
};
|
|
164
164
|
await TasksTable.save(task1);
|
|
@@ -170,8 +170,8 @@ describe('table', () => {
|
|
|
170
170
|
expect(existingRecord?.taskId).toBe(existingTaskId);
|
|
171
171
|
const badTask = {
|
|
172
172
|
taskId: existingTaskId,
|
|
173
|
-
title:
|
|
174
|
-
body:
|
|
173
|
+
title: "Test Task",
|
|
174
|
+
body: "This is a test task",
|
|
175
175
|
dueDate: new Date(),
|
|
176
176
|
};
|
|
177
177
|
// Try-catch approach to handle environments where UNIQUE constraint might not throw
|
|
@@ -180,7 +180,7 @@ describe('table', () => {
|
|
|
180
180
|
await TasksTable.insert(badTask);
|
|
181
181
|
// If we get here without throwing, the test should fail
|
|
182
182
|
// This can happen in some SQLite configurations that don't enforce UNIQUE constraints properly
|
|
183
|
-
fail(
|
|
183
|
+
fail("Expected insert to throw UNIQUE constraint error, but it succeeded");
|
|
184
184
|
}
|
|
185
185
|
catch (error) {
|
|
186
186
|
// Verify the error is related to UNIQUE constraint or primary key
|
|
@@ -191,18 +191,18 @@ describe('table', () => {
|
|
|
191
191
|
{
|
|
192
192
|
const badTask = {
|
|
193
193
|
taskId: existingTaskId,
|
|
194
|
-
title:
|
|
195
|
-
body:
|
|
196
|
-
dueDate:
|
|
194
|
+
title: "Test Task",
|
|
195
|
+
body: "This is a test task",
|
|
196
|
+
dueDate: "not a date",
|
|
197
197
|
};
|
|
198
198
|
const badSavePromise = TasksTable.update(badTask);
|
|
199
|
-
await expect(badSavePromise).rejects.toThrow(
|
|
199
|
+
await expect(badSavePromise).rejects.toThrow("Expected date, received string");
|
|
200
200
|
}
|
|
201
201
|
});
|
|
202
|
-
it(
|
|
202
|
+
it("should allow initializing a record with only part of the data", async () => {
|
|
203
203
|
const newTask = TasksTable.initRecord();
|
|
204
204
|
expect(() => TasksTable.schema.parse(newTask)).toThrow();
|
|
205
|
-
newTask.title =
|
|
205
|
+
newTask.title = "Test Task";
|
|
206
206
|
expect(() => TasksTable.schema.parse(newTask)).not.toThrow();
|
|
207
207
|
});
|
|
208
208
|
afterAll(async () => {
|
|
@@ -210,39 +210,39 @@ describe('table', () => {
|
|
|
210
210
|
await TasksTable.db.close();
|
|
211
211
|
});
|
|
212
212
|
});
|
|
213
|
-
describe(
|
|
213
|
+
describe("when type is loaded from database", () => {
|
|
214
214
|
const tasksTableType = {
|
|
215
|
-
name:
|
|
216
|
-
description:
|
|
217
|
-
primaryKeyName:
|
|
215
|
+
name: "test_tasks_data_driven",
|
|
216
|
+
description: "Task",
|
|
217
|
+
primaryKeyName: "taskId",
|
|
218
218
|
fields: [
|
|
219
|
-
{ name:
|
|
220
|
-
{ name:
|
|
221
|
-
{ name:
|
|
222
|
-
{ name:
|
|
223
|
-
{ name:
|
|
224
|
-
{ name:
|
|
219
|
+
{ name: "taskId", description: "Task ID", type: field_type_1.FieldType.id },
|
|
220
|
+
{ name: "title", description: "Title", type: field_type_1.FieldType.string },
|
|
221
|
+
{ name: "body", description: "Body", type: field_type_1.FieldType.string },
|
|
222
|
+
{ name: "dueDate", description: "Due Date", type: field_type_1.FieldType.Date, optional: true },
|
|
223
|
+
{ name: "completeDT", description: "Complete Date", type: field_type_1.FieldType.Date, optional: true },
|
|
224
|
+
{ name: "parentTaskId", description: "Parent Task ID", type: field_type_1.FieldType.id, optional: true },
|
|
225
225
|
],
|
|
226
226
|
};
|
|
227
227
|
const TasksTable = new sql_data_source_1.SQLDataSource(db, tasksTableType);
|
|
228
228
|
beforeAll(async () => {
|
|
229
229
|
await TasksTable.dropTableIfExists();
|
|
230
230
|
});
|
|
231
|
-
it(
|
|
231
|
+
it("should do runtime typechecks", async () => {
|
|
232
232
|
const badSavePromise = TasksTable.save({
|
|
233
|
-
id:
|
|
233
|
+
id: "test",
|
|
234
234
|
title: 1,
|
|
235
|
-
body:
|
|
235
|
+
body: "This is a test task",
|
|
236
236
|
dueDate: new Date(),
|
|
237
237
|
});
|
|
238
238
|
// await expect(badSavePromise).rejects.toThrow(`SQLITE_ERROR: table ${tableName} has no column named id`);
|
|
239
239
|
await expect(badSavePromise).rejects.toThrow(/validation.*failed.*title.*expected string, received number/ims);
|
|
240
240
|
});
|
|
241
|
-
it(
|
|
241
|
+
it("should do all CRUD operations", async () => {
|
|
242
242
|
const task1 = {
|
|
243
243
|
taskId: (0, utils_1.newid)(),
|
|
244
|
-
title:
|
|
245
|
-
body:
|
|
244
|
+
title: "Test Task",
|
|
245
|
+
body: "This is a test task",
|
|
246
246
|
dueDate: new Date(),
|
|
247
247
|
};
|
|
248
248
|
// CREATE
|
|
@@ -251,7 +251,7 @@ describe('table', () => {
|
|
|
251
251
|
let task1Db = await TasksTable.get(task1.taskId);
|
|
252
252
|
expect(task1Db).toEqual(task1);
|
|
253
253
|
// UPDATE
|
|
254
|
-
task1.title =
|
|
254
|
+
task1.title = "Updated Task";
|
|
255
255
|
await TasksTable.save(task1);
|
|
256
256
|
task1Db = await TasksTable.get(task1.taskId);
|
|
257
257
|
expect(task1Db).toEqual(task1);
|
|
@@ -265,34 +265,37 @@ describe('table', () => {
|
|
|
265
265
|
await TasksTable.db.close();
|
|
266
266
|
});
|
|
267
267
|
});
|
|
268
|
-
describe(
|
|
268
|
+
describe("when the schema has changed", () => {
|
|
269
269
|
const notesTableTypeV1 = {
|
|
270
|
-
name:
|
|
271
|
-
description:
|
|
272
|
-
primaryKeyName:
|
|
270
|
+
name: "test_table_notes",
|
|
271
|
+
description: "Notes",
|
|
272
|
+
primaryKeyName: "entryId",
|
|
273
273
|
fields: [
|
|
274
|
-
{ name:
|
|
275
|
-
{ name:
|
|
276
|
-
{ name:
|
|
277
|
-
],
|
|
278
|
-
indexes: [
|
|
279
|
-
{ fields: ['title'] },
|
|
274
|
+
{ name: "entryId", description: "Entry ID", type: field_type_1.FieldType.id },
|
|
275
|
+
{ name: "title", description: "Title", type: field_type_1.FieldType.string },
|
|
276
|
+
{ name: "body", description: "Body", type: field_type_1.FieldType.string, defaultValue: "" },
|
|
280
277
|
],
|
|
278
|
+
indexes: [{ fields: ["title"] }],
|
|
281
279
|
};
|
|
282
280
|
const NotesTableV1 = new sql_data_source_1.SQLDataSource(db, notesTableTypeV1);
|
|
283
281
|
beforeAll(async () => {
|
|
284
282
|
await NotesTableV1.dropTableIfExists();
|
|
285
283
|
await NotesTableV1.list();
|
|
286
284
|
});
|
|
287
|
-
it(
|
|
285
|
+
it("should not update table if already up to date", async () => {
|
|
288
286
|
const updated = await NotesTableV1.initTable(true);
|
|
289
287
|
expect(updated).toBe(false);
|
|
290
288
|
});
|
|
291
|
-
it(
|
|
292
|
-
const v1Note = await NotesTableV1.insert({ title:
|
|
289
|
+
it("should detect column changes and modify tables to match", async () => {
|
|
290
|
+
const v1Note = await NotesTableV1.insert({ title: "Test Note", body: "This is a test note" });
|
|
293
291
|
// add optional number column
|
|
294
292
|
const notesTableTypeV2 = (0, lodash_1.cloneDeep)(notesTableTypeV1);
|
|
295
|
-
notesTableTypeV2.fields.push({
|
|
293
|
+
notesTableTypeV2.fields.push({
|
|
294
|
+
name: "priority",
|
|
295
|
+
description: "Priority of note",
|
|
296
|
+
type: field_type_1.FieldType.number,
|
|
297
|
+
optional: true,
|
|
298
|
+
});
|
|
296
299
|
const NotesTableV2 = new sql_data_source_1.SQLDataSource(db, notesTableTypeV2);
|
|
297
300
|
const updatedToV2 = await NotesTableV2.initTable(true);
|
|
298
301
|
expect(updatedToV2).toBe(true);
|
|
@@ -300,12 +303,17 @@ describe('table', () => {
|
|
|
300
303
|
expect(v2Note).toEqual({ ...v1Note });
|
|
301
304
|
// add required date column
|
|
302
305
|
const notesTableTypeV3 = (0, lodash_1.cloneDeep)(notesTableTypeV2);
|
|
303
|
-
notesTableTypeV3.fields.push({
|
|
306
|
+
notesTableTypeV3.fields.push({
|
|
307
|
+
name: "modified",
|
|
308
|
+
description: "Last time this was modified",
|
|
309
|
+
type: field_type_1.FieldType.Date,
|
|
310
|
+
defaultValue: () => new Date(),
|
|
311
|
+
});
|
|
304
312
|
const NotesTableV3 = new sql_data_source_1.SQLDataSource(db, notesTableTypeV3);
|
|
305
313
|
const updatedToV3 = await NotesTableV3.initTable(true);
|
|
306
314
|
expect(updatedToV3).toBe(true);
|
|
307
315
|
const v3Note = await NotesTableV3.get(v1Note.entryId);
|
|
308
|
-
expect(v3Note).toEqual({ ...v1Note, modified: v3Note
|
|
316
|
+
expect(v3Note).toEqual({ ...v1Note, modified: v3Note?.modified });
|
|
309
317
|
// remove column
|
|
310
318
|
const notesTableTypeV4 = (0, lodash_1.cloneDeep)(notesTableTypeV3);
|
|
311
319
|
notesTableTypeV4.fields.pop();
|
|
@@ -326,9 +334,9 @@ describe('table', () => {
|
|
|
326
334
|
const updatedToV5Again = await NotesTableV5.initTable(true);
|
|
327
335
|
expect(updatedToV5Again).toBe(false);
|
|
328
336
|
});
|
|
329
|
-
it(
|
|
337
|
+
it("should detect and change column indexes", async () => {
|
|
330
338
|
const notesTableTypeV1Indexes = (0, lodash_1.cloneDeep)(notesTableTypeV1);
|
|
331
|
-
notesTableTypeV1Indexes.name +=
|
|
339
|
+
notesTableTypeV1Indexes.name += "_indexes";
|
|
332
340
|
const NotesTableV1 = new sql_data_source_1.SQLDataSource(db, notesTableTypeV1Indexes);
|
|
333
341
|
await NotesTableV1.dropTableIfExists();
|
|
334
342
|
await NotesTableV1.initTable(true);
|
|
@@ -345,26 +353,26 @@ describe('table', () => {
|
|
|
345
353
|
expect(indexesV2).toHaveLength(1);
|
|
346
354
|
});
|
|
347
355
|
});
|
|
348
|
-
describe(
|
|
356
|
+
describe("when the field type is `object`", () => {
|
|
349
357
|
const tableType = {
|
|
350
|
-
name:
|
|
351
|
-
description:
|
|
352
|
-
primaryKeyName:
|
|
358
|
+
name: "test_table_objects",
|
|
359
|
+
description: "Objects",
|
|
360
|
+
primaryKeyName: "objectId",
|
|
353
361
|
fields: [
|
|
354
|
-
{ name:
|
|
355
|
-
{ name:
|
|
356
|
-
{ name:
|
|
362
|
+
{ name: "objectId", description: "Object ID", type: field_type_1.FieldType.id },
|
|
363
|
+
{ name: "name", description: "Name", type: field_type_1.FieldType.string },
|
|
364
|
+
{ name: "data", description: "Data", type: field_type_1.FieldType.object },
|
|
357
365
|
],
|
|
358
366
|
};
|
|
359
367
|
const ObjectsTable = new sql_data_source_1.SQLDataSource(db, tableType);
|
|
360
368
|
beforeAll(async () => {
|
|
361
369
|
await ObjectsTable.dropTableIfExists();
|
|
362
370
|
});
|
|
363
|
-
it(
|
|
371
|
+
it("should store objects as JSON strings", async () => {
|
|
364
372
|
const obj = {
|
|
365
373
|
objectId: (0, utils_1.newid)(),
|
|
366
|
-
name:
|
|
367
|
-
data: { test:
|
|
374
|
+
name: "Test Object",
|
|
375
|
+
data: { test: "data" },
|
|
368
376
|
};
|
|
369
377
|
await ObjectsTable.save(obj);
|
|
370
378
|
const objDb = await ObjectsTable.get(obj.objectId);
|
|
@@ -375,26 +383,26 @@ describe('table', () => {
|
|
|
375
383
|
await ObjectsTable.db.close();
|
|
376
384
|
});
|
|
377
385
|
});
|
|
378
|
-
describe(
|
|
386
|
+
describe("when the field type is an array of primitives", () => {
|
|
379
387
|
const tableType = {
|
|
380
|
-
name:
|
|
381
|
-
description:
|
|
382
|
-
primaryKeyName:
|
|
388
|
+
name: "test_table_arrays",
|
|
389
|
+
description: "Arrays",
|
|
390
|
+
primaryKeyName: "arrayId",
|
|
383
391
|
fields: [
|
|
384
|
-
{ name:
|
|
385
|
-
{ name:
|
|
386
|
-
{ name:
|
|
392
|
+
{ name: "arrayId", description: "Array ID", type: field_type_1.FieldType.id },
|
|
393
|
+
{ name: "name", description: "Name", type: field_type_1.FieldType.string },
|
|
394
|
+
{ name: "data", description: "Data", type: field_type_1.FieldType.string, isArray: true },
|
|
387
395
|
],
|
|
388
396
|
};
|
|
389
397
|
const ArraysTable = new sql_data_source_1.SQLDataSource(db, tableType);
|
|
390
398
|
beforeAll(async () => {
|
|
391
399
|
await ArraysTable.dropTableIfExists();
|
|
392
400
|
});
|
|
393
|
-
it(
|
|
401
|
+
it("should store arrays as JSON strings and automatically rehydrate them", async () => {
|
|
394
402
|
const obj = {
|
|
395
403
|
arrayId: (0, utils_1.newid)(),
|
|
396
|
-
name:
|
|
397
|
-
data: [
|
|
404
|
+
name: "Test Array",
|
|
405
|
+
data: ["test", "data"],
|
|
398
406
|
};
|
|
399
407
|
await ArraysTable.save(obj);
|
|
400
408
|
const objDb = await ArraysTable.get(obj.arrayId);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { Emitter, Event } from "../../events";
|
|
2
|
-
import { DataFilter, ICursorIterable, IDataQueryParams, IDataSource } from "./data-query";
|
|
1
|
+
import { Emitter, type Event } from "../../events";
|
|
2
|
+
import { type DataFilter, type ICursorIterable, type IDataQueryParams, type IDataSource } from "./data-query";
|
|
3
3
|
export interface IDataChangedEvent<T> {
|
|
4
4
|
dataObject: T;
|
|
5
|
-
op:
|
|
6
|
-
source:
|
|
5
|
+
op: "insert" | "update" | "delete";
|
|
6
|
+
source: "local" | "remote";
|
|
7
7
|
}
|
|
8
8
|
export declare class SubscribableDataSource<T extends {
|
|
9
9
|
[key: string]: any;
|
|
@@ -15,7 +15,7 @@ class SubscribableDataSource {
|
|
|
15
15
|
this.tableName = dataSource.tableName;
|
|
16
16
|
this.primaryKeyName = dataSource.primaryKeyName;
|
|
17
17
|
// ensure different data source emitters for the same table have different names
|
|
18
|
-
|
|
18
|
+
const eventNameCount = eventNameCounts.get(this.tableName) || 0;
|
|
19
19
|
eventNameCounts.set(this.tableName, eventNameCount + 1);
|
|
20
20
|
const eventName = `SubscribableDataSource_${this.tableName}_DataChanged_${eventNameCount}`;
|
|
21
21
|
this.dataChangedEmitter = new events_1.Emitter(eventName);
|
|
@@ -51,22 +51,22 @@ class SubscribableDataSource {
|
|
|
51
51
|
}
|
|
52
52
|
async insert(record) {
|
|
53
53
|
record = await this.dataSource.insert(record);
|
|
54
|
-
this.dataChangedEmitter.emit({ dataObject: record, op:
|
|
54
|
+
this.dataChangedEmitter.emit({ dataObject: record, op: "insert", source: "local" });
|
|
55
55
|
return record;
|
|
56
56
|
}
|
|
57
57
|
async update(record) {
|
|
58
58
|
record = await this.dataSource.update(record);
|
|
59
|
-
this.dataChangedEmitter.emit({ dataObject: record, op:
|
|
59
|
+
this.dataChangedEmitter.emit({ dataObject: record, op: "update", source: "local" });
|
|
60
60
|
return record;
|
|
61
61
|
}
|
|
62
62
|
async delete(idOrRecord) {
|
|
63
|
-
const id = typeof idOrRecord ===
|
|
63
|
+
const id = typeof idOrRecord === "string" ? idOrRecord : idOrRecord[this.primaryKeyName];
|
|
64
64
|
const record = await this.get(id);
|
|
65
65
|
if (!record) {
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
68
68
|
await this.dataSource.delete(idOrRecord);
|
|
69
|
-
this.dataChangedEmitter.emit({ dataObject: record, op:
|
|
69
|
+
this.dataChangedEmitter.emit({ dataObject: record, op: "delete", source: "local" });
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
exports.SubscribableDataSource = SubscribableDataSource;
|
|
@@ -1,45 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const zod_1 = require("zod");
|
|
4
|
-
const table_container_1 = require("./table-container");
|
|
5
|
-
const event_registry_1 = require("./event-registry");
|
|
6
|
-
const client_proxy_data_source_1 = require("./client-proxy.data-source");
|
|
7
4
|
const field_type_1 = require("../../types/field-type");
|
|
8
|
-
|
|
5
|
+
const client_proxy_data_source_1 = require("./client-proxy.data-source");
|
|
6
|
+
const event_registry_1 = require("./event-registry");
|
|
7
|
+
const table_container_1 = require("./table-container");
|
|
8
|
+
describe("TableFactory Event Sharing", () => {
|
|
9
9
|
const testSchema = zod_1.z.object({
|
|
10
10
|
id: zod_1.z.string(),
|
|
11
11
|
name: zod_1.z.string(),
|
|
12
12
|
});
|
|
13
13
|
const testMetaData = {
|
|
14
|
-
name:
|
|
15
|
-
description:
|
|
16
|
-
primaryKeyName:
|
|
14
|
+
name: "TestTable",
|
|
15
|
+
description: "Test table for event sharing",
|
|
16
|
+
primaryKeyName: "id",
|
|
17
17
|
fields: [
|
|
18
|
-
{ name:
|
|
19
|
-
{ name:
|
|
18
|
+
{ name: "id", type: field_type_1.FieldType.string, optional: false },
|
|
19
|
+
{ name: "name", type: field_type_1.FieldType.string, optional: false },
|
|
20
20
|
],
|
|
21
21
|
};
|
|
22
|
-
it(
|
|
22
|
+
it("should share event emitters when using the same EventRegistry", () => {
|
|
23
23
|
// Create mock data context for event registry
|
|
24
24
|
const mockDataContext = {
|
|
25
|
-
dataContextId:
|
|
25
|
+
dataContextId: "test-context",
|
|
26
26
|
};
|
|
27
27
|
// Create shared event registry
|
|
28
28
|
const sharedRegistry = new event_registry_1.EventRegistry(mockDataContext);
|
|
29
29
|
// Create table factory function that uses shared registry
|
|
30
|
-
const tableFactory1 = jest
|
|
30
|
+
const tableFactory1 = jest
|
|
31
|
+
.fn()
|
|
32
|
+
.mockImplementation((metaData, schema, TableClass) => {
|
|
31
33
|
const deps = {
|
|
32
|
-
dataSource: new client_proxy_data_source_1.ClientProxyDataSource(metaData, schema || testSchema,
|
|
34
|
+
dataSource: new client_proxy_data_source_1.ClientProxyDataSource(metaData, schema || testSchema, "test-context"),
|
|
33
35
|
eventRegistry: sharedRegistry,
|
|
34
36
|
};
|
|
35
|
-
return new (TableClass || require(
|
|
37
|
+
return new (TableClass || require("./table").Table)(metaData, deps);
|
|
36
38
|
});
|
|
37
|
-
const tableFactory2 = jest
|
|
39
|
+
const tableFactory2 = jest
|
|
40
|
+
.fn()
|
|
41
|
+
.mockImplementation((metaData, schema, TableClass) => {
|
|
38
42
|
const deps = {
|
|
39
|
-
dataSource: new client_proxy_data_source_1.ClientProxyDataSource(metaData, schema || testSchema,
|
|
43
|
+
dataSource: new client_proxy_data_source_1.ClientProxyDataSource(metaData, schema || testSchema, "test-context"),
|
|
40
44
|
eventRegistry: sharedRegistry,
|
|
41
45
|
};
|
|
42
|
-
return new (TableClass || require(
|
|
46
|
+
return new (TableClass || require("./table").Table)(metaData, deps);
|
|
43
47
|
});
|
|
44
48
|
// Create two table containers with the same shared registry
|
|
45
49
|
const container1 = new table_container_1.TableContainer(tableFactory1);
|
|
@@ -54,27 +58,31 @@ describe('TableFactory Event Sharing', () => {
|
|
|
54
58
|
// Verify the shared registry only has one emitter for this table
|
|
55
59
|
expect(sharedRegistry.getEmitterCount()).toBe(1);
|
|
56
60
|
});
|
|
57
|
-
it(
|
|
61
|
+
it("should have separate event emitters when using different EventRegistry instances", () => {
|
|
58
62
|
// Create separate mock data contexts for event registries
|
|
59
|
-
const mockContext1 = { dataContextId:
|
|
60
|
-
const mockContext2 = { dataContextId:
|
|
63
|
+
const mockContext1 = { dataContextId: "test-context-1" };
|
|
64
|
+
const mockContext2 = { dataContextId: "test-context-2" };
|
|
61
65
|
// Create separate event registries
|
|
62
66
|
const registry1 = new event_registry_1.EventRegistry(mockContext1);
|
|
63
67
|
const registry2 = new event_registry_1.EventRegistry(mockContext2);
|
|
64
68
|
// Create table factory functions with different registries
|
|
65
|
-
const tableFactory1 = jest
|
|
69
|
+
const tableFactory1 = jest
|
|
70
|
+
.fn()
|
|
71
|
+
.mockImplementation((metaData, schema, TableClass) => {
|
|
66
72
|
const deps = {
|
|
67
|
-
dataSource: new client_proxy_data_source_1.ClientProxyDataSource(metaData, schema || testSchema,
|
|
73
|
+
dataSource: new client_proxy_data_source_1.ClientProxyDataSource(metaData, schema || testSchema, "test-context"),
|
|
68
74
|
eventRegistry: registry1,
|
|
69
75
|
};
|
|
70
|
-
return new (TableClass || require(
|
|
76
|
+
return new (TableClass || require("./table").Table)(metaData, deps);
|
|
71
77
|
});
|
|
72
|
-
const tableFactory2 = jest
|
|
78
|
+
const tableFactory2 = jest
|
|
79
|
+
.fn()
|
|
80
|
+
.mockImplementation((metaData, schema, TableClass) => {
|
|
73
81
|
const deps = {
|
|
74
|
-
dataSource: new client_proxy_data_source_1.ClientProxyDataSource(metaData, schema || testSchema,
|
|
82
|
+
dataSource: new client_proxy_data_source_1.ClientProxyDataSource(metaData, schema || testSchema, "test-context"),
|
|
75
83
|
eventRegistry: registry2,
|
|
76
84
|
};
|
|
77
|
-
return new (TableClass || require(
|
|
85
|
+
return new (TableClass || require("./table").Table)(metaData, deps);
|
|
78
86
|
});
|
|
79
87
|
// Create two table containers with different registries
|
|
80
88
|
const container1 = new table_container_1.TableContainer(tableFactory1);
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { z } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import { Table } from "./table";
|
|
3
|
+
import type { ITableDefinition, TableConstructor, TableFactory } from "./table-definitions.type";
|
|
4
|
+
import { type ITableMetaData } from "./types";
|
|
5
5
|
/**
|
|
6
6
|
* Compare two table definition versions and decide whether to update.
|
|
7
7
|
* @returns 'update' when incoming version is strictly newer, 'skip' otherwise.
|
|
8
8
|
* Logs an error if same version but different definitions (caller should bump versionNumber).
|
|
9
9
|
*/
|
|
10
|
-
export declare function checkVersionedUpdate(existingVersion: number, incomingVersion: number, existingMetaData: ITableMetaData, incomingMetaData: ITableMetaData):
|
|
10
|
+
export declare function checkVersionedUpdate(existingVersion: number, incomingVersion: number, existingMetaData: ITableMetaData, incomingMetaData: ITableMetaData): "update" | "skip";
|
|
11
11
|
export declare class TableContainer {
|
|
12
12
|
readonly tableFactory: TableFactory;
|
|
13
13
|
readonly groupId?: string | undefined;
|
|
@@ -67,6 +67,6 @@ export declare class TableContainer {
|
|
|
67
67
|
*
|
|
68
68
|
* This is primarily intended to be used by the peer-device sync operation which needs all
|
|
69
69
|
* tables to be able to apply changes correctly.
|
|
70
|
-
|
|
70
|
+
*/
|
|
71
71
|
getAllTables(): Table<any>[];
|
|
72
72
|
}
|