@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
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const table_1 = require("./table");
|
|
4
|
-
const subscribable_data_source_1 = require("./subscribable.data-source");
|
|
5
|
-
const types_1 = require("./types");
|
|
6
3
|
const field_type_1 = require("../../types/field-type");
|
|
7
4
|
const utils_1 = require("../../utils");
|
|
8
5
|
const event_registry_1 = require("./event-registry");
|
|
6
|
+
const subscribable_data_source_1 = require("./subscribable.data-source");
|
|
7
|
+
const table_1 = require("./table");
|
|
8
|
+
const types_1 = require("./types");
|
|
9
9
|
// Mock data source for testing
|
|
10
10
|
class MockDataSource {
|
|
11
11
|
tableName;
|
|
12
12
|
primaryKeyName;
|
|
13
13
|
data = new Map();
|
|
14
|
-
constructor(tableName, primaryKeyName =
|
|
14
|
+
constructor(tableName, primaryKeyName = "id", initialData = []) {
|
|
15
15
|
this.tableName = tableName;
|
|
16
16
|
this.primaryKeyName = primaryKeyName;
|
|
17
|
-
initialData.forEach(item => {
|
|
17
|
+
initialData.forEach((item) => {
|
|
18
18
|
this.data.set(item[primaryKeyName], item);
|
|
19
19
|
});
|
|
20
20
|
}
|
|
@@ -50,56 +50,56 @@ class MockDataSource {
|
|
|
50
50
|
return record;
|
|
51
51
|
}
|
|
52
52
|
async delete(idOrRecord) {
|
|
53
|
-
const id = typeof idOrRecord ===
|
|
53
|
+
const id = typeof idOrRecord === "string" ? idOrRecord : idOrRecord[this.primaryKeyName];
|
|
54
54
|
this.data.delete(id);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
describe(
|
|
57
|
+
describe("Table Event Source Functionality", () => {
|
|
58
58
|
let table;
|
|
59
59
|
let underlyingDataSource;
|
|
60
60
|
let subscribableDataSource;
|
|
61
61
|
let capturedEvents;
|
|
62
62
|
const testMetadata = {
|
|
63
|
-
name:
|
|
64
|
-
description:
|
|
65
|
-
primaryKeyName:
|
|
63
|
+
name: "TestTable",
|
|
64
|
+
description: "Test table for event source functionality",
|
|
65
|
+
primaryKeyName: "id",
|
|
66
66
|
fields: [
|
|
67
|
-
{ name:
|
|
68
|
-
{ name:
|
|
69
|
-
{ name:
|
|
70
|
-
]
|
|
67
|
+
{ name: "id", type: field_type_1.FieldType.id, description: "Primary key" },
|
|
68
|
+
{ name: "name", type: field_type_1.FieldType.string, description: "Name field" },
|
|
69
|
+
{ name: "age", type: field_type_1.FieldType.number, description: "Age field" },
|
|
70
|
+
],
|
|
71
71
|
};
|
|
72
72
|
const testSchema = (0, types_1.fieldsToSchema)(testMetadata.fields);
|
|
73
73
|
const testRecord = {
|
|
74
|
-
id:
|
|
75
|
-
name:
|
|
76
|
-
age: 30
|
|
74
|
+
id: "test-1",
|
|
75
|
+
name: "John Doe",
|
|
76
|
+
age: 30,
|
|
77
77
|
};
|
|
78
78
|
beforeEach(() => {
|
|
79
79
|
capturedEvents = [];
|
|
80
80
|
// Create underlying data source with unique name to avoid conflicts
|
|
81
81
|
const uniqueTableName = `TestTable_${Date.now()}_${Math.random()}`;
|
|
82
|
-
underlyingDataSource = new MockDataSource(uniqueTableName,
|
|
82
|
+
underlyingDataSource = new MockDataSource(uniqueTableName, "id");
|
|
83
83
|
// Wrap it in a SubscribableDataSource
|
|
84
84
|
subscribableDataSource = new subscribable_data_source_1.SubscribableDataSource(underlyingDataSource);
|
|
85
85
|
// Create real event registry for testing
|
|
86
86
|
const mockDataContextForRegistry = {
|
|
87
|
-
dataContextId:
|
|
87
|
+
dataContextId: "test-context",
|
|
88
88
|
};
|
|
89
89
|
const eventRegistry = new event_registry_1.EventRegistry(mockDataContextForRegistry);
|
|
90
|
-
const
|
|
90
|
+
const _mockDataContext = {
|
|
91
91
|
dataSourceFactory: () => subscribableDataSource,
|
|
92
|
-
eventRegistry: eventRegistry
|
|
92
|
+
eventRegistry: eventRegistry,
|
|
93
93
|
};
|
|
94
94
|
// Create table with the subscribable data source
|
|
95
95
|
const metaData = {
|
|
96
96
|
...testMetadata,
|
|
97
|
-
name: uniqueTableName
|
|
97
|
+
name: uniqueTableName,
|
|
98
98
|
};
|
|
99
99
|
const deps = {
|
|
100
100
|
dataSource: subscribableDataSource,
|
|
101
101
|
eventRegistry: eventRegistry,
|
|
102
|
-
schema: testSchema
|
|
102
|
+
schema: testSchema,
|
|
103
103
|
};
|
|
104
104
|
table = new table_1.Table(metaData, deps);
|
|
105
105
|
// Subscribe to events to capture them
|
|
@@ -107,17 +107,17 @@ describe('Table Event Source Functionality', () => {
|
|
|
107
107
|
capturedEvents.push(event);
|
|
108
108
|
});
|
|
109
109
|
});
|
|
110
|
-
describe(
|
|
111
|
-
it(
|
|
110
|
+
describe("Local Operations", () => {
|
|
111
|
+
it("should mark insert events as local when called from table", async () => {
|
|
112
112
|
await table.insert(testRecord);
|
|
113
113
|
expect(capturedEvents).toHaveLength(1);
|
|
114
114
|
expect(capturedEvents[0]).toEqual({
|
|
115
115
|
dataObject: testRecord,
|
|
116
|
-
op:
|
|
117
|
-
source:
|
|
116
|
+
op: "insert",
|
|
117
|
+
source: "local",
|
|
118
118
|
});
|
|
119
119
|
});
|
|
120
|
-
it(
|
|
120
|
+
it("should mark update events as local when called from table", async () => {
|
|
121
121
|
// First insert the record
|
|
122
122
|
await table.insert(testRecord);
|
|
123
123
|
capturedEvents.length = 0; // Clear events
|
|
@@ -126,11 +126,11 @@ describe('Table Event Source Functionality', () => {
|
|
|
126
126
|
expect(capturedEvents).toHaveLength(1);
|
|
127
127
|
expect(capturedEvents[0]).toEqual({
|
|
128
128
|
dataObject: updatedRecord,
|
|
129
|
-
op:
|
|
130
|
-
source:
|
|
129
|
+
op: "update",
|
|
130
|
+
source: "local",
|
|
131
131
|
});
|
|
132
132
|
});
|
|
133
|
-
it(
|
|
133
|
+
it("should mark delete events as local when called from table", async () => {
|
|
134
134
|
// First insert the record
|
|
135
135
|
await table.insert(testRecord);
|
|
136
136
|
capturedEvents.length = 0; // Clear events
|
|
@@ -138,20 +138,20 @@ describe('Table Event Source Functionality', () => {
|
|
|
138
138
|
expect(capturedEvents).toHaveLength(1);
|
|
139
139
|
expect(capturedEvents[0]).toEqual({
|
|
140
140
|
dataObject: testRecord,
|
|
141
|
-
op:
|
|
142
|
-
source:
|
|
141
|
+
op: "delete",
|
|
142
|
+
source: "local",
|
|
143
143
|
});
|
|
144
144
|
});
|
|
145
|
-
it(
|
|
145
|
+
it("should mark save events as local (insert case)", async () => {
|
|
146
146
|
await table.save(testRecord);
|
|
147
147
|
expect(capturedEvents).toHaveLength(1);
|
|
148
148
|
expect(capturedEvents[0]).toEqual({
|
|
149
149
|
dataObject: testRecord,
|
|
150
|
-
op:
|
|
151
|
-
source:
|
|
150
|
+
op: "insert",
|
|
151
|
+
source: "local",
|
|
152
152
|
});
|
|
153
153
|
});
|
|
154
|
-
it(
|
|
154
|
+
it("should mark save events as local (update case)", async () => {
|
|
155
155
|
// First insert the record directly to underlying source
|
|
156
156
|
await underlyingDataSource.insert(testRecord);
|
|
157
157
|
capturedEvents.length = 0; // Clear events
|
|
@@ -160,22 +160,22 @@ describe('Table Event Source Functionality', () => {
|
|
|
160
160
|
expect(capturedEvents).toHaveLength(1);
|
|
161
161
|
expect(capturedEvents[0]).toEqual({
|
|
162
162
|
dataObject: updatedRecord,
|
|
163
|
-
op:
|
|
164
|
-
source:
|
|
163
|
+
op: "update",
|
|
164
|
+
source: "local",
|
|
165
165
|
});
|
|
166
166
|
});
|
|
167
167
|
});
|
|
168
|
-
describe(
|
|
169
|
-
it(
|
|
168
|
+
describe("Remote Operations", () => {
|
|
169
|
+
it("should mark insert events as remote when called from underlying source", async () => {
|
|
170
170
|
await subscribableDataSource.insert(testRecord);
|
|
171
171
|
expect(capturedEvents).toHaveLength(1);
|
|
172
172
|
expect(capturedEvents[0]).toEqual({
|
|
173
173
|
dataObject: testRecord,
|
|
174
|
-
op:
|
|
175
|
-
source:
|
|
174
|
+
op: "insert",
|
|
175
|
+
source: "remote",
|
|
176
176
|
});
|
|
177
177
|
});
|
|
178
|
-
it(
|
|
178
|
+
it("should mark update events as remote when called from underlying source", async () => {
|
|
179
179
|
// First insert the record
|
|
180
180
|
await subscribableDataSource.insert(testRecord);
|
|
181
181
|
capturedEvents.length = 0; // Clear events
|
|
@@ -184,11 +184,11 @@ describe('Table Event Source Functionality', () => {
|
|
|
184
184
|
expect(capturedEvents).toHaveLength(1);
|
|
185
185
|
expect(capturedEvents[0]).toEqual({
|
|
186
186
|
dataObject: updatedRecord,
|
|
187
|
-
op:
|
|
188
|
-
source:
|
|
187
|
+
op: "update",
|
|
188
|
+
source: "remote",
|
|
189
189
|
});
|
|
190
190
|
});
|
|
191
|
-
it(
|
|
191
|
+
it("should mark delete events as remote when called from underlying source", async () => {
|
|
192
192
|
// First insert the record
|
|
193
193
|
await subscribableDataSource.insert(testRecord);
|
|
194
194
|
capturedEvents.length = 0; // Clear events
|
|
@@ -196,95 +196,85 @@ describe('Table Event Source Functionality', () => {
|
|
|
196
196
|
expect(capturedEvents).toHaveLength(1);
|
|
197
197
|
expect(capturedEvents[0]).toEqual({
|
|
198
198
|
dataObject: testRecord,
|
|
199
|
-
op:
|
|
200
|
-
source:
|
|
199
|
+
op: "delete",
|
|
200
|
+
source: "remote",
|
|
201
201
|
});
|
|
202
202
|
});
|
|
203
203
|
});
|
|
204
|
-
describe(
|
|
205
|
-
it(
|
|
206
|
-
const record1 = { id:
|
|
207
|
-
const record2 = { id:
|
|
208
|
-
const record3 = { id:
|
|
204
|
+
describe("Concurrent Operations", () => {
|
|
205
|
+
it("should handle multiple concurrent insert operations correctly", async () => {
|
|
206
|
+
const record1 = { id: "test-1", name: "John", age: 30 };
|
|
207
|
+
const record2 = { id: "test-2", name: "Jane", age: 25 };
|
|
208
|
+
const record3 = { id: "test-3", name: "Bob", age: 35 };
|
|
209
209
|
// Execute multiple operations concurrently
|
|
210
|
-
await Promise.all([
|
|
211
|
-
table.insert(record1),
|
|
212
|
-
table.insert(record2),
|
|
213
|
-
table.insert(record3)
|
|
214
|
-
]);
|
|
210
|
+
await Promise.all([table.insert(record1), table.insert(record2), table.insert(record3)]);
|
|
215
211
|
expect(capturedEvents).toHaveLength(3);
|
|
216
|
-
capturedEvents.forEach(event => {
|
|
217
|
-
expect(event.op).toBe(
|
|
218
|
-
expect(event.source).toBe(
|
|
212
|
+
capturedEvents.forEach((event) => {
|
|
213
|
+
expect(event.op).toBe("insert");
|
|
214
|
+
expect(event.source).toBe("local");
|
|
219
215
|
});
|
|
220
216
|
// Verify all records were inserted
|
|
221
|
-
const insertedIds = capturedEvents.map(e => e.dataObject.id).sort();
|
|
222
|
-
expect(insertedIds).toEqual([
|
|
217
|
+
const insertedIds = capturedEvents.map((e) => e.dataObject.id).sort();
|
|
218
|
+
expect(insertedIds).toEqual(["test-1", "test-2", "test-3"]);
|
|
223
219
|
});
|
|
224
|
-
it(
|
|
225
|
-
const record1 = { id:
|
|
226
|
-
const record2 = { id:
|
|
220
|
+
it("should handle concurrent operations with different operations types", async () => {
|
|
221
|
+
const record1 = { id: "test-1", name: "John", age: 30 };
|
|
222
|
+
const record2 = { id: "test-2", name: "Jane", age: 25 };
|
|
227
223
|
// First insert records to set up for update/delete
|
|
228
224
|
await table.insert(record1);
|
|
229
225
|
await table.insert(record2);
|
|
230
226
|
capturedEvents.length = 0; // Clear events
|
|
231
227
|
const updatedRecord1 = { ...record1, age: 31 };
|
|
232
|
-
const record3 = { id:
|
|
228
|
+
const record3 = { id: "test-3", name: "Alice", age: 28 };
|
|
233
229
|
// Execute mixed operations concurrently
|
|
234
230
|
await Promise.all([
|
|
235
231
|
table.update(updatedRecord1),
|
|
236
232
|
table.delete(record2.id),
|
|
237
|
-
table.insert(record3)
|
|
233
|
+
table.insert(record3),
|
|
238
234
|
]);
|
|
239
235
|
expect(capturedEvents).toHaveLength(3);
|
|
240
236
|
// All should be marked as local
|
|
241
|
-
capturedEvents.forEach(event => {
|
|
242
|
-
expect(event.source).toBe(
|
|
237
|
+
capturedEvents.forEach((event) => {
|
|
238
|
+
expect(event.source).toBe("local");
|
|
243
239
|
});
|
|
244
240
|
// Check specific operations
|
|
245
|
-
const operations = capturedEvents.map(e => e.op).sort();
|
|
246
|
-
expect(operations).toEqual([
|
|
241
|
+
const operations = capturedEvents.map((e) => e.op).sort();
|
|
242
|
+
expect(operations).toEqual(["delete", "insert", "update"]);
|
|
247
243
|
});
|
|
248
|
-
it(
|
|
249
|
-
const localRecord = { id:
|
|
250
|
-
const remoteRecord = { id:
|
|
244
|
+
it("should handle concurrent local and remote operations correctly", async () => {
|
|
245
|
+
const localRecord = { id: "local-1", name: "Local User", age: 30 };
|
|
246
|
+
const remoteRecord = { id: "remote-1", name: "Remote User", age: 25 };
|
|
251
247
|
// Execute local and remote operations concurrently
|
|
252
|
-
await Promise.all([
|
|
253
|
-
table.insert(localRecord),
|
|
254
|
-
subscribableDataSource.insert(remoteRecord)
|
|
255
|
-
]);
|
|
248
|
+
await Promise.all([table.insert(localRecord), subscribableDataSource.insert(remoteRecord)]);
|
|
256
249
|
expect(capturedEvents).toHaveLength(2);
|
|
257
250
|
// Find events by record ID
|
|
258
|
-
const localEvent = capturedEvents.find(e => e.dataObject.id ===
|
|
259
|
-
const remoteEvent = capturedEvents.find(e => e.dataObject.id ===
|
|
260
|
-
expect(localEvent?.source).toBe(
|
|
261
|
-
expect(remoteEvent?.source).toBe(
|
|
251
|
+
const localEvent = capturedEvents.find((e) => e.dataObject.id === "local-1");
|
|
252
|
+
const remoteEvent = capturedEvents.find((e) => e.dataObject.id === "remote-1");
|
|
253
|
+
expect(localEvent?.source).toBe("local");
|
|
254
|
+
expect(remoteEvent?.source).toBe("remote");
|
|
262
255
|
});
|
|
263
|
-
it(
|
|
264
|
-
const record1 = { id:
|
|
265
|
-
const record2 = { id:
|
|
256
|
+
it("should handle concurrent operations on different records correctly", async () => {
|
|
257
|
+
const record1 = { id: "test-1", name: "John", age: 30 };
|
|
258
|
+
const record2 = { id: "test-2", name: "Jane", age: 25 };
|
|
266
259
|
// Insert records first
|
|
267
260
|
await table.insert(record1);
|
|
268
261
|
await subscribableDataSource.insert(record2);
|
|
269
262
|
capturedEvents.length = 0;
|
|
270
|
-
const localUpdate = { ...record1, name:
|
|
271
|
-
const remoteUpdate = { ...record2, name:
|
|
263
|
+
const localUpdate = { ...record1, name: "John Local", age: 31 };
|
|
264
|
+
const remoteUpdate = { ...record2, name: "Jane Remote", age: 26 };
|
|
272
265
|
// Execute concurrent updates on different records (one local, one remote)
|
|
273
|
-
await Promise.all([
|
|
274
|
-
table.update(localUpdate),
|
|
275
|
-
subscribableDataSource.update(remoteUpdate)
|
|
276
|
-
]);
|
|
266
|
+
await Promise.all([table.update(localUpdate), subscribableDataSource.update(remoteUpdate)]);
|
|
277
267
|
expect(capturedEvents).toHaveLength(2);
|
|
278
268
|
// Both operations should complete, but with different sources
|
|
279
|
-
const localEvent = capturedEvents.find(e => e.dataObject.name?.includes(
|
|
280
|
-
const remoteEvent = capturedEvents.find(e => e.dataObject.name?.includes(
|
|
281
|
-
expect(localEvent?.source).toBe(
|
|
282
|
-
expect(remoteEvent?.source).toBe(
|
|
269
|
+
const localEvent = capturedEvents.find((e) => e.dataObject.name?.includes("Local"));
|
|
270
|
+
const remoteEvent = capturedEvents.find((e) => e.dataObject.name?.includes("Remote"));
|
|
271
|
+
expect(localEvent?.source).toBe("local");
|
|
272
|
+
expect(remoteEvent?.source).toBe("remote");
|
|
283
273
|
});
|
|
284
274
|
});
|
|
285
|
-
describe(
|
|
286
|
-
it(
|
|
287
|
-
const record = { id:
|
|
275
|
+
describe("Cache Management", () => {
|
|
276
|
+
it("should clean up cache entries after operations complete", async () => {
|
|
277
|
+
const record = { id: "test-1", name: "John", age: 30 };
|
|
288
278
|
// Insert record
|
|
289
279
|
await table.insert(record);
|
|
290
280
|
// Verify the cache was cleaned up by checking that subsequent remote operations
|
|
@@ -292,50 +282,50 @@ describe('Table Event Source Functionality', () => {
|
|
|
292
282
|
const updatedRecord = { ...record, age: 31 };
|
|
293
283
|
await subscribableDataSource.update(updatedRecord);
|
|
294
284
|
expect(capturedEvents).toHaveLength(2);
|
|
295
|
-
expect(capturedEvents[0].source).toBe(
|
|
296
|
-
expect(capturedEvents[1].source).toBe(
|
|
285
|
+
expect(capturedEvents[0].source).toBe("local"); // Insert
|
|
286
|
+
expect(capturedEvents[1].source).toBe("remote"); // Update from subscribable source
|
|
297
287
|
});
|
|
298
|
-
it(
|
|
299
|
-
const record = { id:
|
|
288
|
+
it("should clean up cache entries even when operations throw errors", async () => {
|
|
289
|
+
const record = { id: "nonexistent", name: "John", age: 30 };
|
|
300
290
|
// Try to update a non-existent record (should throw)
|
|
301
291
|
try {
|
|
302
292
|
await table.update(record);
|
|
303
293
|
}
|
|
304
|
-
catch (
|
|
294
|
+
catch (_error) {
|
|
305
295
|
// Expected to throw
|
|
306
296
|
}
|
|
307
297
|
// Now insert the same record through underlying source
|
|
308
298
|
await subscribableDataSource.insert(record);
|
|
309
299
|
// Should be marked as remote since cache was cleaned up
|
|
310
300
|
expect(capturedEvents).toHaveLength(1);
|
|
311
|
-
expect(capturedEvents[0].source).toBe(
|
|
301
|
+
expect(capturedEvents[0].source).toBe("remote");
|
|
312
302
|
});
|
|
313
303
|
});
|
|
314
|
-
describe(
|
|
315
|
-
it(
|
|
304
|
+
describe("Table Without Underlying SubscribableDataSource", () => {
|
|
305
|
+
it("should work correctly when no underlying SubscribableDataSource exists", async () => {
|
|
316
306
|
// Create table with plain data source (no SubscribableDataSource)
|
|
317
|
-
const plainDataSource = new MockDataSource(
|
|
307
|
+
const plainDataSource = new MockDataSource("PlainTable", "id");
|
|
318
308
|
const mockDataContextForRegistry2 = {
|
|
319
|
-
dataContextId:
|
|
309
|
+
dataContextId: "test-context-2",
|
|
320
310
|
};
|
|
321
311
|
const eventRegistry2 = new event_registry_1.EventRegistry(mockDataContextForRegistry2);
|
|
322
|
-
const
|
|
312
|
+
const _mockDataContext = {
|
|
323
313
|
dataSourceFactory: () => plainDataSource,
|
|
324
|
-
eventRegistry: eventRegistry2
|
|
314
|
+
eventRegistry: eventRegistry2,
|
|
325
315
|
};
|
|
326
316
|
const plainTableDeps = {
|
|
327
317
|
dataSource: plainDataSource,
|
|
328
318
|
eventRegistry: eventRegistry2,
|
|
329
|
-
schema: testSchema
|
|
319
|
+
schema: testSchema,
|
|
330
320
|
};
|
|
331
321
|
const plainTable = new table_1.Table(testMetadata, plainTableDeps);
|
|
332
322
|
const events = [];
|
|
333
|
-
plainTable.dataChanged.subscribe(event => {
|
|
323
|
+
plainTable.dataChanged.subscribe((event) => {
|
|
334
324
|
events.push(event);
|
|
335
325
|
});
|
|
336
326
|
await plainTable.insert(testRecord);
|
|
337
327
|
expect(events).toHaveLength(1);
|
|
338
|
-
expect(events[0].source).toBe(
|
|
328
|
+
expect(events[0].source).toBe("local");
|
|
339
329
|
});
|
|
340
330
|
});
|
|
341
331
|
});
|
package/dist/data/orm/table.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
// import { Collection } from "peers-kore";
|
|
3
|
+
// import { injectDB } from "../../common/inject-db";
|
|
4
|
+
// import { singular } from "peers-kore/dist/orm/factory";
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.Table = void 0;
|
|
4
7
|
exports.getIconClassName = getIconClassName;
|
|
8
|
+
const lodash_1 = require("lodash");
|
|
9
|
+
const rpc_types_1 = require("../../rpc-types");
|
|
10
|
+
const utils_1 = require("../../utils");
|
|
5
11
|
const data_query_1 = require("./data-query");
|
|
6
12
|
const doc_1 = require("./doc");
|
|
13
|
+
const sql_data_source_1 = require("./sql.data-source");
|
|
7
14
|
const subscribable_data_source_1 = require("./subscribable.data-source");
|
|
8
15
|
const types_1 = require("./types");
|
|
9
|
-
const utils_1 = require("../../utils");
|
|
10
|
-
const rpc_types_1 = require("../../rpc-types");
|
|
11
|
-
const lodash_1 = require("lodash");
|
|
12
|
-
const sql_data_source_1 = require("./sql.data-source");
|
|
13
16
|
class Table {
|
|
14
17
|
tableName;
|
|
15
18
|
primaryKeyName;
|
|
@@ -30,7 +33,7 @@ class Table {
|
|
|
30
33
|
this.tableName = (0, utils_1.getFullTableName)(metaData);
|
|
31
34
|
this.primaryKeyName = metaData.primaryKeyName;
|
|
32
35
|
// Event setup with explicit dependency
|
|
33
|
-
const eventName = this.tableName
|
|
36
|
+
const eventName = `${this.tableName}_DataChanged`;
|
|
34
37
|
this.dataChangedEmitter = deps.eventRegistry.getEmitter(eventName);
|
|
35
38
|
this.dataChanged = this.dataChangedEmitter.event;
|
|
36
39
|
if (rpc_types_1.isClient && !(0, rpc_types_1.isSingleProcessClient)()) {
|
|
@@ -38,12 +41,12 @@ class Table {
|
|
|
38
41
|
this.dataChangedEmitter.emit = lodash_1.noop;
|
|
39
42
|
}
|
|
40
43
|
// Validation (works for both patterns since this.metaData is set)
|
|
41
|
-
const primaryKeyIsValid = this.metaData.fields.find(f => f.name === this.metaData.primaryKeyName);
|
|
44
|
+
const primaryKeyIsValid = this.metaData.fields.find((f) => f.name === this.metaData.primaryKeyName);
|
|
42
45
|
if (!primaryKeyIsValid) {
|
|
43
46
|
throw new Error(`Table "${this.tableName}", primary key "${this.metaData.primaryKeyName}" is not a valid field name`);
|
|
44
47
|
}
|
|
45
48
|
// Find any underlying SubscribableDataSource to intercept its events
|
|
46
|
-
let subscribableDataSource
|
|
49
|
+
let subscribableDataSource;
|
|
47
50
|
let _dataSource = this.dataSource;
|
|
48
51
|
while (_dataSource) {
|
|
49
52
|
if (!subscribableDataSource && _dataSource instanceof subscribable_data_source_1.SubscribableDataSource) {
|
|
@@ -66,7 +69,7 @@ class Table {
|
|
|
66
69
|
this.dataChangedEmitter.emit({
|
|
67
70
|
dataObject: event.dataObject,
|
|
68
71
|
op: event.op,
|
|
69
|
-
source:
|
|
72
|
+
source: "remote",
|
|
70
73
|
});
|
|
71
74
|
}
|
|
72
75
|
});
|
|
@@ -90,25 +93,25 @@ class Table {
|
|
|
90
93
|
if (useCache && this.cachedRecords[id]) {
|
|
91
94
|
return this.cachedRecords[id];
|
|
92
95
|
}
|
|
93
|
-
const promise =
|
|
96
|
+
const promise = (async () => {
|
|
94
97
|
try {
|
|
95
98
|
let record;
|
|
96
99
|
record = await this.dataSource.get(id);
|
|
97
100
|
if (!record) {
|
|
98
101
|
cacheTtlMs = 1000; // very short cache ttl for non-existent records
|
|
99
102
|
}
|
|
100
|
-
|
|
103
|
+
return record;
|
|
101
104
|
}
|
|
102
105
|
catch (err) {
|
|
103
106
|
cacheTtlMs = 1000; // very short cache ttl on error
|
|
104
|
-
|
|
107
|
+
throw err;
|
|
105
108
|
}
|
|
106
109
|
finally {
|
|
107
110
|
setTimeout(() => {
|
|
108
111
|
delete this.cachedRecords[id];
|
|
109
112
|
}, cacheTtlMs);
|
|
110
113
|
}
|
|
111
|
-
});
|
|
114
|
+
})();
|
|
112
115
|
if (useCache) {
|
|
113
116
|
this.cachedRecords[id] = promise;
|
|
114
117
|
}
|
|
@@ -117,11 +120,9 @@ class Table {
|
|
|
117
120
|
async list(filter = {}, opts = {}) {
|
|
118
121
|
return this.dataSource.list(filter, opts);
|
|
119
122
|
}
|
|
120
|
-
;
|
|
121
123
|
async count(filter = {}) {
|
|
122
124
|
return (0, data_query_1.dataSourceCount)(this.dataSource, filter);
|
|
123
125
|
}
|
|
124
|
-
;
|
|
125
126
|
cursor(filter = {}, opts = {}) {
|
|
126
127
|
return (0, data_query_1.dataSourceCursor)(this.dataSource, filter, opts);
|
|
127
128
|
}
|
|
@@ -144,12 +145,12 @@ class Table {
|
|
|
144
145
|
delete this.cachedRecords[recordId];
|
|
145
146
|
}
|
|
146
147
|
const isInsert = !recordId || !(await this.get(recordId));
|
|
147
|
-
const operation = isInsert ?
|
|
148
|
+
const operation = isInsert ? "insert" : "update";
|
|
148
149
|
this.setLocalOperation(recordId, operation);
|
|
149
150
|
let result;
|
|
150
151
|
try {
|
|
151
152
|
// NOTE: done this way to allow individual tables to have custom logic in `save`, `insert`, and `update`
|
|
152
|
-
// but this results in a double-read (this method and the data-source method).
|
|
153
|
+
// but this results in a double-read (this method and the data-source method).
|
|
153
154
|
// TODO: try to avoid the double-read, probably by passing the just-read result as `opts.dbData`
|
|
154
155
|
result = await this.dataSource.save(record, opts);
|
|
155
156
|
}
|
|
@@ -159,63 +160,63 @@ class Table {
|
|
|
159
160
|
this.dataChangedEmitter.emit({
|
|
160
161
|
dataObject: result,
|
|
161
162
|
op: operation,
|
|
162
|
-
source:
|
|
163
|
+
source: "local",
|
|
163
164
|
});
|
|
164
165
|
return result;
|
|
165
166
|
}
|
|
166
167
|
async insert(record) {
|
|
167
168
|
const recordId = this.getRecordId(record);
|
|
168
|
-
this.setLocalOperation(recordId,
|
|
169
|
+
this.setLocalOperation(recordId, "insert");
|
|
169
170
|
let result;
|
|
170
171
|
try {
|
|
171
172
|
result = await this.dataSource.insert(record);
|
|
172
173
|
}
|
|
173
174
|
finally {
|
|
174
|
-
this.clearLocalOperation(recordId,
|
|
175
|
+
this.clearLocalOperation(recordId, "insert");
|
|
175
176
|
}
|
|
176
177
|
this.dataChangedEmitter.emit({
|
|
177
178
|
dataObject: result,
|
|
178
|
-
op:
|
|
179
|
-
source:
|
|
179
|
+
op: "insert",
|
|
180
|
+
source: "local",
|
|
180
181
|
});
|
|
181
182
|
return result;
|
|
182
183
|
}
|
|
183
184
|
async update(record) {
|
|
184
185
|
delete this.cachedRecords[record[this.metaData.primaryKeyName]];
|
|
185
186
|
const recordId = this.getRecordId(record);
|
|
186
|
-
this.setLocalOperation(recordId,
|
|
187
|
+
this.setLocalOperation(recordId, "update");
|
|
187
188
|
let result;
|
|
188
189
|
try {
|
|
189
190
|
result = await this.dataSource.update(record);
|
|
190
191
|
}
|
|
191
192
|
finally {
|
|
192
|
-
this.clearLocalOperation(recordId,
|
|
193
|
+
this.clearLocalOperation(recordId, "update");
|
|
193
194
|
}
|
|
194
195
|
this.dataChangedEmitter.emit({
|
|
195
196
|
dataObject: result,
|
|
196
|
-
op:
|
|
197
|
-
source:
|
|
197
|
+
op: "update",
|
|
198
|
+
source: "local",
|
|
198
199
|
});
|
|
199
200
|
return result;
|
|
200
201
|
}
|
|
201
202
|
async delete(idOrRecord) {
|
|
202
|
-
const primaryKey = typeof idOrRecord ===
|
|
203
|
-
const existingRecord = typeof idOrRecord ===
|
|
203
|
+
const primaryKey = typeof idOrRecord === "string" ? idOrRecord : idOrRecord[this.metaData.primaryKeyName];
|
|
204
|
+
const existingRecord = typeof idOrRecord === "object" ? idOrRecord : await this.get(primaryKey);
|
|
204
205
|
delete this.cachedRecords[primaryKey];
|
|
205
206
|
if (!existingRecord) {
|
|
206
207
|
return; // nothing to delete
|
|
207
208
|
}
|
|
208
|
-
this.setLocalOperation(primaryKey,
|
|
209
|
+
this.setLocalOperation(primaryKey, "delete");
|
|
209
210
|
try {
|
|
210
211
|
await this.dataSource.delete(idOrRecord);
|
|
211
212
|
}
|
|
212
213
|
finally {
|
|
213
|
-
this.clearLocalOperation(primaryKey,
|
|
214
|
+
this.clearLocalOperation(primaryKey, "delete");
|
|
214
215
|
}
|
|
215
216
|
this.dataChangedEmitter.emit({
|
|
216
217
|
dataObject: existingRecord,
|
|
217
|
-
op:
|
|
218
|
-
source:
|
|
218
|
+
op: "delete",
|
|
219
|
+
source: "local",
|
|
219
220
|
});
|
|
220
221
|
}
|
|
221
222
|
initRecord(data = {}) {
|
|
@@ -225,7 +226,7 @@ class Table {
|
|
|
225
226
|
if (this.codeSchema?.shape?.[field.name]) {
|
|
226
227
|
const codeValue = this.codeSchema.shape[field.name].safeParse(data[field.name]);
|
|
227
228
|
if (codeValue.success) {
|
|
228
|
-
// @ts-
|
|
229
|
+
// @ts-expect-error
|
|
229
230
|
defaults[field.name] = codeValue.data;
|
|
230
231
|
continue;
|
|
231
232
|
}
|
|
@@ -234,7 +235,7 @@ class Table {
|
|
|
234
235
|
const zodField = this.schema.shape[field.name];
|
|
235
236
|
const value = zodField.safeParse(data[field.name]);
|
|
236
237
|
if (value.success) {
|
|
237
|
-
// @ts-
|
|
238
|
+
// @ts-expect-error
|
|
238
239
|
defaults[field.name] = value.data;
|
|
239
240
|
}
|
|
240
241
|
}
|
|
@@ -252,5 +253,5 @@ class Table {
|
|
|
252
253
|
}
|
|
253
254
|
exports.Table = Table;
|
|
254
255
|
function getIconClassName(table) {
|
|
255
|
-
return table.metaData.iconClassName ??
|
|
256
|
+
return table.metaData.iconClassName ?? "bi bi-question";
|
|
256
257
|
}
|
package/dist/data/orm/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { z } from
|
|
2
|
-
import { IField } from
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type IField } from "../../types/field-type";
|
|
3
3
|
export interface ITableMetaData {
|
|
4
4
|
tableId?: string;
|
|
5
5
|
name: string;
|
|
@@ -9,7 +9,7 @@ export interface ITableMetaData {
|
|
|
9
9
|
indexes?: {
|
|
10
10
|
fields: (string | {
|
|
11
11
|
name: string;
|
|
12
|
-
order:
|
|
12
|
+
order: "ASC" | "DESC";
|
|
13
13
|
})[];
|
|
14
14
|
unique?: true;
|
|
15
15
|
}[];
|