recoder-code
Version:
Complete AI-powered development platform with ML model training, plugin registry, real-time collaboration, monitoring, infrastructure automation, and enterprise deployment capabilities
176 lines (157 loc) • 6.46 kB
JavaScript
var DB = require('./index');
var Snapshot = require('../snapshot');
var util = require('../util');
var clone = util.clone;
// In-memory ShareDB database
//
// This adapter is not appropriate for production use. It is intended for
// testing and as an API example for people implementing database adaptors. It
// is fully functional, except it stores all documents & operations forever in
// memory. As such, memory usage will grow without bound, it doesn't scale
// across multiple node processes and you'll lose all your data if the server
// restarts. Query APIs are adapter specific. Use with care.
function MemoryDB(options) {
if (!(this instanceof MemoryDB)) return new MemoryDB(options);
DB.call(this, options);
// Map from collection name -> doc id -> doc snapshot ({v:, type:, data:})
this.docs = Object.create(null);
// Map from collection name -> doc id -> list of operations. Operations
// don't store their version - instead their version is simply the index in
// the list.
this.ops = Object.create(null);
this.closed = false;
};
module.exports = MemoryDB;
MemoryDB.prototype = Object.create(DB.prototype);
MemoryDB.prototype.close = function(callback) {
this.closed = true;
if (callback) callback();
};
// Persists an op and snapshot if it is for the next version. Calls back with
// callback(err, succeeded)
MemoryDB.prototype.commit = function(collection, id, op, snapshot, options, callback) {
var db = this;
if (typeof callback !== 'function') throw new Error('Callback required');
util.nextTick(function() {
var version = db._getVersionSync(collection, id);
if (snapshot.v !== version + 1) {
var succeeded = false;
return callback(null, succeeded);
}
var err = db._writeOpSync(collection, id, op);
if (err) return callback(err);
err = db._writeSnapshotSync(collection, id, snapshot);
if (err) return callback(err);
var succeeded = true;
callback(null, succeeded);
});
};
// Get the named document from the database. The callback is called with (err,
// snapshot). A snapshot with a version of zero is returned if the docuemnt
// has never been created in the database.
MemoryDB.prototype.getSnapshot = function(collection, id, fields, options, callback) {
var includeMetadata = (fields && fields.$submit) || (options && options.metadata);
var db = this;
if (typeof callback !== 'function') throw new Error('Callback required');
util.nextTick(function() {
var snapshot = db._getSnapshotSync(collection, id, includeMetadata);
callback(null, snapshot);
});
};
// Get operations between [from, to) noninclusively. (Ie, the range should
// contain start but not end).
//
// If end is null, this function should return all operations from start onwards.
//
// The operations that getOps returns don't need to have a version: field.
// The version will be inferred from the parameters if it is missing.
//
// Callback should be called as callback(error, [list of ops]);
MemoryDB.prototype.getOps = function(collection, id, from, to, options, callback) {
var includeMetadata = options && options.metadata;
var db = this;
if (typeof callback !== 'function') throw new Error('Callback required');
util.nextTick(function() {
var opLog = db._getOpLogSync(collection, id);
if (to == null) {
to = opLog.length;
}
var ops = clone(opLog.slice(from, to));
if (!includeMetadata) {
for (var i = 0; i < ops.length; i++) {
delete ops[i].m;
}
}
callback(null, ops);
});
};
// The memory database query function returns all documents in a collection
// regardless of query by default
MemoryDB.prototype.query = function(collection, query, fields, options, callback) {
var includeMetadata = options && options.metadata;
var db = this;
if (typeof callback !== 'function') throw new Error('Callback required');
util.nextTick(function() {
var collectionDocs = db.docs[collection];
var snapshots = [];
for (var id in collectionDocs || {}) {
var snapshot = db._getSnapshotSync(collection, id, includeMetadata);
snapshots.push(snapshot);
}
try {
var result = db._querySync(snapshots, query, options);
callback(null, result.snapshots, result.extra);
} catch (err) {
callback(err);
}
});
};
// For testing, it may be useful to implement the desired query
// language by defining this function. Returns an object with
// two properties:
// - snapshots: array of query result snapshots
// - extra: (optional) other types of results, such as counts
MemoryDB.prototype._querySync = function(snapshots) {
return {snapshots: snapshots};
};
MemoryDB.prototype._writeOpSync = function(collection, id, op) {
var opLog = this._getOpLogSync(collection, id);
// This will write an op in the log at its version, which should always be
// the next item in the array under normal operation
opLog[op.v] = clone(op);
};
// Create, update, and delete snapshots. For creates and updates, a snapshot
// object will be passed in with a type property. If there is no type property,
// it should be considered a delete
MemoryDB.prototype._writeSnapshotSync = function(collection, id, snapshot) {
var collectionDocs = this.docs[collection] || (this.docs[collection] = Object.create(null));
if (!snapshot.type) {
delete collectionDocs[id];
} else {
collectionDocs[id] = clone(snapshot);
}
};
MemoryDB.prototype._getSnapshotSync = function(collection, id, includeMetadata) {
var collectionDocs = this.docs[collection];
// We need to clone the snapshot, because ShareDB assumes each call to
// getSnapshot returns a new object
var doc = collectionDocs && collectionDocs[id];
var snapshot;
if (doc) {
var data = clone(doc.data);
var meta = (includeMetadata) ? clone(doc.m) : null;
snapshot = new Snapshot(id, doc.v, doc.type, data, meta);
} else {
var version = this._getVersionSync(collection, id);
snapshot = new Snapshot(id, version, null, undefined, null);
}
return snapshot;
};
MemoryDB.prototype._getOpLogSync = function(collection, id) {
var collectionOps = this.ops[collection] || (this.ops[collection] = Object.create(null));
return collectionOps[id] || (collectionOps[id] = []);
};
MemoryDB.prototype._getVersionSync = function(collection, id) {
var collectionOps = this.ops[collection];
return (collectionOps && collectionOps[id] && collectionOps[id].length) || 0;
};