@tldraw/store 5.2.0-next.ee0fa4d6244f → 5.2.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/DOCS.md +790 -0
- package/README.md +9 -1
- package/dist-cjs/index.js +1 -1
- package/dist-cjs/lib/ImmutableMap.js +0 -13
- package/dist-cjs/lib/ImmutableMap.js.map +2 -2
- package/dist-cjs/lib/RecordType.js +1 -1
- package/dist-cjs/lib/RecordType.js.map +2 -2
- package/dist-cjs/lib/RecordsDiff.js +26 -14
- package/dist-cjs/lib/RecordsDiff.js.map +2 -2
- package/dist-cjs/lib/Store.js +6 -5
- package/dist-cjs/lib/Store.js.map +2 -2
- package/dist-cjs/lib/StoreSchema.js +1 -1
- package/dist-cjs/lib/StoreSchema.js.map +2 -2
- package/dist-cjs/lib/executeQuery.js +1 -1
- package/dist-cjs/lib/executeQuery.js.map +2 -2
- package/dist-esm/index.mjs +1 -1
- package/dist-esm/lib/ImmutableMap.mjs +0 -13
- package/dist-esm/lib/ImmutableMap.mjs.map +2 -2
- package/dist-esm/lib/RecordType.mjs +1 -1
- package/dist-esm/lib/RecordType.mjs.map +2 -2
- package/dist-esm/lib/RecordsDiff.mjs +26 -14
- package/dist-esm/lib/RecordsDiff.mjs.map +2 -2
- package/dist-esm/lib/Store.mjs +7 -6
- package/dist-esm/lib/Store.mjs.map +2 -2
- package/dist-esm/lib/StoreSchema.mjs +1 -1
- package/dist-esm/lib/StoreSchema.mjs.map +2 -2
- package/dist-esm/lib/executeQuery.mjs +1 -1
- package/dist-esm/lib/executeQuery.mjs.map +2 -2
- package/package.json +9 -5
- package/src/lib/{test/AtomMap.test.ts → AtomMap.test.ts} +77 -111
- package/src/lib/AtomSet.test.ts +116 -0
- package/src/lib/BaseRecord.test.ts +10 -22
- package/src/lib/ImmutableMap.test.ts +114 -71
- package/src/lib/ImmutableMap.ts +1 -0
- package/src/lib/IncrementalSetConstructor.test.ts +76 -81
- package/src/lib/RecordType.test.ts +216 -0
- package/src/lib/RecordType.ts +1 -1
- package/src/lib/RecordsDiff.test.ts +112 -106
- package/src/lib/RecordsDiff.ts +43 -18
- package/src/lib/Store.test.ts +570 -630
- package/src/lib/Store.ts +9 -10
- package/src/lib/StoreListeners.test.ts +462 -0
- package/src/lib/StoreQueries.test.ts +586 -434
- package/src/lib/StoreSchema.test.ts +1012 -174
- package/src/lib/StoreSchema.ts +1 -1
- package/src/lib/StoreSideEffects.test.ts +546 -158
- package/src/lib/devFreeze.test.ts +94 -124
- package/src/lib/executeQuery.test.ts +77 -31
- package/src/lib/executeQuery.ts +3 -1
- package/src/lib/migrate.test.ts +273 -296
- package/src/lib/setUtils.test.ts +38 -79
- package/src/lib/test/createMigrations.test.ts +0 -75
- package/src/lib/test/dependsOn.test.ts +0 -166
- package/src/lib/test/getMigrationsSince.test.ts +0 -121
- package/src/lib/test/migrate.test.ts +0 -118
- package/src/lib/test/migratePersistedRecord.test.ts +0 -265
- package/src/lib/test/migrationCaching.test.ts +0 -209
- package/src/lib/test/recordStore.test.ts +0 -1567
- package/src/lib/test/recordStoreQueries.test.ts +0 -814
- package/src/lib/test/recordType.test.ts +0 -19
- package/src/lib/test/sortMigrations.test.ts +0 -83
- package/src/lib/test/upgradeSchema.test.ts +0 -80
- package/src/lib/test/validate.test.ts +0 -178
- package/src/lib/test/validateMigrations.test.ts +0 -165
package/src/lib/setUtils.test.ts
CHANGED
|
@@ -1,105 +1,64 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest'
|
|
2
2
|
import { diffSets, intersectSets } from './setUtils'
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const set1 = new Set([1, 2, 3, 4])
|
|
7
|
-
const set2 = new Set([2, 3, 4, 5])
|
|
8
|
-
const set3 = new Set([3, 4, 5, 6])
|
|
4
|
+
// Tests for SPEC.md §25 (set utilities).
|
|
5
|
+
// Rule IDs like [SU1] in test names refer to that document.
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
describe('intersectSets (SU)', () => {
|
|
8
|
+
it('[SU1] returns the elements present in every set', () => {
|
|
9
|
+
expect(
|
|
10
|
+
intersectSets([new Set([1, 2, 3, 4]), new Set([2, 3, 4, 5]), new Set([3, 4, 5, 6])])
|
|
11
|
+
).toEqual(new Set([3, 4]))
|
|
11
12
|
|
|
12
|
-
expect(
|
|
13
|
+
expect(intersectSets([new Set([1, 2, 3]), new Set([4, 5, 6])])).toEqual(new Set())
|
|
14
|
+
expect(intersectSets([new Set([1, 2, 3]), new Set(), new Set([2, 3, 4])])).toEqual(new Set())
|
|
13
15
|
})
|
|
14
16
|
|
|
15
|
-
it('
|
|
16
|
-
|
|
17
|
-
expect(result.size).toBe(0)
|
|
17
|
+
it('[SU1] no sets yields an empty set', () => {
|
|
18
|
+
expect(intersectSets([])).toEqual(new Set())
|
|
18
19
|
})
|
|
19
20
|
|
|
20
|
-
it('
|
|
21
|
-
const
|
|
22
|
-
const
|
|
21
|
+
it('[SU1] a single set yields a copy', () => {
|
|
22
|
+
const set = new Set([1, 2, 3])
|
|
23
|
+
const result = intersectSets([set])
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
expect(result.size).toBe(0)
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('should return empty set when any set is empty', () => {
|
|
30
|
-
const set1 = new Set([1, 2, 3])
|
|
31
|
-
const set2 = new Set<number>()
|
|
32
|
-
const set3 = new Set([2, 3, 4])
|
|
33
|
-
|
|
34
|
-
const result = intersectSets([set1, set2, set3])
|
|
35
|
-
|
|
36
|
-
expect(result.size).toBe(0)
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
it('should return copy of single set', () => {
|
|
40
|
-
const set1 = new Set([1, 2, 3])
|
|
41
|
-
const result = intersectSets([set1])
|
|
42
|
-
|
|
43
|
-
expect(result).not.toBe(set1)
|
|
44
|
-
expect(Array.from(result).sort()).toEqual([1, 2, 3])
|
|
25
|
+
expect(result).not.toBe(set)
|
|
26
|
+
expect(result).toEqual(set)
|
|
45
27
|
})
|
|
46
28
|
})
|
|
47
29
|
|
|
48
|
-
describe('diffSets', () => {
|
|
49
|
-
it('
|
|
50
|
-
|
|
51
|
-
|
|
30
|
+
describe('diffSets (SU)', () => {
|
|
31
|
+
it('[SU2] reports added and removed elements, with only the populated keys', () => {
|
|
32
|
+
expect(diffSets(new Set(['a', 'b']), new Set(['a', 'b', 'c']))).toEqual({
|
|
33
|
+
added: new Set(['c']),
|
|
34
|
+
})
|
|
52
35
|
|
|
53
|
-
|
|
36
|
+
expect(diffSets(new Set(['a', 'b', 'c']), new Set(['a', 'b']))).toEqual({
|
|
37
|
+
removed: new Set(['c']),
|
|
38
|
+
})
|
|
54
39
|
|
|
55
|
-
expect(
|
|
56
|
-
|
|
57
|
-
|
|
40
|
+
expect(diffSets(new Set(['a', 'b']), new Set(['b', 'c']))).toEqual({
|
|
41
|
+
added: new Set(['c']),
|
|
42
|
+
removed: new Set(['a']),
|
|
43
|
+
})
|
|
58
44
|
})
|
|
59
45
|
|
|
60
|
-
it('
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const result = diffSets(prev, next)
|
|
65
|
-
|
|
66
|
-
expect(result?.removed).toBeDefined()
|
|
67
|
-
expect(result?.added).toBeUndefined()
|
|
68
|
-
expect(Array.from(result!.removed!)).toEqual(['c'])
|
|
46
|
+
it('[SU2] returns undefined when the sets have the same members', () => {
|
|
47
|
+
expect(diffSets(new Set(['a', 'b', 'c']), new Set(['a', 'b', 'c']))).toBeUndefined()
|
|
48
|
+
expect(diffSets(new Set(), new Set())).toBeUndefined()
|
|
69
49
|
})
|
|
70
50
|
|
|
71
|
-
it('
|
|
72
|
-
const prev = new Set(['a', 'b'])
|
|
73
|
-
const next = new Set(['b', 'c'])
|
|
74
|
-
|
|
75
|
-
const result = diffSets(prev, next)
|
|
76
|
-
|
|
77
|
-
expect(result?.added).toBeDefined()
|
|
78
|
-
expect(result?.removed).toBeDefined()
|
|
79
|
-
expect(Array.from(result!.added!)).toEqual(['c'])
|
|
80
|
-
expect(Array.from(result!.removed!)).toEqual(['a'])
|
|
81
|
-
})
|
|
82
|
-
|
|
83
|
-
it('should return undefined when sets are identical', () => {
|
|
84
|
-
const prev = new Set(['a', 'b', 'c'])
|
|
85
|
-
const next = new Set(['a', 'b', 'c'])
|
|
86
|
-
|
|
87
|
-
const result = diffSets(prev, next)
|
|
88
|
-
|
|
89
|
-
expect(result).toBeUndefined()
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
it('should handle object references correctly', () => {
|
|
51
|
+
it('[SU2] compares object members by reference', () => {
|
|
93
52
|
const obj1 = { id: 1 }
|
|
94
53
|
const obj2 = { id: 2 }
|
|
95
54
|
const obj3 = { id: 3 }
|
|
96
55
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
56
|
+
expect(diffSets(new Set([obj1, obj2]), new Set([obj2, obj3]))).toEqual({
|
|
57
|
+
added: new Set([obj3]),
|
|
58
|
+
removed: new Set([obj1]),
|
|
59
|
+
})
|
|
101
60
|
|
|
102
|
-
|
|
103
|
-
expect(
|
|
61
|
+
// structurally equal but distinct objects are different members
|
|
62
|
+
expect(diffSets(new Set([{ id: 1 }]), new Set([{ id: 1 }]))).toBeDefined()
|
|
104
63
|
})
|
|
105
64
|
})
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { createMigrationSequence } from '../migrate'
|
|
2
|
-
|
|
3
|
-
describe(createMigrationSequence, () => {
|
|
4
|
-
it('allows dependsOn to be deferred', () => {
|
|
5
|
-
expect(
|
|
6
|
-
createMigrationSequence({
|
|
7
|
-
sequenceId: 'foo',
|
|
8
|
-
retroactive: false,
|
|
9
|
-
sequence: [{ dependsOn: ['bar/1'] }],
|
|
10
|
-
}).sequence.length
|
|
11
|
-
).toBe(0)
|
|
12
|
-
|
|
13
|
-
const result = createMigrationSequence({
|
|
14
|
-
sequenceId: 'foo',
|
|
15
|
-
retroactive: false,
|
|
16
|
-
sequence: [
|
|
17
|
-
{
|
|
18
|
-
id: 'foo/1',
|
|
19
|
-
scope: 'record',
|
|
20
|
-
up() {
|
|
21
|
-
// noop
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
{ dependsOn: ['bar/1'] },
|
|
25
|
-
],
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
expect(result.sequence.length).toBe(1)
|
|
29
|
-
expect(result.sequence[0].dependsOn?.length).toBeFalsy()
|
|
30
|
-
|
|
31
|
-
const result2 = createMigrationSequence({
|
|
32
|
-
sequenceId: 'foo',
|
|
33
|
-
retroactive: false,
|
|
34
|
-
sequence: [
|
|
35
|
-
{ dependsOn: ['bar/1'] },
|
|
36
|
-
{
|
|
37
|
-
id: 'foo/1',
|
|
38
|
-
scope: 'record',
|
|
39
|
-
up() {
|
|
40
|
-
// noop
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
],
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
expect(result2.sequence.length).toBe(1)
|
|
47
|
-
expect(result2.sequence[0].dependsOn).toEqual(['bar/1'])
|
|
48
|
-
|
|
49
|
-
const result3 = createMigrationSequence({
|
|
50
|
-
sequenceId: 'foo',
|
|
51
|
-
retroactive: false,
|
|
52
|
-
sequence: [
|
|
53
|
-
{
|
|
54
|
-
id: 'foo/1',
|
|
55
|
-
scope: 'record',
|
|
56
|
-
up() {
|
|
57
|
-
// noop
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
{ dependsOn: ['bar/1'] },
|
|
61
|
-
{
|
|
62
|
-
id: 'foo/2',
|
|
63
|
-
scope: 'record',
|
|
64
|
-
up() {
|
|
65
|
-
// noop
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
expect(result3.sequence.length).toBe(2)
|
|
72
|
-
expect(result3.sequence[0].dependsOn?.length).toBeFalsy()
|
|
73
|
-
expect(result3.sequence[1].dependsOn).toEqual(['bar/1'])
|
|
74
|
-
})
|
|
75
|
-
})
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import { MigrationSequence, createMigrationSequence } from '../migrate'
|
|
2
|
-
import { StoreSchema } from '../StoreSchema'
|
|
3
|
-
|
|
4
|
-
describe('dependsOn', () => {
|
|
5
|
-
it('requires the depended on ids to be present', () => {
|
|
6
|
-
expect(() => {
|
|
7
|
-
StoreSchema.create(
|
|
8
|
-
{},
|
|
9
|
-
{
|
|
10
|
-
migrations: [
|
|
11
|
-
{
|
|
12
|
-
sequenceId: 'foo',
|
|
13
|
-
retroactive: false,
|
|
14
|
-
sequence: [
|
|
15
|
-
{
|
|
16
|
-
id: 'foo/1',
|
|
17
|
-
dependsOn: ['bar/1'],
|
|
18
|
-
scope: 'record',
|
|
19
|
-
up() {
|
|
20
|
-
// noop
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
],
|
|
24
|
-
},
|
|
25
|
-
],
|
|
26
|
-
}
|
|
27
|
-
)
|
|
28
|
-
}).toThrowErrorMatchingInlineSnapshot(
|
|
29
|
-
`[Error: Migration 'foo/1' depends on missing migration 'bar/1']`
|
|
30
|
-
)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
it('makes sure the migrations are sorted', () => {
|
|
34
|
-
const foo: MigrationSequence = {
|
|
35
|
-
sequenceId: 'foo',
|
|
36
|
-
retroactive: false,
|
|
37
|
-
sequence: [
|
|
38
|
-
{
|
|
39
|
-
id: 'foo/1',
|
|
40
|
-
dependsOn: ['bar/1'],
|
|
41
|
-
scope: 'record',
|
|
42
|
-
up() {
|
|
43
|
-
// noop
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
],
|
|
47
|
-
}
|
|
48
|
-
const bar: MigrationSequence = {
|
|
49
|
-
sequenceId: 'bar',
|
|
50
|
-
retroactive: false,
|
|
51
|
-
sequence: [
|
|
52
|
-
{
|
|
53
|
-
id: 'bar/1',
|
|
54
|
-
scope: 'record',
|
|
55
|
-
up() {
|
|
56
|
-
// noop
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
}
|
|
61
|
-
const s = StoreSchema.create(
|
|
62
|
-
{},
|
|
63
|
-
{
|
|
64
|
-
migrations: [foo, bar],
|
|
65
|
-
}
|
|
66
|
-
)
|
|
67
|
-
const s2 = StoreSchema.create(
|
|
68
|
-
{},
|
|
69
|
-
{
|
|
70
|
-
migrations: [bar, foo],
|
|
71
|
-
}
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
expect(s.sortedMigrations.map((s) => s.id)).toMatchInlineSnapshot(`
|
|
75
|
-
[
|
|
76
|
-
"bar/1",
|
|
77
|
-
"foo/1",
|
|
78
|
-
]
|
|
79
|
-
`)
|
|
80
|
-
expect(s2.sortedMigrations).toEqual(s.sortedMigrations)
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
describe('standalone dependsOn', () => {
|
|
85
|
-
it('requires the depended on ids to be present', () => {
|
|
86
|
-
expect(() => {
|
|
87
|
-
StoreSchema.create(
|
|
88
|
-
{},
|
|
89
|
-
{
|
|
90
|
-
migrations: [
|
|
91
|
-
createMigrationSequence({
|
|
92
|
-
sequenceId: 'foo',
|
|
93
|
-
retroactive: false,
|
|
94
|
-
sequence: [
|
|
95
|
-
{
|
|
96
|
-
dependsOn: ['bar/1'],
|
|
97
|
-
},
|
|
98
|
-
{
|
|
99
|
-
id: 'foo/1',
|
|
100
|
-
scope: 'record',
|
|
101
|
-
up() {
|
|
102
|
-
// noop
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
],
|
|
106
|
-
}),
|
|
107
|
-
],
|
|
108
|
-
}
|
|
109
|
-
)
|
|
110
|
-
}).toThrowErrorMatchingInlineSnapshot(
|
|
111
|
-
`[Error: Migration 'foo/1' depends on missing migration 'bar/1']`
|
|
112
|
-
)
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('makes sure the migrations are sorted', () => {
|
|
116
|
-
const foo: MigrationSequence = createMigrationSequence({
|
|
117
|
-
sequenceId: 'foo',
|
|
118
|
-
retroactive: false,
|
|
119
|
-
sequence: [
|
|
120
|
-
{
|
|
121
|
-
dependsOn: ['bar/1'],
|
|
122
|
-
},
|
|
123
|
-
{
|
|
124
|
-
id: 'foo/1',
|
|
125
|
-
scope: 'record',
|
|
126
|
-
up() {
|
|
127
|
-
// noop
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
],
|
|
131
|
-
})
|
|
132
|
-
const bar: MigrationSequence = createMigrationSequence({
|
|
133
|
-
sequenceId: 'bar',
|
|
134
|
-
retroactive: false,
|
|
135
|
-
sequence: [
|
|
136
|
-
{
|
|
137
|
-
id: 'bar/1',
|
|
138
|
-
scope: 'record',
|
|
139
|
-
up() {
|
|
140
|
-
// noop
|
|
141
|
-
},
|
|
142
|
-
},
|
|
143
|
-
],
|
|
144
|
-
})
|
|
145
|
-
const s = StoreSchema.create(
|
|
146
|
-
{},
|
|
147
|
-
{
|
|
148
|
-
migrations: [foo, bar],
|
|
149
|
-
}
|
|
150
|
-
)
|
|
151
|
-
const s2 = StoreSchema.create(
|
|
152
|
-
{},
|
|
153
|
-
{
|
|
154
|
-
migrations: [bar, foo],
|
|
155
|
-
}
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
expect(s.sortedMigrations.map((s) => s.id)).toMatchInlineSnapshot(`
|
|
159
|
-
[
|
|
160
|
-
"bar/1",
|
|
161
|
-
"foo/1",
|
|
162
|
-
]
|
|
163
|
-
`)
|
|
164
|
-
expect(s2.sortedMigrations).toEqual(s.sortedMigrations)
|
|
165
|
-
})
|
|
166
|
-
})
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import { MigrationSequence } from '../migrate'
|
|
2
|
-
import { SerializedSchemaV2, StoreSchema } from '../StoreSchema'
|
|
3
|
-
|
|
4
|
-
const mockSequence = ({
|
|
5
|
-
id,
|
|
6
|
-
retroactive,
|
|
7
|
-
versions,
|
|
8
|
-
}: {
|
|
9
|
-
id: string
|
|
10
|
-
retroactive: boolean
|
|
11
|
-
versions: number
|
|
12
|
-
}) =>
|
|
13
|
-
({
|
|
14
|
-
sequenceId: id,
|
|
15
|
-
retroactive,
|
|
16
|
-
sequence: new Array(versions).fill(0).map((_, i) => ({
|
|
17
|
-
id: `${id}/${i + 1}`,
|
|
18
|
-
scope: 'record',
|
|
19
|
-
up() {
|
|
20
|
-
// noop
|
|
21
|
-
},
|
|
22
|
-
})),
|
|
23
|
-
}) satisfies MigrationSequence
|
|
24
|
-
|
|
25
|
-
function getMigrationsBetween(
|
|
26
|
-
serialized: SerializedSchemaV2['sequences'],
|
|
27
|
-
current: MigrationSequence[]
|
|
28
|
-
) {
|
|
29
|
-
const schema = StoreSchema.create({}, { migrations: current })
|
|
30
|
-
const ms = schema.getMigrationsSince({ schemaVersion: 2, sequences: serialized })
|
|
31
|
-
if (!ms.ok) {
|
|
32
|
-
throw new Error('Expected migrations to be found')
|
|
33
|
-
}
|
|
34
|
-
return ms.value.map((m) => m.id)
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
describe('getMigrationsSince', () => {
|
|
38
|
-
it('includes migrations from new migration sequences with retroactive: true', () => {
|
|
39
|
-
const foo = mockSequence({ id: 'foo', retroactive: true, versions: 2 })
|
|
40
|
-
const bar = mockSequence({ id: 'bar', retroactive: true, versions: 3 })
|
|
41
|
-
|
|
42
|
-
const ids = getMigrationsBetween({}, [foo, bar])
|
|
43
|
-
const foos = ids.filter((id) => id.startsWith('foo'))
|
|
44
|
-
const bars = ids.filter((id) => id.startsWith('bar'))
|
|
45
|
-
|
|
46
|
-
expect(foos).toEqual(['foo/1', 'foo/2'])
|
|
47
|
-
expect(bars).toEqual(['bar/1', 'bar/2', 'bar/3'])
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('does not include migrations from new migration sequences with retroactive: false', () => {
|
|
51
|
-
const foo = mockSequence({ id: 'foo', retroactive: true, versions: 2 })
|
|
52
|
-
const bar = mockSequence({ id: 'bar', retroactive: false, versions: 3 })
|
|
53
|
-
|
|
54
|
-
const ids = getMigrationsBetween({}, [foo, bar])
|
|
55
|
-
const foos = ids.filter((id) => id.startsWith('foo'))
|
|
56
|
-
const bars = ids.filter((id) => id.startsWith('bar'))
|
|
57
|
-
|
|
58
|
-
expect(foos).toEqual(['foo/1', 'foo/2'])
|
|
59
|
-
expect(bars).toEqual([])
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it('returns the empty array if there are no overlapping sequences and new ones are retroactive: false', () => {
|
|
63
|
-
const foo = mockSequence({ id: 'foo', retroactive: false, versions: 2 })
|
|
64
|
-
const bar = mockSequence({ id: 'bar', retroactive: false, versions: 3 })
|
|
65
|
-
|
|
66
|
-
const ids = getMigrationsBetween({}, [foo, bar])
|
|
67
|
-
expect(ids).toEqual([])
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('if a sequence is present both before and now, unapplied migrations will be returned', () => {
|
|
71
|
-
const foo = mockSequence({ id: 'foo', retroactive: true, versions: 2 })
|
|
72
|
-
const bar = mockSequence({ id: 'bar', retroactive: false, versions: 3 })
|
|
73
|
-
const ids = getMigrationsBetween({ foo: 1, bar: 1 }, [foo, bar])
|
|
74
|
-
|
|
75
|
-
const foos = ids.filter((id) => id.startsWith('foo'))
|
|
76
|
-
const bars = ids.filter((id) => id.startsWith('bar'))
|
|
77
|
-
|
|
78
|
-
expect(foos).toEqual(['foo/2'])
|
|
79
|
-
expect(bars).toEqual(['bar/2', 'bar/3'])
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
it('if a sequence has not changed the empty array will be returned', () => {
|
|
83
|
-
const foo = mockSequence({ id: 'foo', retroactive: true, versions: 2 })
|
|
84
|
-
const bar = mockSequence({ id: 'bar', retroactive: false, versions: 3 })
|
|
85
|
-
const ids = getMigrationsBetween({ foo: 2, bar: 3 }, [foo, bar])
|
|
86
|
-
|
|
87
|
-
expect(ids).toEqual([])
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('if a sequence starts with 0 all unapplied migrations will be returned', () => {
|
|
91
|
-
const foo = mockSequence({ id: 'foo', retroactive: true, versions: 2 })
|
|
92
|
-
const bar = mockSequence({ id: 'bar', retroactive: false, versions: 3 })
|
|
93
|
-
|
|
94
|
-
const ids = getMigrationsBetween(
|
|
95
|
-
{
|
|
96
|
-
foo: 0,
|
|
97
|
-
bar: 0,
|
|
98
|
-
},
|
|
99
|
-
[foo, bar]
|
|
100
|
-
)
|
|
101
|
-
const foos = ids.filter((id) => id.startsWith('foo'))
|
|
102
|
-
const bars = ids.filter((id) => id.startsWith('bar'))
|
|
103
|
-
|
|
104
|
-
expect(foos).toEqual(['foo/1', 'foo/2'])
|
|
105
|
-
expect(bars).toEqual(['bar/1', 'bar/2', 'bar/3'])
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('if a sequence starts with 0 and has 0 new migrations, no migrations will be returned', () => {
|
|
109
|
-
const foo = mockSequence({ id: 'foo', retroactive: true, versions: 0 })
|
|
110
|
-
const bar = mockSequence({ id: 'bar', retroactive: false, versions: 0 })
|
|
111
|
-
|
|
112
|
-
const ids = getMigrationsBetween(
|
|
113
|
-
{
|
|
114
|
-
foo: 0,
|
|
115
|
-
bar: 0,
|
|
116
|
-
},
|
|
117
|
-
[foo, bar]
|
|
118
|
-
)
|
|
119
|
-
expect(ids).toEqual([])
|
|
120
|
-
})
|
|
121
|
-
})
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { SerializedStore } from '../Store'
|
|
2
|
-
import { testSchemaV0 } from './testSchema.v0'
|
|
3
|
-
import { testSchemaV1 } from './testSchema.v1'
|
|
4
|
-
|
|
5
|
-
const serializedV0Schenma = testSchemaV0.serialize()
|
|
6
|
-
const serializedV1Schenma = testSchemaV1.serialize()
|
|
7
|
-
|
|
8
|
-
test('serializedV0Schenma', () => {
|
|
9
|
-
expect(serializedV0Schenma).toMatchInlineSnapshot(`
|
|
10
|
-
{
|
|
11
|
-
"schemaVersion": 2,
|
|
12
|
-
"sequences": {},
|
|
13
|
-
}
|
|
14
|
-
`)
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
test('serializedV1Schenma', () => {
|
|
18
|
-
expect(serializedV1Schenma).toMatchInlineSnapshot(`
|
|
19
|
-
{
|
|
20
|
-
"schemaVersion": 2,
|
|
21
|
-
"sequences": {
|
|
22
|
-
"com.tldraw.shape": 2,
|
|
23
|
-
"com.tldraw.shape.oval": 1,
|
|
24
|
-
"com.tldraw.shape.rectangle": 1,
|
|
25
|
-
"com.tldraw.store": 1,
|
|
26
|
-
"com.tldraw.user": 2,
|
|
27
|
-
},
|
|
28
|
-
}
|
|
29
|
-
`)
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
test('unknown types fail', () => {
|
|
33
|
-
expect(
|
|
34
|
-
testSchemaV1.migratePersistedRecord(
|
|
35
|
-
{
|
|
36
|
-
id: 'whatevere',
|
|
37
|
-
typeName: 'steve',
|
|
38
|
-
} as any,
|
|
39
|
-
serializedV0Schenma,
|
|
40
|
-
'up'
|
|
41
|
-
)
|
|
42
|
-
).toMatchObject({
|
|
43
|
-
type: 'error',
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
expect(
|
|
47
|
-
testSchemaV1.migratePersistedRecord(
|
|
48
|
-
{
|
|
49
|
-
id: 'whatevere',
|
|
50
|
-
typeName: 'jeff',
|
|
51
|
-
} as any,
|
|
52
|
-
serializedV0Schenma,
|
|
53
|
-
'down'
|
|
54
|
-
)
|
|
55
|
-
).toMatchObject({
|
|
56
|
-
type: 'error',
|
|
57
|
-
})
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
test('migrating a whole store snapshot works', () => {
|
|
61
|
-
const serializedStore: SerializedStore<any> = {
|
|
62
|
-
'user-1': {
|
|
63
|
-
id: 'user-1',
|
|
64
|
-
typeName: 'user',
|
|
65
|
-
name: 'name',
|
|
66
|
-
},
|
|
67
|
-
'shape-1': {
|
|
68
|
-
id: 'shape-1',
|
|
69
|
-
typeName: 'shape',
|
|
70
|
-
x: 0,
|
|
71
|
-
y: 0,
|
|
72
|
-
type: 'rectangle',
|
|
73
|
-
props: {
|
|
74
|
-
width: 100,
|
|
75
|
-
height: 100,
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
'org-1': {
|
|
79
|
-
id: 'org-1',
|
|
80
|
-
typeName: 'org',
|
|
81
|
-
name: 'tldraw',
|
|
82
|
-
},
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const result = testSchemaV1.migrateStoreSnapshot({
|
|
86
|
-
store: serializedStore,
|
|
87
|
-
schema: serializedV0Schenma,
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
if (result.type !== 'success') {
|
|
91
|
-
console.error(result)
|
|
92
|
-
throw new Error('Migration failed')
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
expect(result.value).toEqual({
|
|
96
|
-
'shape-1': {
|
|
97
|
-
id: 'shape-1',
|
|
98
|
-
typeName: 'shape',
|
|
99
|
-
x: 0,
|
|
100
|
-
y: 0,
|
|
101
|
-
type: 'rectangle',
|
|
102
|
-
parentId: null,
|
|
103
|
-
rotation: 0,
|
|
104
|
-
props: {
|
|
105
|
-
width: 100,
|
|
106
|
-
height: 100,
|
|
107
|
-
opacity: 1,
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
'user-1': {
|
|
111
|
-
id: 'user-1',
|
|
112
|
-
typeName: 'user',
|
|
113
|
-
name: 'name',
|
|
114
|
-
locale: 'en',
|
|
115
|
-
phoneNumber: null,
|
|
116
|
-
},
|
|
117
|
-
})
|
|
118
|
-
})
|