Skip to content

Commit b9cd5f5

Browse files
authored
Merge pull request #40 from microsoft/bviswanathan/memorystore-fix
InMemoryStore will create commitedStoreData only when provider supportsRollback
2 parents f9eb884 + f9080d8 commit b9cd5f5

File tree

3 files changed

+124
-15
lines changed

3 files changed

+124
-15
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@microsoft/objectstoreprovider",
3-
"version": "0.6.38",
3+
"version": "0.6.39",
44
"description": "A cross-browser object store library",
55
"author": "Mukundan Kavanur Kidambi <[email protected]>",
66
"scripts": {

src/InMemoryProvider.ts

+42-11
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,12 @@ export class InMemoryProvider extends DbProvider {
6767

6868
private _lockHelper: TransactionLockHelper | undefined;
6969
private readonly _mapType?: OrderedMapType;
70+
private readonly _supportsRollback?: boolean;
7071

71-
constructor(mapType?: OrderedMapType) {
72+
constructor(mapType?: OrderedMapType, supportsRollback = false) {
7273
super();
7374
this._mapType = mapType;
75+
this._supportsRollback = supportsRollback;
7476
}
7577

7678
open(
@@ -105,7 +107,13 @@ export class InMemoryProvider extends DbProvider {
105107
): Promise<DbTransaction> {
106108
return this._lockHelper!!!.openTransaction(storeNames, writeNeeded).then(
107109
(token: any) =>
108-
new InMemoryTransaction(this, this._lockHelper!!!, token, writeNeeded)
110+
new InMemoryTransaction(
111+
this,
112+
this._lockHelper!!!,
113+
token,
114+
writeNeeded,
115+
this._supportsRollback!
116+
)
109117
);
110118
}
111119

@@ -128,19 +136,20 @@ class InMemoryTransaction implements DbTransaction {
128136
private _prov: InMemoryProvider,
129137
private _lockHelper: TransactionLockHelper,
130138
private _transToken: TransactionToken,
131-
writeNeeded: boolean
139+
private _writeNeeded: boolean,
140+
private _supportsRollback: boolean
132141
) {
133142
// Close the transaction on the next tick. By definition, anything is completed synchronously here, so after an event tick
134143
// goes by, there can't have been anything pending.
135-
if (writeNeeded) {
144+
if (this._writeNeeded) {
136145
this._openTimer = setTimeout(() => {
137146
this._openTimer = undefined;
138147
this._commitTransaction();
139148
this._lockHelper.transactionComplete(this._transToken);
140149
}, 0) as any as number;
141150
} else {
151+
// read-only
142152
this._openTimer = undefined;
143-
this._commitTransaction();
144153
this._lockHelper.transactionComplete(this._transToken);
145154
}
146155
}
@@ -156,6 +165,11 @@ class InMemoryTransaction implements DbTransaction {
156165
}
157166

158167
abort(): void {
168+
if (!this._supportsRollback) {
169+
throw new Error(
170+
"Unable to abort transaction since provider doesn't support rollback"
171+
);
172+
}
159173
this._stores.forEach((store) => {
160174
store.internal_rollbackPendingData();
161175
});
@@ -188,7 +202,11 @@ class InMemoryTransaction implements DbTransaction {
188202
if (!store) {
189203
throw new Error("Store not found: " + storeName);
190204
}
191-
const ims = new InMemoryStore(this, store);
205+
const ims = new InMemoryStore(
206+
this,
207+
store,
208+
this._writeNeeded && this._supportsRollback
209+
);
192210
this._stores.set(storeName, ims);
193211
return ims;
194212
}
@@ -199,27 +217,40 @@ class InMemoryTransaction implements DbTransaction {
199217
}
200218

201219
class InMemoryStore implements DbStore {
202-
private _committedStoreData: Map<string, ItemType>;
220+
private _committedStoreData?: Map<string, ItemType>;
203221
private _mergedData: Map<string, ItemType>;
204222
private _storeSchema: StoreSchema;
205223
private _indices: Map<string, InMemoryIndex>;
206224
private _mapType?: OrderedMapType;
207-
constructor(private _trans: InMemoryTransaction, storeInfo: StoreData) {
225+
constructor(
226+
private _trans: InMemoryTransaction,
227+
storeInfo: StoreData,
228+
private _supportsRollback: boolean
229+
) {
208230
this._storeSchema = storeInfo.schema;
209-
this._committedStoreData = new Map(storeInfo.data);
231+
if (this._supportsRollback) {
232+
this._committedStoreData = new Map(storeInfo.data);
233+
}
210234
this._indices = storeInfo.indices;
211235
this._mergedData = storeInfo.data;
212236
this._mapType = storeInfo.mapType;
213237
}
214238

215239
internal_commitPendingData(): void {
216-
this._committedStoreData = new Map(this._mergedData);
240+
if (this._supportsRollback) {
241+
this._committedStoreData = new Map(this._mergedData);
242+
}
217243
// Indices were already updated, theres no need to update them now.
218244
}
219245

220246
internal_rollbackPendingData(): void {
247+
if (!this._supportsRollback) {
248+
throw new Error(
249+
"Unable to rollback since InMemoryStore was created with supportsRollback = false"
250+
);
251+
}
221252
this._mergedData.clear();
222-
this._committedStoreData.forEach((val, key) => {
253+
this._committedStoreData?.forEach((val, key) => {
223254
this._mergedData.set(key, val);
224255
});
225256
// Recreate all indexes on a roll back.

src/tests/ObjectStoreProvider.spec.ts

+81-3
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,14 @@ function openProvider(
2525
providerName: string,
2626
schema: DbSchema,
2727
wipeFirst: boolean,
28-
handleOnClose?: OnCloseHandler
28+
handleOnClose?: OnCloseHandler,
29+
supportsRollback?: boolean
2930
) {
3031
let provider: DbProvider;
3132
if (providerName === "memory-rbtree") {
32-
provider = new InMemoryProvider("red-black-tree");
33+
provider = new InMemoryProvider("red-black-tree", supportsRollback);
3334
} else if (providerName === "memory-btree") {
34-
provider = new InMemoryProvider("b+tree");
35+
provider = new InMemoryProvider("b+tree", supportsRollback);
3536
} else if (providerName === "indexeddb") {
3637
provider = new IndexedDbProvider();
3738
} else if (providerName === "indexeddbfakekeys") {
@@ -2599,6 +2600,8 @@ describe("ObjectStoreProvider", function () {
25992600
},
26002601
],
26012602
},
2603+
true,
2604+
undefined,
26022605
true
26032606
)
26042607
.then((prov) => {
@@ -4955,6 +4958,81 @@ describe("ObjectStoreProvider", function () {
49554958
});
49564959
});
49574960
});
4961+
4962+
if (provName === "memory-rbtree" || provName === "memory-btree") {
4963+
it("Doesn't create committedStoreData for read-only operation", async () => {
4964+
return openProvider(
4965+
provName,
4966+
{
4967+
version: 2,
4968+
stores: [
4969+
{
4970+
name: "test",
4971+
primaryKeyPath: "id",
4972+
indexes: [
4973+
{
4974+
name: "i",
4975+
keyPath: "txt",
4976+
fullText: true,
4977+
unique: false,
4978+
},
4979+
],
4980+
},
4981+
],
4982+
},
4983+
true
4984+
).then((prov) => {
4985+
const itemsToPut = [];
4986+
for (var i = 0; i < 10; i++) {
4987+
itemsToPut.push({ id: `a${i}`, txt: `aaaaaa${i}` });
4988+
}
4989+
assert.equal((<InMemoryProvider>prov)["_supportsRollback"], false);
4990+
prov.put("test", itemsToPut).then(() => {
4991+
prov.openTransaction(["test"], false).then((transaction) => {
4992+
const store = <any>transaction.getStore("test"); // InMemoryStore
4993+
assert.equal(store["_supportsRollback"], false);
4994+
assert.equal(store["_committedStoreData"], undefined);
4995+
prov.close();
4996+
});
4997+
});
4998+
});
4999+
});
5000+
it("InMemoryProvider with supportsRollback = true", async () => {
5001+
return openProvider(
5002+
provName,
5003+
{
5004+
version: 2,
5005+
stores: [
5006+
{
5007+
name: "test",
5008+
primaryKeyPath: "id",
5009+
},
5010+
],
5011+
},
5012+
true,
5013+
undefined,
5014+
true
5015+
).then((prov) => {
5016+
const itemsToPut = [];
5017+
for (var i = 0; i < 10; i++) {
5018+
itemsToPut.push({ id: `a${i}`, txt: `aaaaaa${i}` });
5019+
}
5020+
assert.equal((<InMemoryProvider>prov)["_supportsRollback"], true);
5021+
prov.put("test", itemsToPut).then(() => {
5022+
prov.openTransaction(["test"], true).then((transaction) => {
5023+
const store = <any>transaction.getStore("test"); // InMemoryStore
5024+
assert.equal(store["_supportsRollback"], true);
5025+
assert.equal(
5026+
Array.from(store["_committedStoreData"]?.values() || [])
5027+
.length,
5028+
10
5029+
);
5030+
prov.close();
5031+
});
5032+
});
5033+
});
5034+
});
5035+
}
49585036
});
49595037
});
49605038
});

0 commit comments

Comments
 (0)