@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.13.2",
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.11.1",
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.7.1",
35
- "@quenty/rx": "^13.11.1",
36
- "@quenty/servicebag": "^11.9.1",
37
- "@quenty/signal": "^7.8.1",
38
- "@quenty/symbol": "^3.2.0",
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.11.1"
40
+ "@quenty/valueobject": "^13.12.0"
41
41
  },
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
- "gitHead": "01c43a0ddd3c5e0cb2d9027313dbfa9852eedef1"
45
+ "gitHead": "00e6f71716216dd6ecbc8505ad898a1ab7f72756"
46
46
  }
@@ -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 Math = require("Math")
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 = true
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
- if type(self._baseDataSnapshot) == "table" then
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 type(original) == "table" then
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