@routier/core 0.0.1-alpha.1
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/CHANGELOG.md +8 -0
- package/package.json +91 -0
- package/rspack.config.mjs +65 -0
- package/src/assertions/index.ts +37 -0
- package/src/codegen/SlotPath.ts +20 -0
- package/src/codegen/blocks.ts +578 -0
- package/src/codegen/handlers/CloneHandlerBuilder.ts +13 -0
- package/src/codegen/handlers/CompareHandlerBuilder.ts +13 -0
- package/src/codegen/handlers/DeserializeHandlerBuilder.ts +20 -0
- package/src/codegen/handlers/EnableChangeTrackingHandlerBuilder.ts +13 -0
- package/src/codegen/handlers/EnrichmentHandlerBuilder.ts +28 -0
- package/src/codegen/handlers/FreezeHandlerBuilder.ts +13 -0
- package/src/codegen/handlers/HashHandlerBuilder.ts +25 -0
- package/src/codegen/handlers/HashTypeHandlerBuilder.ts +11 -0
- package/src/codegen/handlers/IdSelectorHandlerBuilder.ts +10 -0
- package/src/codegen/handlers/MergeHandlerBuilder.ts +19 -0
- package/src/codegen/handlers/PrepareHandlerBuilder.ts +23 -0
- package/src/codegen/handlers/SerializeHandlerBuilder.ts +15 -0
- package/src/codegen/handlers/StripHandlerBuilder.ts +18 -0
- package/src/codegen/handlers/clone/CloneObjectHandler.ts +29 -0
- package/src/codegen/handlers/clone/CloneValueHandler.ts +33 -0
- package/src/codegen/handlers/compare/CompareObjectHandler.ts +15 -0
- package/src/codegen/handlers/compare/CompareValueHandler.ts +27 -0
- package/src/codegen/handlers/deserialize/DeserializeComputedValueHandler.ts +16 -0
- package/src/codegen/handlers/deserialize/DeserializeDateHandler.ts +45 -0
- package/src/codegen/handlers/deserialize/DeserializeFunctionHandler.ts +16 -0
- package/src/codegen/handlers/deserialize/DeserializeObjectHandler.ts +29 -0
- package/src/codegen/handlers/deserialize/DeserializeValueHandler.ts +33 -0
- package/src/codegen/handlers/enableChangeTracking/EnableChangeTrackingObjectHandler.ts +20 -0
- package/src/codegen/handlers/enableChangeTracking/EnableChangeTrackingPrimitiveValueHandler.ts +15 -0
- package/src/codegen/handlers/enrichment/EnrichmentComputedValueHandler.ts +37 -0
- package/src/codegen/handlers/enrichment/EnrichmentDefaultFunctionHandler.ts +50 -0
- package/src/codegen/handlers/enrichment/EnrichmentDefaultValueHandler.ts +18 -0
- package/src/codegen/handlers/enrichment/EnrichmentFunctionHandler.ts +38 -0
- package/src/codegen/handlers/enrichment/EnrichmentNullableObjectHandler.ts +44 -0
- package/src/codegen/handlers/enrichment/EnrichmentObjectHandler.ts +29 -0
- package/src/codegen/handlers/enrichment/EnrichmentObjectIdentityHandler.ts +16 -0
- package/src/codegen/handlers/enrichment/EnrichmentPrimitiveHandler.ts +13 -0
- package/src/codegen/handlers/enrichment/EnrichmentPrimitiveIdentityHandler.ts +21 -0
- package/src/codegen/handlers/freeze/FreezeObjectHandler.ts +20 -0
- package/src/codegen/handlers/freeze/FreezePrimitiveValueHandler.ts +15 -0
- package/src/codegen/handlers/hash/HashComputedValueHandler.ts +15 -0
- package/src/codegen/handlers/hash/HashDateHandler.ts +26 -0
- package/src/codegen/handlers/hash/HashFunctionHandler.ts +16 -0
- package/src/codegen/handlers/hash/HashIdentityHandler.ts +15 -0
- package/src/codegen/handlers/hash/HashKeyHandler.ts +26 -0
- package/src/codegen/handlers/hash/HashValueHandler.ts +26 -0
- package/src/codegen/handlers/hashType/HashTypeValueHandler.ts +20 -0
- package/src/codegen/handlers/idSelector/IdSelectorValueHandler.ts +28 -0
- package/src/codegen/handlers/index.ts +13 -0
- package/src/codegen/handlers/merge/MergeComputedValueHandler.ts +37 -0
- package/src/codegen/handlers/merge/MergeDefaultFunctionHandler.ts +40 -0
- package/src/codegen/handlers/merge/MergeDefaultValueHandler.ts +32 -0
- package/src/codegen/handlers/merge/MergeFunctionHandler.ts +16 -0
- package/src/codegen/handlers/merge/MergePrimitiveHandler.ts +21 -0
- package/src/codegen/handlers/prepare/PrepareComputedValueHandler.ts +16 -0
- package/src/codegen/handlers/prepare/PrepareFunctionHandler.ts +16 -0
- package/src/codegen/handlers/prepare/PrepareIdentityHandler.ts +21 -0
- package/src/codegen/handlers/prepare/PrepareKeyHandler.ts +21 -0
- package/src/codegen/handlers/prepare/PrepareObjectHandler.ts +38 -0
- package/src/codegen/handlers/prepare/PrepareValueHandler.ts +36 -0
- package/src/codegen/handlers/serialize/SerializeDateHandler.ts +45 -0
- package/src/codegen/handlers/serialize/SerializeObjectHandler.ts +28 -0
- package/src/codegen/handlers/serialize/SerializeValueHandler.ts +33 -0
- package/src/codegen/handlers/strip/StripIdentityHandler.ts +15 -0
- package/src/codegen/handlers/strip/StripKeyHandler.ts +15 -0
- package/src/codegen/handlers/strip/StripObjectHandler.ts +35 -0
- package/src/codegen/handlers/strip/StripValueHandler.ts +36 -0
- package/src/codegen/handlers/types.ts +119 -0
- package/src/codegen/index.ts +2 -0
- package/src/codegen/types.ts +2 -0
- package/src/codegen/utils.ts +74 -0
- package/src/collections/Changes.test.ts +337 -0
- package/src/collections/Changes.ts +177 -0
- package/src/collections/IdSet.ts +28 -0
- package/src/collections/MemoryDataCollection.test.ts +424 -0
- package/src/collections/MemoryDataCollection.ts +134 -0
- package/src/collections/SchemaCollection.ts +22 -0
- package/src/collections/TagCollection.test.ts +443 -0
- package/src/collections/TagCollection.ts +62 -0
- package/src/collections/index.ts +5 -0
- package/src/errors/SchemaError.ts +6 -0
- package/src/errors/index.ts +1 -0
- package/src/expressions/index.ts +3 -0
- package/src/expressions/parser.test.ts +913 -0
- package/src/expressions/parser.ts +661 -0
- package/src/expressions/types.ts +184 -0
- package/src/expressions/utils.test.ts +346 -0
- package/src/expressions/utils.ts +59 -0
- package/src/index.ts +12 -0
- package/src/performance/index.ts +26 -0
- package/src/pipeline/SyncronousQueue.test.ts +269 -0
- package/src/pipeline/SyncronousQueue.ts +30 -0
- package/src/pipeline/TrampolinePipeline.test.ts +374 -0
- package/src/pipeline/TrampolinePipeline.ts +437 -0
- package/src/pipeline/index.ts +2 -0
- package/src/plugins/EphemeralDataPlugin.ts +132 -0
- package/src/plugins/capabilities/DbPluginCapability.ts +111 -0
- package/src/plugins/capabilities/index.ts +2 -0
- package/src/plugins/capabilities/logging/DbPluginLoggingCapability.ts +261 -0
- package/src/plugins/capabilities/logging/index.ts +1 -0
- package/src/plugins/index.ts +6 -0
- package/src/plugins/query/Query.ts +67 -0
- package/src/plugins/query/QueryOptionsCollection.test.ts +86 -0
- package/src/plugins/query/QueryOptionsCollection.ts +154 -0
- package/src/plugins/query/index.ts +3 -0
- package/src/plugins/query/types.ts +46 -0
- package/src/plugins/replication/OptimisticReplicationDbPlugin.ts +202 -0
- package/src/plugins/replication/ReplicationDbPlugin.ts +137 -0
- package/src/plugins/replication/index.ts +3 -0
- package/src/plugins/replication/types.ts +5 -0
- package/src/plugins/translators/DataTranslator.ts +46 -0
- package/src/plugins/translators/JsonTranslator.test.ts +618 -0
- package/src/plugins/translators/JsonTranslator.ts +211 -0
- package/src/plugins/translators/SqlTranslator.ts +45 -0
- package/src/plugins/translators/index.ts +3 -0
- package/src/plugins/types.ts +114 -0
- package/src/results/Result.ts +91 -0
- package/src/results/index.ts +3 -0
- package/src/results/types.ts +17 -0
- package/src/results/utils.ts +15 -0
- package/src/schema/PropertyInfo.test.ts +479 -0
- package/src/schema/PropertyInfo.ts +374 -0
- package/src/schema/SchemaDefinition.ts +626 -0
- package/src/schema/builder.ts +18 -0
- package/src/schema/index.ts +7 -0
- package/src/schema/property/base/SchemaBase.ts +49 -0
- package/src/schema/property/base/index.ts +1 -0
- package/src/schema/property/modifiers/SchemaDefault.ts +29 -0
- package/src/schema/property/modifiers/SchemaDeserialize.ts +23 -0
- package/src/schema/property/modifiers/SchemaDistinct.ts +14 -0
- package/src/schema/property/modifiers/SchemaFrom.ts +54 -0
- package/src/schema/property/modifiers/SchemaIdentity.ts +13 -0
- package/src/schema/property/modifiers/SchemaIndex.ts +60 -0
- package/src/schema/property/modifiers/SchemaKey.ts +28 -0
- package/src/schema/property/modifiers/SchemaNullable.ts +18 -0
- package/src/schema/property/modifiers/SchemaOptional.ts +19 -0
- package/src/schema/property/modifiers/SchemaReadonly.ts +34 -0
- package/src/schema/property/modifiers/SchemaSerialize.ts +18 -0
- package/src/schema/property/modifiers/SchemaTracked.ts +14 -0
- package/src/schema/property/modifiers/index.ts +12 -0
- package/src/schema/property/types/SchemaArray.ts +50 -0
- package/src/schema/property/types/SchemaBoolean.ts +59 -0
- package/src/schema/property/types/SchemaDate.ts +58 -0
- package/src/schema/property/types/SchemaNumber.ts +69 -0
- package/src/schema/property/types/SchemaObject.ts +44 -0
- package/src/schema/property/types/SchemaString.ts +69 -0
- package/src/schema/property/types/index.ts +6 -0
- package/src/schema/table/SchemaComputed.ts +20 -0
- package/src/schema/table/SchemaFunction.ts +15 -0
- package/src/schema/table/index.ts +2 -0
- package/src/schema/types.ts +238 -0
- package/src/types/index.ts +5 -0
- package/src/utilities/arrays.test.ts +312 -0
- package/src/utilities/arrays.ts +12 -0
- package/src/utilities/dates.test.ts +388 -0
- package/src/utilities/dates.ts +11 -0
- package/src/utilities/dbPluginEventUtils.ts +44 -0
- package/src/utilities/index.ts +10 -0
- package/src/utilities/objects.ts +7 -0
- package/src/utilities/queryOptionsCollection.ts +16 -0
- package/src/utilities/replication.ts +23 -0
- package/src/utilities/runtime.ts +3 -0
- package/src/utilities/strings.ts +18 -0
- package/src/utilities/types.ts +1 -0
- package/src/utilities/uuid.ts +56 -0
- package/tsconfig.json +28 -0
- package/vitest.config.ts +11 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { EntityUpdateInfo } from "../plugins/types";
|
|
2
|
+
import { InferCreateType, InferType, SchemaId } from "../schema";
|
|
3
|
+
import { TagCollection } from "./TagCollection";
|
|
4
|
+
export class BulkPersistResult extends Map<SchemaId, SchemaPersistResult> {
|
|
5
|
+
|
|
6
|
+
resolve(schemaId: SchemaId): SchemaPersistResult {
|
|
7
|
+
if (this.has(schemaId)) {
|
|
8
|
+
return this.get(schemaId);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
this.set(schemaId, new SchemaPersistResult());
|
|
12
|
+
|
|
13
|
+
return this.get(schemaId);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
override get<T extends {} = Record<string, unknown>>(schemaId: SchemaId) {
|
|
17
|
+
return super.get(schemaId) as SchemaPersistResult<T>
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
get aggregate() {
|
|
21
|
+
return {
|
|
22
|
+
size: this.aggregateSize,
|
|
23
|
+
adds: this.aggregateAddsSize,
|
|
24
|
+
updates: this.aggregateUpdatesSize,
|
|
25
|
+
removes: this.aggregateRemovesSize
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private get aggregateSize() {
|
|
30
|
+
let count = 0;
|
|
31
|
+
|
|
32
|
+
for (const [, result] of this) {
|
|
33
|
+
count += result.total;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return count;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private get aggregateAddsSize() {
|
|
40
|
+
let count = 0;
|
|
41
|
+
|
|
42
|
+
for (const [, result] of this) {
|
|
43
|
+
count += result.adds.length;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return count;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private get aggregateUpdatesSize() {
|
|
50
|
+
let count = 0;
|
|
51
|
+
|
|
52
|
+
for (const [, result] of this) {
|
|
53
|
+
count += result.updates.length;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return count;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private get aggregateRemovesSize() {
|
|
60
|
+
let count = 0;
|
|
61
|
+
|
|
62
|
+
for (const [, result] of this) {
|
|
63
|
+
count += result.removes.length;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return count;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export class BulkPersistChanges extends Map<SchemaId, SchemaPersistChanges> {
|
|
71
|
+
|
|
72
|
+
resolve(schemaId: SchemaId): SchemaPersistChanges {
|
|
73
|
+
if (this.has(schemaId)) {
|
|
74
|
+
return this.get(schemaId);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
this.set(schemaId, new SchemaPersistChanges());
|
|
78
|
+
|
|
79
|
+
return this.get(schemaId);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
override get<T extends {} = Record<string, unknown>>(schemaId: SchemaId) {
|
|
83
|
+
return super.get(schemaId) as SchemaPersistChanges<T>
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
get aggregate() {
|
|
87
|
+
return {
|
|
88
|
+
size: this.aggregateSize,
|
|
89
|
+
adds: this.aggregateAddsSize,
|
|
90
|
+
updates: this.aggregateUpdatesSize,
|
|
91
|
+
removes: this.aggregateRemovesSize
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private get aggregateSize() {
|
|
96
|
+
let count = 0;
|
|
97
|
+
|
|
98
|
+
for (const [, result] of this) {
|
|
99
|
+
count += result.total;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return count;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
private get aggregateAddsSize() {
|
|
106
|
+
let count = 0;
|
|
107
|
+
|
|
108
|
+
for (const [, result] of this) {
|
|
109
|
+
count += result.adds.length;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return count;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private get aggregateUpdatesSize() {
|
|
116
|
+
let count = 0;
|
|
117
|
+
|
|
118
|
+
for (const [, result] of this) {
|
|
119
|
+
count += result.updates.length;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return count;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private get aggregateRemovesSize() {
|
|
126
|
+
let count = 0;
|
|
127
|
+
|
|
128
|
+
for (const [, result] of this) {
|
|
129
|
+
count += result.removes.length;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return count;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Ensures the result has the same result sets as the change sets
|
|
137
|
+
* @returns
|
|
138
|
+
*/
|
|
139
|
+
toResult() {
|
|
140
|
+
const result = new BulkPersistResult();
|
|
141
|
+
|
|
142
|
+
for (const [schemaId] of this) {
|
|
143
|
+
result.set(schemaId, new SchemaPersistResult());
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return result;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export class SchemaPersistChanges<T extends {} = Record<string, unknown>> {
|
|
151
|
+
adds: InferCreateType<T>[] = [];
|
|
152
|
+
updates: EntityUpdateInfo<T>[] = [];
|
|
153
|
+
removes: InferType<T>[] = [];
|
|
154
|
+
tags: TagCollection = new TagCollection();
|
|
155
|
+
|
|
156
|
+
get hasItems() {
|
|
157
|
+
return this.total > 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
get total() {
|
|
161
|
+
return this.adds.length + this.updates.length + this.removes.length;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export class SchemaPersistResult<T extends {} = Record<string, unknown>> {
|
|
166
|
+
adds: InferType<T>[] = [];
|
|
167
|
+
updates: InferType<T>[] = [];
|
|
168
|
+
removes: InferType<T>[] = [];
|
|
169
|
+
|
|
170
|
+
get hasItems() {
|
|
171
|
+
return this.total > 0;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
get total() {
|
|
175
|
+
return this.adds.length + this.updates.length + this.removes.length;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { IdType } from "../schema";
|
|
2
|
+
|
|
3
|
+
export class IdSet {
|
|
4
|
+
|
|
5
|
+
readonly ids: readonly IdType[];
|
|
6
|
+
|
|
7
|
+
constructor(...ids: IdType[]) {
|
|
8
|
+
this.ids = Object.freeze(ids);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
equals(other: IdSet): boolean {
|
|
12
|
+
|
|
13
|
+
if (this.ids.length === 1) {
|
|
14
|
+
return this.ids[0] === other.ids[0];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return this.toString() === other.toString();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
toString(): string {
|
|
21
|
+
|
|
22
|
+
if (this.ids.length === 1) {
|
|
23
|
+
return String(this.ids[0]);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return this.ids.toString();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { MemoryDataCollection } from './MemoryDataCollection';
|
|
3
|
+
import { CompiledSchema, SchemaTypes } from '../schema';
|
|
4
|
+
import { PropertyInfo } from '../schema/PropertyInfo';
|
|
5
|
+
import { Result } from '../results';
|
|
6
|
+
|
|
7
|
+
vi.mock('../utilities/uuid', () => ({
|
|
8
|
+
uuidv4: vi.fn(() => 'mock-uuid-123')
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
describe('EphemeralDataCollection', () => {
|
|
12
|
+
let mockSchema: CompiledSchema<any>;
|
|
13
|
+
let mockIdProperty: PropertyInfo<any>;
|
|
14
|
+
let collection: MemoryDataCollection;
|
|
15
|
+
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
mockIdProperty = {
|
|
18
|
+
id: 'id',
|
|
19
|
+
name: 'id',
|
|
20
|
+
type: SchemaTypes.String,
|
|
21
|
+
getValue: vi.fn((item: any) => item.id),
|
|
22
|
+
setValue: vi.fn(),
|
|
23
|
+
isIdentity: true,
|
|
24
|
+
isKey: true,
|
|
25
|
+
isNullable: false,
|
|
26
|
+
isOptional: false,
|
|
27
|
+
isReadonly: false,
|
|
28
|
+
isUnmapped: false,
|
|
29
|
+
isDistinct: false,
|
|
30
|
+
indexes: [],
|
|
31
|
+
injected: null,
|
|
32
|
+
defaultValue: null,
|
|
33
|
+
valueSerializer: null,
|
|
34
|
+
valueDeserializer: null,
|
|
35
|
+
functionBody: null,
|
|
36
|
+
children: [],
|
|
37
|
+
schema: {} as any,
|
|
38
|
+
literals: [],
|
|
39
|
+
parent: undefined,
|
|
40
|
+
level: 0,
|
|
41
|
+
_getPropertyChain: vi.fn(),
|
|
42
|
+
_needsOptionalChaining: vi.fn(),
|
|
43
|
+
_resolvePathArray: vi.fn(),
|
|
44
|
+
getPathArray: vi.fn(() => ['id']),
|
|
45
|
+
getParentPathArray: vi.fn(),
|
|
46
|
+
hasNullableParents: false,
|
|
47
|
+
hasIdentityChildren: false,
|
|
48
|
+
getSelectrorPath: vi.fn(),
|
|
49
|
+
getAssignmentPath: vi.fn()
|
|
50
|
+
} as any;
|
|
51
|
+
|
|
52
|
+
mockSchema = {
|
|
53
|
+
idProperties: [mockIdProperty],
|
|
54
|
+
hasIdentityKeys: true,
|
|
55
|
+
properties: [mockIdProperty],
|
|
56
|
+
hasIdentities: true,
|
|
57
|
+
hashType: 'Ids' as any,
|
|
58
|
+
hash: vi.fn(),
|
|
59
|
+
getHashType: vi.fn(),
|
|
60
|
+
compare: vi.fn(),
|
|
61
|
+
deserialize: vi.fn(),
|
|
62
|
+
serialize: vi.fn(),
|
|
63
|
+
id: 1,
|
|
64
|
+
collectionName: 'test_collection',
|
|
65
|
+
getIds: vi.fn(),
|
|
66
|
+
enrich: vi.fn(),
|
|
67
|
+
freeze: vi.fn(),
|
|
68
|
+
enableChangeTracking: vi.fn(),
|
|
69
|
+
definition: {} as any,
|
|
70
|
+
getIndexes: vi.fn(() => []),
|
|
71
|
+
createSubscription: vi.fn(),
|
|
72
|
+
getProperty: vi.fn(),
|
|
73
|
+
getId: vi.fn(),
|
|
74
|
+
clone: vi.fn(),
|
|
75
|
+
strip: vi.fn(),
|
|
76
|
+
prepare: vi.fn(),
|
|
77
|
+
merge: vi.fn()
|
|
78
|
+
} as any;
|
|
79
|
+
|
|
80
|
+
collection = new MemoryDataCollection(mockSchema);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('constructor', () => {
|
|
84
|
+
it('should initialize with empty data and numerical ids', () => {
|
|
85
|
+
const newCollection = new MemoryDataCollection(mockSchema);
|
|
86
|
+
|
|
87
|
+
expect(newCollection.size).toBe(0);
|
|
88
|
+
expect(newCollection.records).toEqual([]);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('should store the schema and id properties', () => {
|
|
92
|
+
expect(collection['schema']).toBe(mockSchema);
|
|
93
|
+
expect(collection['idProperties']).toEqual([mockIdProperty]);
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('size', () => {
|
|
98
|
+
it('should return zero for empty collection', () => {
|
|
99
|
+
expect(collection.size).toBe(0);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should return correct size after adding items', () => {
|
|
103
|
+
const item1 = { id: '1', name: 'test1' };
|
|
104
|
+
const item2 = { id: '2', name: 'test2' };
|
|
105
|
+
|
|
106
|
+
collection.add(item1);
|
|
107
|
+
collection.add(item2);
|
|
108
|
+
|
|
109
|
+
expect(collection.size).toBe(2);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('records', () => {
|
|
114
|
+
it('should return empty array for empty collection', () => {
|
|
115
|
+
expect(collection.records).toEqual([]);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should return all records in collection', () => {
|
|
119
|
+
const item1 = { id: '1', name: 'test1' };
|
|
120
|
+
const item2 = { id: '2', name: 'test2' };
|
|
121
|
+
|
|
122
|
+
collection.add(item1);
|
|
123
|
+
collection.add(item2);
|
|
124
|
+
|
|
125
|
+
const records = collection.records;
|
|
126
|
+
expect(records).toHaveLength(2);
|
|
127
|
+
expect(records).toContainEqual(item1);
|
|
128
|
+
expect(records).toContainEqual(item2);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('seed', () => {
|
|
133
|
+
it('should add multiple items to collection', () => {
|
|
134
|
+
const items = [
|
|
135
|
+
{ id: '1', name: 'test1' },
|
|
136
|
+
{ id: '2', name: 'test2' },
|
|
137
|
+
{ id: '3', name: 'test3' }
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
collection.seed(items);
|
|
141
|
+
|
|
142
|
+
expect(collection.size).toBe(3);
|
|
143
|
+
expect(collection.records).toHaveLength(3);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('should handle empty array', () => {
|
|
147
|
+
collection.seed([]);
|
|
148
|
+
|
|
149
|
+
expect(collection.size).toBe(0);
|
|
150
|
+
expect(collection.records).toEqual([]);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should generate ids for items without ids', () => {
|
|
154
|
+
const items = [
|
|
155
|
+
{ id: '1', name: 'test1' },
|
|
156
|
+
{ id: '2', name: 'test2' }
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
collection.seed(items);
|
|
160
|
+
|
|
161
|
+
expect(collection.size).toBe(2);
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
describe('add', () => {
|
|
166
|
+
it('should add item with existing id', () => {
|
|
167
|
+
const item = { id: 'test-id', name: 'test' };
|
|
168
|
+
|
|
169
|
+
collection.add(item);
|
|
170
|
+
|
|
171
|
+
expect(collection.size).toBe(1);
|
|
172
|
+
expect(collection.records).toContainEqual(item);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should generate string id for item without id', () => {
|
|
176
|
+
const item = { name: 'test' } as any;
|
|
177
|
+
|
|
178
|
+
collection.add(item);
|
|
179
|
+
|
|
180
|
+
expect(collection.size).toBe(1);
|
|
181
|
+
expect(item.id).toBe('mock-uuid-123');
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should generate numerical id for numerical id property', () => {
|
|
185
|
+
const numericalIdProperty = {
|
|
186
|
+
...mockIdProperty,
|
|
187
|
+
type: SchemaTypes.Number
|
|
188
|
+
} as any;
|
|
189
|
+
const numericalSchema = {
|
|
190
|
+
...mockSchema,
|
|
191
|
+
idProperties: [numericalIdProperty]
|
|
192
|
+
} as any;
|
|
193
|
+
const numericalCollection = new MemoryDataCollection(numericalSchema);
|
|
194
|
+
const item = { name: 'test' } as any;
|
|
195
|
+
|
|
196
|
+
numericalCollection.add(item);
|
|
197
|
+
|
|
198
|
+
expect(numericalCollection.size).toBe(1);
|
|
199
|
+
expect(item.id).toBe(1);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should throw error for unsupported id type', () => {
|
|
203
|
+
const unsupportedIdProperty = {
|
|
204
|
+
...mockIdProperty,
|
|
205
|
+
type: SchemaTypes.Boolean
|
|
206
|
+
} as any;
|
|
207
|
+
const unsupportedSchema = {
|
|
208
|
+
...mockSchema,
|
|
209
|
+
idProperties: [unsupportedIdProperty]
|
|
210
|
+
} as any;
|
|
211
|
+
const unsupportedCollection = new MemoryDataCollection(unsupportedSchema);
|
|
212
|
+
const item = { name: 'test' } as any;
|
|
213
|
+
|
|
214
|
+
expect(() => unsupportedCollection.add(item)).toThrow(
|
|
215
|
+
"Id Property 'id' must be string or number, found 'Boolean'"
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('should handle multiple id properties', () => {
|
|
220
|
+
const idProperty1 = { ...mockIdProperty, name: 'id1', id: 'id1' } as any;
|
|
221
|
+
const idProperty2 = { ...mockIdProperty, name: 'id2', id: 'id2' } as any;
|
|
222
|
+
const multiIdSchema = {
|
|
223
|
+
...mockSchema,
|
|
224
|
+
idProperties: [idProperty1, idProperty2]
|
|
225
|
+
} as any;
|
|
226
|
+
const multiIdCollection = new MemoryDataCollection(multiIdSchema);
|
|
227
|
+
const item = { name: 'test' } as any;
|
|
228
|
+
|
|
229
|
+
multiIdCollection.add(item);
|
|
230
|
+
|
|
231
|
+
expect(multiIdCollection.size).toBe(1);
|
|
232
|
+
expect(item.id1).toBe('mock-uuid-123');
|
|
233
|
+
expect(item.id2).toBe('mock-uuid-123');
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
describe('remove', () => {
|
|
238
|
+
it('should remove existing item', () => {
|
|
239
|
+
const item = { id: 'test-id', name: 'test' };
|
|
240
|
+
collection.add(item);
|
|
241
|
+
|
|
242
|
+
collection.remove(item);
|
|
243
|
+
|
|
244
|
+
expect(collection.size).toBe(0);
|
|
245
|
+
expect(collection.records).toEqual([]);
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should handle removing non-existent item', () => {
|
|
249
|
+
const item = { id: 'non-existent', name: 'test' };
|
|
250
|
+
|
|
251
|
+
expect(() => collection.remove(item)).not.toThrow();
|
|
252
|
+
expect(collection.size).toBe(0);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should throw error when key is null', () => {
|
|
256
|
+
const item = { id: null, name: 'test' } as any;
|
|
257
|
+
|
|
258
|
+
expect(() => collection.remove(item)).toThrow('Key cannot be null. Key: id');
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it('should handle multiple id properties for removal', () => {
|
|
262
|
+
const idProperty1 = {
|
|
263
|
+
...mockIdProperty,
|
|
264
|
+
name: 'id1',
|
|
265
|
+
id: 'id1',
|
|
266
|
+
getValue: vi.fn((item: any) => item.id1)
|
|
267
|
+
} as any;
|
|
268
|
+
const idProperty2 = {
|
|
269
|
+
...mockIdProperty,
|
|
270
|
+
name: 'id2',
|
|
271
|
+
id: 'id2',
|
|
272
|
+
getValue: vi.fn((item: any) => item.id2)
|
|
273
|
+
} as any;
|
|
274
|
+
const multiIdSchema = {
|
|
275
|
+
...mockSchema,
|
|
276
|
+
idProperties: [idProperty1, idProperty2],
|
|
277
|
+
hasIdentityKeys: false
|
|
278
|
+
} as any;
|
|
279
|
+
const multiIdCollection = new MemoryDataCollection(multiIdSchema);
|
|
280
|
+
const item = { id1: '1', id2: '2', name: 'test' };
|
|
281
|
+
|
|
282
|
+
multiIdCollection.add(item);
|
|
283
|
+
multiIdCollection.remove(item);
|
|
284
|
+
|
|
285
|
+
expect(multiIdCollection.size).toBe(0);
|
|
286
|
+
});
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
describe('update', () => {
|
|
290
|
+
it('should update existing item', () => {
|
|
291
|
+
const item = { id: 'test-id', name: 'test' };
|
|
292
|
+
collection.add(item);
|
|
293
|
+
|
|
294
|
+
item.name = 'updated';
|
|
295
|
+
collection.update(item);
|
|
296
|
+
|
|
297
|
+
expect(collection.size).toBe(1);
|
|
298
|
+
expect(collection.records[0].name).toBe('updated');
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('should add item if it does not exist', () => {
|
|
302
|
+
const item = { id: 'new-id', name: 'new' };
|
|
303
|
+
|
|
304
|
+
collection.update(item);
|
|
305
|
+
|
|
306
|
+
expect(collection.size).toBe(1);
|
|
307
|
+
expect(collection.records).toContainEqual(item);
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('should throw error when key is null', () => {
|
|
311
|
+
const item = { id: null, name: 'test' } as any;
|
|
312
|
+
|
|
313
|
+
expect(() => collection.update(item)).toThrow('Key cannot be null. Key: id');
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
describe('destroy', () => {
|
|
318
|
+
it('should clear all data and numerical ids', () => {
|
|
319
|
+
const item1 = { id: '1', name: 'test1' };
|
|
320
|
+
const item2 = { id: '2', name: 'test2' };
|
|
321
|
+
|
|
322
|
+
collection.add(item1);
|
|
323
|
+
collection.add(item2);
|
|
324
|
+
|
|
325
|
+
const mockCallback = vi.fn();
|
|
326
|
+
collection.destroy(mockCallback);
|
|
327
|
+
|
|
328
|
+
expect(collection.size).toBe(0);
|
|
329
|
+
expect(collection.records).toEqual([]);
|
|
330
|
+
expect(mockCallback).toHaveBeenCalledWith(Result.success());
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('should handle destroy on empty collection', () => {
|
|
334
|
+
const mockCallback = vi.fn();
|
|
335
|
+
collection.destroy(mockCallback);
|
|
336
|
+
|
|
337
|
+
expect(collection.size).toBe(0);
|
|
338
|
+
expect(mockCallback).toHaveBeenCalledWith(Result.success());
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
describe('id generation', () => {
|
|
343
|
+
it('should increment numerical ids correctly', () => {
|
|
344
|
+
const numericalIdProperty = {
|
|
345
|
+
...mockIdProperty,
|
|
346
|
+
type: SchemaTypes.Number
|
|
347
|
+
} as any;
|
|
348
|
+
const numericalSchema = {
|
|
349
|
+
...mockSchema,
|
|
350
|
+
idProperties: [numericalIdProperty]
|
|
351
|
+
} as any;
|
|
352
|
+
const numericalCollection = new MemoryDataCollection(numericalSchema);
|
|
353
|
+
|
|
354
|
+
const item1 = { name: 'test1' } as any;
|
|
355
|
+
const item2 = { name: 'test2' } as any;
|
|
356
|
+
const item3 = { name: 'test3' } as any;
|
|
357
|
+
|
|
358
|
+
numericalCollection.add(item1);
|
|
359
|
+
numericalCollection.add(item2);
|
|
360
|
+
numericalCollection.add(item3);
|
|
361
|
+
|
|
362
|
+
expect(item1.id).toBe(1);
|
|
363
|
+
expect(item2.id).toBe(2);
|
|
364
|
+
expect(item3.id).toBe(3);
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('should handle numerical ids with existing values', () => {
|
|
368
|
+
const numericalIdProperty = {
|
|
369
|
+
...mockIdProperty,
|
|
370
|
+
type: SchemaTypes.Number
|
|
371
|
+
} as any;
|
|
372
|
+
const numericalSchema = {
|
|
373
|
+
...mockSchema,
|
|
374
|
+
idProperties: [numericalIdProperty]
|
|
375
|
+
} as any;
|
|
376
|
+
const numericalCollection = new MemoryDataCollection(numericalSchema);
|
|
377
|
+
|
|
378
|
+
const item1 = { id: 5, name: 'test1' };
|
|
379
|
+
const item2 = { name: 'test2' } as any;
|
|
380
|
+
|
|
381
|
+
numericalCollection.add(item1);
|
|
382
|
+
numericalCollection.add(item2);
|
|
383
|
+
|
|
384
|
+
expect(item1.id).toBe(5);
|
|
385
|
+
expect(item2.id).toBe(1);
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
describe('edge cases', () => {
|
|
390
|
+
it('should handle schema without identity keys', () => {
|
|
391
|
+
const nonIdentitySchema = {
|
|
392
|
+
...mockSchema,
|
|
393
|
+
hasIdentityKeys: false
|
|
394
|
+
} as any;
|
|
395
|
+
const nonIdentityCollection = new MemoryDataCollection(nonIdentitySchema);
|
|
396
|
+
const item = { id: 'existing-id', name: 'test' };
|
|
397
|
+
|
|
398
|
+
nonIdentityCollection.add(item);
|
|
399
|
+
|
|
400
|
+
expect(nonIdentityCollection.size).toBe(1);
|
|
401
|
+
expect(nonIdentityCollection.records).toContainEqual(item);
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
it('should handle items with undefined id properties', () => {
|
|
405
|
+
const item = { name: 'test' } as any;
|
|
406
|
+
|
|
407
|
+
collection.add(item);
|
|
408
|
+
|
|
409
|
+
expect(collection.size).toBe(1);
|
|
410
|
+
expect(item.id).toBeDefined();
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it('should handle multiple items with same id', () => {
|
|
414
|
+
const item1 = { id: 'same-id', name: 'test1' };
|
|
415
|
+
const item2 = { id: 'same-id', name: 'test2' };
|
|
416
|
+
|
|
417
|
+
collection.add(item1);
|
|
418
|
+
collection.add(item2);
|
|
419
|
+
|
|
420
|
+
expect(collection.size).toBe(1);
|
|
421
|
+
expect(collection.records).toContainEqual(item2);
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
});
|