UNPKG

gridsome

Version:

A JAMstack framework for building blazing fast websites with Vue.js

176 lines (133 loc) 4.21 kB
const Loki = require('lokijs') const autoBind = require('auto-bind') const NodeIndex = require('./NodeIndex') const EventEmitter = require('eventemitter3') const { deprecate } = require('../utils/deprecate') const { isArray, isPlainObject } = require('lodash') const Collection = require('./Collection') const { safeKey } = require('../utils') const lokiOps = require('./lokiOps') const { SyncWaterfallHook } = require('tapable') const SyncBailWaterfallHook = require('../app/SyncBailWaterfallHook') Object.assign(Loki.LokiOps, lokiOps) class Store { constructor (app) { this.app = app this.collections = {} this.nodeIndex = new NodeIndex(app) this._events = new EventEmitter() this.lastUpdate = null this.setUpdateTime() autoBind(this) this.metadata = new Loki.Collection('core/metadata', { unique: ['key'], autoupdate: true }) this.hooks = { addCollection: new SyncWaterfallHook(['options']), addNode: new SyncBailWaterfallHook(['options', 'collection']) } this.hooks.addNode.tap('TransformNodeContent', require('./transformNodeContent')) this.hooks.addNode.tap('ProcessNodeFields', require('./processNodeFields')) } getHooksContext () { return { hooks: this.hooks } } on (eventName, fn, ctx) { return this._events.on(eventName, fn, ctx) } off (eventName, fn, ctx) { return this._events.removeListener(eventName, fn, ctx) } // site addMetadata (key, data) { let node = this.metadata.findOne({ key }) if (node && isArray(node.data) && isArray(data)) { node.data = node.data.concat(data) } else if (node && isPlainObject(node.data) && isPlainObject(data)) { Object.assign(node.data, data) } else if (node) { node.data = data } else { node = this.metadata.insert({ key, data }) } return node } // nodes addCollection (options, store) { options = this.hooks.addCollection.call(options) if (this.collections.hasOwnProperty(options.typeName)) { return this.getCollection(options.typeName) } const collection = new Collection( options.typeName, options, store ) collection.on('add', node => { this.nodeIndex.addEntry(node, collection) this.setUpdateTime() }) collection.on('update', node => { this.nodeIndex.updateEntry(node, collection) this.setUpdateTime() }) collection.on('remove', node => { this.nodeIndex.removeEntry(node) this.setUpdateTime() }) this.collections[options.typeName] = collection return collection } getCollection (typeName) { return this.collections[typeName] } getNodeByUid (uid) { const entry = this.nodeIndex.getEntry(uid) return entry ? this.collections[entry.typeName].getNodeById(entry.id) : null } getNode (typeName, id) { return this.getCollection(typeName).getNodeById(id) } // TODO: move this to internal plugin setBelongsTo (node, typeName, id) { const entry = this.nodeIndex.getEntry(node.$uid) const belongsTo = entry.belongsTo const key = safeKey(id) belongsTo[typeName] = belongsTo[typeName] || {} belongsTo[typeName][key] = true this.nodeIndex.index.update({ ...entry, belongsTo }) } chainIndex (query = {}, resolveNodes = true) { const chain = this.nodeIndex.getChain().find(query) if (!resolveNodes) { return chain } return chain.map(entry => { const collection = this.collections[entry.typeName] const node = collection.collection.by('id', entry.id) return { ...node, $loki: undefined } }) } // utils setUpdateTime () { this.lastUpdate = Date.now() if (this.app.isBootstrapped) { this._events.emit('change') } } // deprecated addContentType (options, store) { deprecate('The store.addContentType() method has been renamed to store.addCollection().') return this.addCollection(options, store) } getContentType (typeName) { deprecate('The store.getContentType() method has been renamed to store.getCollection().') return this.getCollection(typeName) } } module.exports = Store