@quenty/datastore 13.13.2 → 13.14.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/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [13.14.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/datastore@13.13.2...@quenty/datastore@13.14.0) (2024-11-06)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* Fix deletion checks (maybe not very well tested) ([71c6a99](https://github.com/Quenty/NevermoreEngine/commit/71c6a998001bd0296ce2a7e9bf9b05f304e91acc))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
## [13.13.2](https://github.com/Quenty/NevermoreEngine/compare/@quenty/datastore@13.13.1...@quenty/datastore@13.13.2) (2024-11-04)
|
|
7
18
|
|
|
8
19
|
**Note:** Version bump only for package @quenty/datastore
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/datastore",
|
|
3
|
-
"version": "13.
|
|
3
|
+
"version": "13.14.0",
|
|
4
4
|
"description": "Quenty's Datastore implementation for Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -27,20 +27,20 @@
|
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@quenty/baseobject": "^10.7.1",
|
|
30
|
-
"@quenty/bindtocloseservice": "^8.
|
|
30
|
+
"@quenty/bindtocloseservice": "^8.12.0",
|
|
31
31
|
"@quenty/loader": "^10.7.1",
|
|
32
32
|
"@quenty/maid": "^3.4.0",
|
|
33
33
|
"@quenty/math": "^2.7.0",
|
|
34
|
-
"@quenty/promise": "^10.
|
|
35
|
-
"@quenty/rx": "^13.
|
|
36
|
-
"@quenty/servicebag": "^11.
|
|
37
|
-
"@quenty/signal": "^7.
|
|
38
|
-
"@quenty/symbol": "^3.
|
|
34
|
+
"@quenty/promise": "^10.8.0",
|
|
35
|
+
"@quenty/rx": "^13.12.0",
|
|
36
|
+
"@quenty/servicebag": "^11.10.0",
|
|
37
|
+
"@quenty/signal": "^7.9.0",
|
|
38
|
+
"@quenty/symbol": "^3.3.0",
|
|
39
39
|
"@quenty/table": "^3.6.0",
|
|
40
|
-
"@quenty/valueobject": "^13.
|
|
40
|
+
"@quenty/valueobject": "^13.12.0"
|
|
41
41
|
},
|
|
42
42
|
"publishConfig": {
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "00e6f71716216dd6ecbc8505ad898a1ab7f72756"
|
|
46
46
|
}
|
package/src/Server/DataStore.lua
CHANGED
|
@@ -69,11 +69,12 @@ local DataStoreDeleteToken = require("DataStoreDeleteToken")
|
|
|
69
69
|
local DataStorePromises = require("DataStorePromises")
|
|
70
70
|
local DataStoreStage = require("DataStoreStage")
|
|
71
71
|
local Maid = require("Maid")
|
|
72
|
+
local Math = require("Math")
|
|
72
73
|
local Promise = require("Promise")
|
|
74
|
+
local Rx = require("Rx")
|
|
73
75
|
local Signal = require("Signal")
|
|
74
|
-
local
|
|
76
|
+
local Symbol = require("Symbol")
|
|
75
77
|
local ValueObject = require("ValueObject")
|
|
76
|
-
local Rx = require("Rx")
|
|
77
78
|
|
|
78
79
|
local DEFAULT_DEBUG_WRITING = false
|
|
79
80
|
|
|
@@ -118,8 +119,7 @@ function DataStore.new(robloxDataStore, key)
|
|
|
118
119
|
@prop Saving Signal<Promise>
|
|
119
120
|
@within DataStore
|
|
120
121
|
]=]
|
|
121
|
-
self.Saving = Signal.new() -- :Fire(promise)
|
|
122
|
-
self._maid:GiveTask(self.Saving)
|
|
122
|
+
self.Saving = self._maid:Add(Signal.new()) -- :Fire(promise)
|
|
123
123
|
|
|
124
124
|
self:_setupAutoSaving()
|
|
125
125
|
|
|
@@ -222,6 +222,7 @@ end
|
|
|
222
222
|
]=]
|
|
223
223
|
function DataStore:SetUserIdList(userIdList)
|
|
224
224
|
assert(type(userIdList) == "table" or userIdList == nil, "Bad userIdList")
|
|
225
|
+
assert(not Symbol.isSymbol(userIdList), "Should not be symbol")
|
|
225
226
|
|
|
226
227
|
self._userIdList = userIdList
|
|
227
228
|
end
|
|
@@ -376,6 +377,8 @@ function DataStore:_doDataSync(writer, doMergeNewData)
|
|
|
376
377
|
result = {}
|
|
377
378
|
end
|
|
378
379
|
|
|
380
|
+
self:_checkSnapshotIntegrity("writer:WriteMerge(original)", result)
|
|
381
|
+
|
|
379
382
|
if self._debugWriting then
|
|
380
383
|
print("[DataStore] - Writing", result)
|
|
381
384
|
end
|
|
@@ -417,7 +420,7 @@ end
|
|
|
417
420
|
function DataStore:_promiseGetAsyncNoCache()
|
|
418
421
|
return self._maid:GivePromise(DataStorePromises.getAsync(self._robloxDataStore, self._key))
|
|
419
422
|
:Catch(function(err)
|
|
420
|
-
warn(string.format("DataStorePromises.getAsync(%q) -> warning - ", self._key), err)
|
|
423
|
+
warn(string.format("DataStorePromises.getAsync(%q) -> warning - %s", tostring(self._key), tostring(err or "empty error")))
|
|
421
424
|
return Promise.rejected(err)
|
|
422
425
|
end)
|
|
423
426
|
:Then(function(data)
|
|
@@ -427,7 +430,7 @@ function DataStore:_promiseGetAsyncNoCache()
|
|
|
427
430
|
self:MergeDiffSnapshot(diffSnapshot)
|
|
428
431
|
|
|
429
432
|
if self._debugWriting then
|
|
430
|
-
print(string.format("DataStorePromises.getAsync(%q) -> Got ", self._key), data, "with diff snapshot", diffSnapshot, "to view", self._viewSnapshot)
|
|
433
|
+
print(string.format("DataStorePromises.getAsync(%q) -> Got ", tostring(self._key)), data, "with diff snapshot", diffSnapshot, "to view", self._viewSnapshot)
|
|
431
434
|
-- print(string.format("DataStorePromises.getAsync(%q) -> Got ", self._key), data)
|
|
432
435
|
end
|
|
433
436
|
end)
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
|
|
5
5
|
local require = require(script.Parent.loader).load(script)
|
|
6
6
|
|
|
7
|
+
local Symbol = require("Symbol")
|
|
8
|
+
|
|
7
9
|
local DataStoreSnapshotUtils = {}
|
|
8
10
|
|
|
9
11
|
function DataStoreSnapshotUtils.isEmptySnapshot(snapshot)
|
|
10
|
-
return type(snapshot) == "table" and next(snapshot) == nil
|
|
12
|
+
return not Symbol.isSymbol(snapshot) and type(snapshot) == "table" and next(snapshot) == nil
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
return DataStoreSnapshotUtils
|
|
@@ -18,6 +18,7 @@ local require = require(script.Parent.loader).load(script)
|
|
|
18
18
|
|
|
19
19
|
local BaseObject = require("BaseObject")
|
|
20
20
|
local DataStoreDeleteToken = require("DataStoreDeleteToken")
|
|
21
|
+
local DataStoreSnapshotUtils = require("DataStoreSnapshotUtils")
|
|
21
22
|
local DataStoreWriter = require("DataStoreWriter")
|
|
22
23
|
local GoodSignal = require("GoodSignal")
|
|
23
24
|
local Maid = require("Maid")
|
|
@@ -26,10 +27,10 @@ local ObservableSubscriptionTable = require("ObservableSubscriptionTable")
|
|
|
26
27
|
local Promise = require("Promise")
|
|
27
28
|
local PromiseUtils = require("PromiseUtils")
|
|
28
29
|
local Set = require("Set")
|
|
30
|
+
local Symbol = require("Symbol")
|
|
29
31
|
local Table = require("Table")
|
|
30
|
-
local DataStoreSnapshotUtils = require("DataStoreSnapshotUtils")
|
|
31
32
|
|
|
32
|
-
local SLOW_INTEGRITY_CHECK_ENABLED =
|
|
33
|
+
local SLOW_INTEGRITY_CHECK_ENABLED = false
|
|
33
34
|
|
|
34
35
|
local DataStoreStage = setmetatable({}, BaseObject)
|
|
35
36
|
DataStoreStage.ClassName = "DataStoreStage"
|
|
@@ -172,10 +173,10 @@ function DataStoreStage:GetSubStore(key)
|
|
|
172
173
|
end
|
|
173
174
|
|
|
174
175
|
local maid = Maid.new()
|
|
175
|
-
local newStore = DataStoreStage.new(key, self)
|
|
176
|
-
maid:GiveTask(newStore)
|
|
176
|
+
local newStore = maid:Add(DataStoreStage.new(key, self))
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
-- TODO: Transfer delete tokens too?
|
|
179
|
+
if type(self._baseDataSnapshot) == "table" and not Symbol.isSymbol(self._baseDataSnapshot) then
|
|
179
180
|
local baseDataToTransfer = self._baseDataSnapshot[key]
|
|
180
181
|
if baseDataToTransfer ~= nil then
|
|
181
182
|
local newSnapshot = table.clone(self._baseDataSnapshot)
|
|
@@ -186,7 +187,7 @@ function DataStoreStage:GetSubStore(key)
|
|
|
186
187
|
end
|
|
187
188
|
|
|
188
189
|
-- Transfer save data to substore
|
|
189
|
-
if type(self._saveDataSnapshot) == "table" then
|
|
190
|
+
if type(self._saveDataSnapshot) == "table" and not Symbol.isSymbol(self._saveDataSnapshot) then
|
|
190
191
|
local saveDataToTransfer = self._saveDataSnapshot[key]
|
|
191
192
|
|
|
192
193
|
if saveDataToTransfer ~= nil then
|
|
@@ -507,7 +508,7 @@ function DataStoreStage:Overwrite(data)
|
|
|
507
508
|
data = DataStoreDeleteToken
|
|
508
509
|
end
|
|
509
510
|
|
|
510
|
-
if type(data) == "table" then
|
|
511
|
+
if type(data) == "table" and data ~= DataStoreDeleteToken then
|
|
511
512
|
local newSaveSnapshot = {}
|
|
512
513
|
|
|
513
514
|
local remaining = Set.fromKeys(self._stores)
|
|
@@ -719,6 +720,8 @@ function DataStoreStage:_updateStoresAndComputeBaseDataSnapshotFromDiffSnapshot(
|
|
|
719
720
|
if diffSnapshot == DataStoreDeleteToken then
|
|
720
721
|
return nil
|
|
721
722
|
elseif type(diffSnapshot) == "table" then
|
|
723
|
+
assert(not Symbol.isSymbol(diffSnapshot), "diffSnapshot should not be symbol")
|
|
724
|
+
|
|
722
725
|
local newBaseDataSnapshot
|
|
723
726
|
if type(self._baseDataSnapshot) == "table" then
|
|
724
727
|
newBaseDataSnapshot = table.clone(self._baseDataSnapshot)
|
|
@@ -976,6 +979,42 @@ function DataStoreStage:_storeAtKey(key, value)
|
|
|
976
979
|
self:_checkIntegrity()
|
|
977
980
|
end
|
|
978
981
|
|
|
982
|
+
function DataStoreStage:_checkSnapshotIntegrity(label, result)
|
|
983
|
+
assert(type(label) == "string", "Bad label")
|
|
984
|
+
|
|
985
|
+
if not SLOW_INTEGRITY_CHECK_ENABLED then
|
|
986
|
+
return
|
|
987
|
+
end
|
|
988
|
+
|
|
989
|
+
if result == DataStoreDeleteToken then
|
|
990
|
+
error(string.format("%s should not be a DataStoreDeleteToken", label))
|
|
991
|
+
end
|
|
992
|
+
|
|
993
|
+
local function recurse(innerLabel, value)
|
|
994
|
+
if type(value) ~= "table" then
|
|
995
|
+
return
|
|
996
|
+
end
|
|
997
|
+
|
|
998
|
+
for key, item in pairs(value) do
|
|
999
|
+
local keyLabel = innerLabel .. "." .. tostring(key)
|
|
1000
|
+
|
|
1001
|
+
if not (type(key) == "string" or type(key) == "number") then
|
|
1002
|
+
error(string.format("%s should be a number or string", keyLabel))
|
|
1003
|
+
end
|
|
1004
|
+
|
|
1005
|
+
if item == DataStoreDeleteToken then
|
|
1006
|
+
error(string.format("%s should not contain a DataStoreDeleteToken", keyLabel))
|
|
1007
|
+
end
|
|
1008
|
+
|
|
1009
|
+
if type(item) == "table" then
|
|
1010
|
+
recurse(keyLabel, item)
|
|
1011
|
+
end
|
|
1012
|
+
end
|
|
1013
|
+
end
|
|
1014
|
+
|
|
1015
|
+
recurse(label, result)
|
|
1016
|
+
end
|
|
1017
|
+
|
|
979
1018
|
function DataStoreStage:_checkIntegrity()
|
|
980
1019
|
if not SLOW_INTEGRITY_CHECK_ENABLED then
|
|
981
1020
|
return
|
|
@@ -986,6 +1025,7 @@ function DataStoreStage:_checkIntegrity()
|
|
|
986
1025
|
|
|
987
1026
|
if type(self._baseDataSnapshot) == "table" then
|
|
988
1027
|
assert(table.isfrozen(self._baseDataSnapshot), "Base snapshot should be frozen")
|
|
1028
|
+
self:_checkSnapshotIntegrity("self._baseDataSnapshot", self._baseDataSnapshot)
|
|
989
1029
|
end
|
|
990
1030
|
|
|
991
1031
|
if type(self._saveDataSnapshot) == "table" then
|
|
@@ -994,6 +1034,7 @@ function DataStoreStage:_checkIntegrity()
|
|
|
994
1034
|
|
|
995
1035
|
if type(self._viewSnapshot) == "table" then
|
|
996
1036
|
assert(table.isfrozen(self._viewSnapshot), "View snapshot should be frozen")
|
|
1037
|
+
self:_checkSnapshotIntegrity("self._viewSnapshot", self._viewSnapshot)
|
|
997
1038
|
end
|
|
998
1039
|
|
|
999
1040
|
for key, _ in pairs(self._stores) do
|
|
@@ -1005,16 +1046,6 @@ function DataStoreStage:_checkIntegrity()
|
|
|
1005
1046
|
error(string.format("[DataStoreStage] - Duplicate saveData at key %q", key))
|
|
1006
1047
|
end
|
|
1007
1048
|
end
|
|
1008
|
-
|
|
1009
|
-
if type(self._viewSnapshot) == "table" then
|
|
1010
|
-
for key, value in pairs(self._viewSnapshot) do
|
|
1011
|
-
assert(type(key) == "string" or type(key) == "number", "Bad key")
|
|
1012
|
-
if value == DataStoreDeleteToken then
|
|
1013
|
-
error(string.format("[DataStoreStage] - View at key %q is delete token", key))
|
|
1014
|
-
end
|
|
1015
|
-
end
|
|
1016
|
-
end
|
|
1017
1049
|
end
|
|
1018
1050
|
|
|
1019
|
-
|
|
1020
1051
|
return DataStoreStage
|
|
@@ -46,7 +46,7 @@ function DataStoreWriter:SetSaveDataSnapshot(saveDataSnapshot)
|
|
|
46
46
|
|
|
47
47
|
if saveDataSnapshot == DataStoreDeleteToken then
|
|
48
48
|
self._saveDataSnapshot = DataStoreDeleteToken
|
|
49
|
-
elseif type(saveDataSnapshot) == "table" then
|
|
49
|
+
elseif type(saveDataSnapshot) == "table" and not Symbol.isSymbol(saveDataSnapshot) then
|
|
50
50
|
self._saveDataSnapshot = Table.deepCopy(saveDataSnapshot)
|
|
51
51
|
else
|
|
52
52
|
self._saveDataSnapshot = saveDataSnapshot
|
|
@@ -67,6 +67,7 @@ end
|
|
|
67
67
|
|
|
68
68
|
function DataStoreWriter:SetFullBaseDataSnapshot(fullBaseDataSnapshot)
|
|
69
69
|
assert(type(fullBaseDataSnapshot) ~= "table" or table.isfrozen(fullBaseDataSnapshot), "fullBaseDataSnapshot should be frozen")
|
|
70
|
+
assert(not Symbol.isSymbol(fullBaseDataSnapshot), "fullBaseDataSnapshot should not be symbol")
|
|
70
71
|
|
|
71
72
|
if fullBaseDataSnapshot == DataStoreDeleteToken then
|
|
72
73
|
error("[DataStoreWriter] - fullBaseDataSnapshot should not be a delete token")
|
|
@@ -109,6 +110,7 @@ end
|
|
|
109
110
|
]=]
|
|
110
111
|
function DataStoreWriter:ComputeDiffSnapshot(incoming)
|
|
111
112
|
assert(incoming ~= DataStoreDeleteToken, "Incoming value should not be DataStoreDeleteToken")
|
|
113
|
+
assert(not Symbol.isSymbol(incoming), "Incoming should not be symbol")
|
|
112
114
|
|
|
113
115
|
if type(incoming) == "table" then
|
|
114
116
|
local keys = Set.union(Set.fromKeys(self._writers), Set.fromKeys(incoming))
|
|
@@ -147,6 +149,8 @@ end
|
|
|
147
149
|
function DataStoreWriter:_computeValueDiff(original, incoming)
|
|
148
150
|
assert(original ~= DataStoreDeleteToken, "original cannot be DataStoreDeleteToken")
|
|
149
151
|
assert(incoming ~= DataStoreDeleteToken, "incoming cannot be DataStoreDeleteToken")
|
|
152
|
+
assert(not Symbol.isSymbol(original), "original should not be symbol")
|
|
153
|
+
assert(not Symbol.isSymbol(incoming), "incoming should not be symbol")
|
|
150
154
|
|
|
151
155
|
if original == incoming then
|
|
152
156
|
return nil
|
|
@@ -162,6 +166,8 @@ end
|
|
|
162
166
|
function DataStoreWriter:_computeTableDiff(original, incoming)
|
|
163
167
|
assert(type(original) == "table", "Bad original")
|
|
164
168
|
assert(type(incoming) == "table", "Bad incoming")
|
|
169
|
+
assert(not Symbol.isSymbol(original), "original should not be symbol")
|
|
170
|
+
assert(not Symbol.isSymbol(incoming), "incoming should not be symbol")
|
|
165
171
|
|
|
166
172
|
local keys = Set.union(Set.fromKeys(original), Set.fromKeys(incoming))
|
|
167
173
|
|
|
@@ -203,7 +209,9 @@ end
|
|
|
203
209
|
|
|
204
210
|
function DataStoreWriter:_writeMergeWriters(original)
|
|
205
211
|
local copy
|
|
206
|
-
if
|
|
212
|
+
if Symbol.isSymbol(original) then
|
|
213
|
+
copy = original
|
|
214
|
+
elseif type(original) == "table" then
|
|
207
215
|
copy = table.clone(original)
|
|
208
216
|
else
|
|
209
217
|
copy = original
|
|
@@ -211,7 +219,7 @@ function DataStoreWriter:_writeMergeWriters(original)
|
|
|
211
219
|
|
|
212
220
|
if next(self._writers) ~= nil then
|
|
213
221
|
-- Original was not a table. We need to swap to one.
|
|
214
|
-
if type(copy) ~= "table" then
|
|
222
|
+
if type(copy) ~= "table" or Symbol.isSymbol(original) then
|
|
215
223
|
copy = {}
|
|
216
224
|
end
|
|
217
225
|
|
|
@@ -227,7 +235,7 @@ function DataStoreWriter:_writeMergeWriters(original)
|
|
|
227
235
|
end
|
|
228
236
|
|
|
229
237
|
-- Write our save data next
|
|
230
|
-
if type(self._saveDataSnapshot) == "table" and next(self._saveDataSnapshot) ~= nil then
|
|
238
|
+
if not Symbol.isSymbol(self._saveDataSnapshot) and type(self._saveDataSnapshot) == "table" and next(self._saveDataSnapshot) ~= nil then
|
|
231
239
|
-- Original was not a table. We need to swap to one.
|
|
232
240
|
if type(copy) ~= "table" then
|
|
233
241
|
copy = {}
|
|
@@ -248,7 +256,7 @@ function DataStoreWriter:_writeMergeWriters(original)
|
|
|
248
256
|
|
|
249
257
|
-- Handle empty table scenario..
|
|
250
258
|
-- This would also imply our original is nil somehow...
|
|
251
|
-
if type(copy) == "table" and next(copy) == nil then
|
|
259
|
+
if not Symbol.isSymbol(copy) and type(copy) == "table" and next(copy) == nil then
|
|
252
260
|
if type(self._saveDataSnapshot) ~= "table" then
|
|
253
261
|
return nil
|
|
254
262
|
end
|