diff --git a/package-lock.json b/package-lock.json index 5011879..060b13d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "datocms-client", - "version": "3.5.15", + "version": "3.5.16-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "datocms-client", - "version": "3.5.15", + "version": "3.5.16-0", "license": "MIT", "dependencies": { "@iarna/toml": "^2.2.3", diff --git a/package.json b/package.json index c0786c5..748f66b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "datocms-client", - "version": "3.5.15", + "version": "3.5.16-0", "description": "DatoCMS API client and CLI tool", "browser": "dist/client.js", "main": "lib/index.js", diff --git a/src/local/EntitiesRepo.js b/src/local/EntitiesRepo.js index 3d21adf..ca24e44 100644 --- a/src/local/EntitiesRepo.js +++ b/src/local/EntitiesRepo.js @@ -1,5 +1,7 @@ import JsonApiEntity from './JsonApiEntity'; +const entitiesToStorePerCacheKey = 5000; + function payloadEntities(payload) { const accumulator = []; @@ -26,6 +28,63 @@ export default class EntitiesRepo { this.upsertEntities(...payloads); } + async saveStateToCache(cache, cachePrefixKey) { + const entityTypes = Object.keys(this.entities); + + const manifest = { entityTypeChunkKeys: {} }; + + for (const entityType of entityTypes) { + const entities = Object.values(this.entities[entityType]); + + for ( + let i = 0, chunkIndex = 0; + i < entities.length; + i += entitiesToStorePerCacheKey, chunkIndex += 1 + ) { + const chunkCacheKey = `${cachePrefixKey}--${entityType}-${chunkIndex}`; + + manifest.entityTypeChunkKeys[entityType] = + manifest.entityTypeChunkKeys[entityType] || []; + manifest.entityTypeChunkKeys[entityType].push(chunkCacheKey); + + await cache.set( + chunkCacheKey, + entities + .slice(i, i + entitiesToStorePerCacheKey) + .map(entity => entity.payload), + ); + } + } + + await cache.set(cachePrefixKey, manifest); + } + + async loadStateFromCache(cache, cachePrefixKey) { + const manifest = await cache.get(cachePrefixKey); + + if (!manifest) { + return; + } + + this.entities = {}; + + for (const [entityType, entityTypeChunkKeys] of Object.entries( + manifest.entityTypeChunkKeys, + )) { + this.entities[entityType] = {}; + + for (const entityTypeChunkKey of entityTypeChunkKeys) { + const chunkEntities = await cache.get(entityTypeChunkKey); + chunkEntities.forEach(entityPayload => { + this.entities[entityType][entityPayload.id] = new JsonApiEntity( + entityPayload, + this, + ); + }); + } + } + } + serializeState() { return Object.entries(this.entities).reduce((acc, [type, entitiesById]) => { return { diff --git a/src/local/Loader.js b/src/local/Loader.js index 046645d..637dbd9 100644 --- a/src/local/Loader.js +++ b/src/local/Loader.js @@ -31,18 +31,11 @@ export default class Loader { } saveStateToCache(cache) { - return cache.set(this.cacheKey(), this.entitiesRepo.serializeState()); + return this.entitiesRepo.saveStateToCache(cache, this.cacheKey()); } loadStateFromCache(cache) { - return cache.get(this.cacheKey()).then(serializedState => { - if (!serializedState) { - return false; - } - - this.entitiesRepo.loadState(serializedState); - return true; - }); + return this.entitiesRepo.loadStateFromCache(cache, this.cacheKey()); } loadSchema() { diff --git a/src/utils/seoTagsBuilder.js b/src/utils/seoTagsBuilder.js index 4e48ae0..0c79ed5 100644 --- a/src/utils/seoTagsBuilder.js +++ b/src/utils/seoTagsBuilder.js @@ -363,7 +363,7 @@ export const builders = { ogTag('og:image:height', finalUpload.height), altValue && ogTag('og:image:alt', altValue), altValue && ogTag('twitter:image:alt', altValue), - ]; + ].filter(x => !!x); }, };