@data-eden/cache
Advanced tools
Comparing version 0.3.2 to 0.4.0
@@ -328,3 +328,3 @@ import { describe, it, expect } from 'vitest'; | ||
it('test single transaction with commit & rollback', async function () { | ||
it('test single transaction with commit', async function () { | ||
let cache = buildCache(); | ||
@@ -387,12 +387,2 @@ | ||
}); | ||
await tx.rollback(); | ||
expect(await cache.get('book:1')).toEqual({ | ||
'book:1': { title: 'A History of the English speaking peoples' }, | ||
}); | ||
expect(await cache.get('book:2')).toEqual({ | ||
'book:2': { title: 'Marlborough: his life and times' }, | ||
}); | ||
expect(await cache.get('book:3')).toEqual(undefined); | ||
}); | ||
@@ -399,0 +389,0 @@ |
@@ -213,9 +213,5 @@ type DefaultRegistry = Record<string, object>; | ||
/** | ||
* Commits live transction entries. Calls Rollback if there are errors during commit or if commit exceeds timeout | ||
* Commits live transction entries. | ||
*/ | ||
commit(): Promise<void>; | ||
/** | ||
* Rollsback the cache to pre-transactional state | ||
*/ | ||
rollback(): Promise<void>; | ||
} | ||
@@ -222,0 +218,0 @@ export interface CommittingTransaction<CacheKeyRegistry extends DefaultRegistry, Key extends keyof CacheKeyRegistry = keyof CacheKeyRegistry, $Debug = unknown, UserExtensionData = unknown> extends Omit<CacheTransaction<CacheKeyRegistry, Key, $Debug, UserExtensionData>, 'get' | 'entries' | 'localEntries' | 'localRevisions' | 'entryRevisions'> { |
@@ -12,3 +12,3 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { | ||
}; | ||
var _LruCacheImpl_max, _LruCacheImpl_lruCache, _CommittingTransactionImpl_mergedRevisions, _LiveCacheTransactionImpl_originalCacheReference, _LiveCacheTransactionImpl_transactionalCache, _LiveCacheTransactionImpl_localUpdatedEntries, _LiveCacheTransactionImpl_commitingTransaction, _LiveCacheTransactionImpl_cacheSnapshotBeforeCommit, _LiveCacheTransactionImpl_cacheEntryState, _LiveCacheTransactionImpl_userOptionRetentionPolicy, _LiveCacheTransactionImpl_ttlPolicy, _LiveCacheTransactionImpl_lruPolicy, _LiveCacheTransactionImpl_localRevisions, _LiveCacheTransactionImpl_entryRevisions, _CacheImpl_weakCache, _CacheImpl_entryRevisions, _CacheImpl_cacheOptions, _CacheImpl_cacheEntryState, _CacheImpl_lruCache, _CacheImpl_lruPolicy; | ||
var _LruCacheImpl_max, _LruCacheImpl_lruCache, _CommittingTransactionImpl_mergedRevisions, _LiveCacheTransactionImpl_originalCacheReference, _LiveCacheTransactionImpl_transactionalCache, _LiveCacheTransactionImpl_localUpdatedEntries, _LiveCacheTransactionImpl_commitingTransaction, _LiveCacheTransactionImpl_cacheEntryState, _LiveCacheTransactionImpl_userOptionRetentionPolicy, _LiveCacheTransactionImpl_ttlPolicy, _LiveCacheTransactionImpl_lruPolicy, _LiveCacheTransactionImpl_localRevisions, _LiveCacheTransactionImpl_entryRevisions, _CacheImpl_weakCache, _CacheImpl_entryRevisions, _CacheImpl_cacheOptions, _CacheImpl_cacheEntryState, _CacheImpl_lruCache, _CacheImpl_lruPolicy; | ||
// eslint-disable-next-line | ||
@@ -83,3 +83,2 @@ function structuredClone(x) { | ||
_LiveCacheTransactionImpl_commitingTransaction.set(this, void 0); | ||
_LiveCacheTransactionImpl_cacheSnapshotBeforeCommit.set(this, void 0); | ||
_LiveCacheTransactionImpl_cacheEntryState.set(this, void 0); | ||
@@ -94,3 +93,2 @@ _LiveCacheTransactionImpl_userOptionRetentionPolicy.set(this, void 0); | ||
__classPrivateFieldSet(this, _LiveCacheTransactionImpl_localUpdatedEntries, new Map(), "f"); | ||
__classPrivateFieldSet(this, _LiveCacheTransactionImpl_cacheSnapshotBeforeCommit, new Map(), "f"); | ||
__classPrivateFieldSet(this, _LiveCacheTransactionImpl_cacheEntryState, new Map(), "f"); | ||
@@ -137,3 +135,3 @@ __classPrivateFieldSet(this, _LiveCacheTransactionImpl_ttlPolicy, DEFAULT_EXPIRATION.ttl, "f"); | ||
} | ||
async *[(_LiveCacheTransactionImpl_originalCacheReference = new WeakMap(), _LiveCacheTransactionImpl_transactionalCache = new WeakMap(), _LiveCacheTransactionImpl_localUpdatedEntries = new WeakMap(), _LiveCacheTransactionImpl_commitingTransaction = new WeakMap(), _LiveCacheTransactionImpl_cacheSnapshotBeforeCommit = new WeakMap(), _LiveCacheTransactionImpl_cacheEntryState = new WeakMap(), _LiveCacheTransactionImpl_userOptionRetentionPolicy = new WeakMap(), _LiveCacheTransactionImpl_ttlPolicy = new WeakMap(), _LiveCacheTransactionImpl_lruPolicy = new WeakMap(), _LiveCacheTransactionImpl_localRevisions = new WeakMap(), _LiveCacheTransactionImpl_entryRevisions = new WeakMap(), Symbol.asyncIterator)](entryMap) { | ||
async *[(_LiveCacheTransactionImpl_originalCacheReference = new WeakMap(), _LiveCacheTransactionImpl_transactionalCache = new WeakMap(), _LiveCacheTransactionImpl_localUpdatedEntries = new WeakMap(), _LiveCacheTransactionImpl_commitingTransaction = new WeakMap(), _LiveCacheTransactionImpl_cacheEntryState = new WeakMap(), _LiveCacheTransactionImpl_userOptionRetentionPolicy = new WeakMap(), _LiveCacheTransactionImpl_ttlPolicy = new WeakMap(), _LiveCacheTransactionImpl_lruPolicy = new WeakMap(), _LiveCacheTransactionImpl_localRevisions = new WeakMap(), _LiveCacheTransactionImpl_entryRevisions = new WeakMap(), Symbol.asyncIterator)](entryMap) { | ||
for (const [key, value] of entryMap) { | ||
@@ -225,10 +223,2 @@ const state = __classPrivateFieldGet(this, _LiveCacheTransactionImpl_cacheEntryState, "f").get(key) || DEFAULT_ENTRY_STATE; | ||
async commit(options) { | ||
for await (const [cacheKey] of __classPrivateFieldGet(this, _LiveCacheTransactionImpl_originalCacheReference, "f").entries()) { | ||
const originalCacheValue = await __classPrivateFieldGet(this, _LiveCacheTransactionImpl_originalCacheReference, "f").get(cacheKey); | ||
if (originalCacheValue) { | ||
__classPrivateFieldGet(this, _LiveCacheTransactionImpl_cacheSnapshotBeforeCommit, "f").set(cacheKey, { | ||
...originalCacheValue, | ||
}); | ||
} | ||
} | ||
const timeout = options?.timeout ? options.timeout : 10000; | ||
@@ -286,20 +276,4 @@ const commitLock = new Promise((resolve, reject) => setTimeout(reject, timeout)); | ||
}; | ||
try { | ||
await Promise.race([writeToCache(), commitLock]); | ||
} | ||
catch { | ||
// TODO throw error/warning | ||
await this.rollback(); | ||
} | ||
await Promise.race([writeToCache(), commitLock]); | ||
} | ||
async rollback() { | ||
const arrayOfCacheEntryTuples = []; | ||
for (const [cacheKey] of __classPrivateFieldGet(this, _LiveCacheTransactionImpl_cacheSnapshotBeforeCommit, "f")) { | ||
const prevCacheValue = __classPrivateFieldGet(this, _LiveCacheTransactionImpl_cacheSnapshotBeforeCommit, "f").get(cacheKey); | ||
const structuredClonedValue = structuredClone(prevCacheValue); | ||
arrayOfCacheEntryTuples.push([cacheKey, structuredClonedValue]); | ||
} | ||
await __classPrivateFieldGet(this, _LiveCacheTransactionImpl_originalCacheReference, "f").clear(); | ||
await __classPrivateFieldGet(this, _LiveCacheTransactionImpl_originalCacheReference, "f").load(arrayOfCacheEntryTuples); | ||
} | ||
} | ||
@@ -306,0 +280,0 @@ class CacheImpl { |
{ | ||
"$schema": "https://json.schemastore.org/package.json", | ||
"name": "@data-eden/cache", | ||
"version": "0.3.2", | ||
"version": "0.4.0", | ||
"repository": { | ||
@@ -6,0 +6,0 @@ "type": "git", |
@@ -328,7 +328,2 @@ # @data-eden/cache | ||
}): Promise<void>; | ||
/** | ||
Abandon this transaction and discard any changes or other transaction state. | ||
*/ | ||
rollback(): void; | ||
} | ||
@@ -436,37 +431,30 @@ | ||
let tx = cache.beginTransaction(); | ||
let txSucceeded = false; | ||
try { | ||
let cachedEntities = []; | ||
// parseEntities yields in post-order depth-first-search i.e. children before parents | ||
for(let { entity, parent, prop, revision: entityRevision } of await parseEntities(document, queryMetaData)) { | ||
let id = entityId(entity); | ||
let revision = entityRevision ?? defaultRevision; | ||
let { entityMergeStrategy, revisionMergeStrategy } = options; | ||
// merges with pre-existing entities (along with debugging data) and | ||
// returns the merged result | ||
let mergedEntity = await tx.merge(id, entity, { revision, entityMergeStrategy, revisionMergeStrategy, $debug: { rawDocument } }); | ||
// For example, parent === book, prop === 'author' | ||
// Because all userland calls go through Graphql operations, we have | ||
// the metadata necessary to differentiate strings from references | ||
parent[prop] = id; | ||
cachedEntities.push(mergedEntity); | ||
} | ||
DocumentEntityMap.set(document, cachedEntities); | ||
// Proxy exists to do at least the following: | ||
// 1. access referenced cached entities and | ||
// 2. field mask them | ||
let documentProxy = new DocumentProxy(document, queryMetaData, { $debug: { rawDocument } }); | ||
DocumentProxyMap.set(document, documentProxy); | ||
let cachedEntities = []; | ||
// parseEntities yields in post-order depth-first-search i.e. children before parents | ||
for(let { entity, parent, prop, revision: entityRevision } of await parseEntities(document, queryMetaData)) { | ||
let id = entityId(entity); | ||
let revision = entityRevision ?? defaultRevision; | ||
let { entityMergeStrategy, revisionMergeStrategy } = options; | ||
await tx.set(documentKey, document); | ||
await tx.commit(); | ||
txSucceeded = true; | ||
// merges with pre-existing entities (along with debugging data) and | ||
// returns the merged result | ||
let mergedEntity = await tx.merge(id, entity, { revision, entityMergeStrategy, revisionMergeStrategy, $debug: { rawDocument } }); | ||
// For example, parent === book, prop === 'author' | ||
// Because all userland calls go through Graphql operations, we have | ||
// the metadata necessary to differentiate strings from references | ||
parent[prop] = id; | ||
cachedEntities.push(mergedEntity); | ||
} | ||
DocumentEntityMap.set(document, cachedEntities); | ||
// Proxy exists to do at least the following: | ||
// 1. access referenced cached entities and | ||
// 2. field mask them | ||
let documentProxy = new DocumentProxy(document, queryMetaData, { $debug: { rawDocument } }); | ||
DocumentProxyMap.set(document, documentProxy); | ||
return documentProxy; | ||
} finally { | ||
if(!txSucceeded) { | ||
tx.rollback(); | ||
} | ||
} | ||
await tx.set(documentKey, document); | ||
await tx.commit(); | ||
return documentProxy; | ||
} | ||
@@ -473,0 +461,0 @@ |
@@ -377,10 +377,5 @@ // eslint-disable-next-line | ||
/** | ||
* Commits live transction entries. Calls Rollback if there are errors during commit or if commit exceeds timeout | ||
* Commits live transction entries. | ||
*/ | ||
commit(): Promise<void>; | ||
/** | ||
* Rollsback the cache to pre-transactional state | ||
*/ | ||
rollback(): Promise<void>; | ||
} | ||
@@ -526,3 +521,2 @@ | ||
>; | ||
#cacheSnapshotBeforeCommit: Map<Key, CacheKeyRegistry[Key]>; | ||
#cacheEntryState: Map<Key, CacheEntryState<UserExtensionData>>; | ||
@@ -543,3 +537,2 @@ #userOptionRetentionPolicy: ExpirationPolicy; | ||
this.#localUpdatedEntries = new Map<Key, CacheKeyRegistry[Key]>(); | ||
this.#cacheSnapshotBeforeCommit = new Map<Key, CacheKeyRegistry[Key]>(); | ||
this.#cacheEntryState = new Map<Key, CacheEntryState<UserExtensionData>>(); | ||
@@ -766,13 +759,2 @@ this.#ttlPolicy = DEFAULT_EXPIRATION.ttl; | ||
async commit(options?: { timeout: number | false }): Promise<void> { | ||
for await (const [cacheKey] of this.#originalCacheReference.entries()) { | ||
const originalCacheValue = await this.#originalCacheReference.get( | ||
cacheKey | ||
); | ||
if (originalCacheValue) { | ||
this.#cacheSnapshotBeforeCommit.set(cacheKey, { | ||
...originalCacheValue, | ||
}); | ||
} | ||
} | ||
const timeout: number = options?.timeout ? options.timeout : 10000; | ||
@@ -877,29 +859,4 @@ const commitLock = new Promise((resolve, reject) => | ||
try { | ||
await Promise.race([writeToCache(), commitLock]); | ||
} catch { | ||
// TODO throw error/warning | ||
await this.rollback(); | ||
} | ||
await Promise.race([writeToCache(), commitLock]); | ||
} | ||
async rollback(): Promise<void> { | ||
const arrayOfCacheEntryTuples: [ | ||
Key, | ||
CacheKeyRegistry[Key], | ||
CacheEntryState<UserExtensionData>? | ||
][] = []; | ||
for (const [cacheKey] of this.#cacheSnapshotBeforeCommit) { | ||
const prevCacheValue = this.#cacheSnapshotBeforeCommit.get(cacheKey); | ||
const structuredClonedValue = structuredClone( | ||
prevCacheValue | ||
) as CacheKeyRegistry[Key]; | ||
arrayOfCacheEntryTuples.push([cacheKey, structuredClonedValue]); | ||
} | ||
await this.#originalCacheReference.clear(); | ||
await this.#originalCacheReference.load(arrayOfCacheEntryTuples); | ||
} | ||
} | ||
@@ -906,0 +863,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
182682
2442
557