Comparing version 1.0.0-beta.31 to 1.0.0
@@ -5,3 +5,6 @@ var hat = require('hat'); | ||
var logger = require('./logger'); | ||
var ShareDBError = require('./error'); | ||
var ERROR_CODE = ShareDBError.CODES; | ||
/** | ||
@@ -232,3 +235,3 @@ * Agent deserializes the wire protocol messages received from the stream and | ||
return { | ||
code: 4001, | ||
code: ERROR_CODE.ERR_UNKNOWN_ERROR, | ||
message: err | ||
@@ -288,3 +291,3 @@ }; | ||
if (typeof chunk !== 'object') { | ||
var err = {code: 4000, message: 'Received non-object message'}; | ||
var err = new ShareDBError(ERROR_CODE.ERR_MESSAGE_BADLY_FORMED, 'Received non-object message'); | ||
return agent.close(err); | ||
@@ -332,3 +335,3 @@ } | ||
var errMessage = this._checkRequest(request); | ||
if (errMessage) return callback({code: 4000, message: errMessage}); | ||
if (errMessage) return callback(new ShareDBError(ERROR_CODE.ERR_MESSAGE_BADLY_FORMED, errMessage)); | ||
@@ -357,3 +360,3 @@ switch (request.a) { | ||
var op = createClientOp(request, this.clientId); | ||
if (!op) return callback({code: 4000, message: 'Invalid op message'}); | ||
if (!op) return callback(new ShareDBError(ERROR_CODE.ERR_MESSAGE_BADLY_FORMED, 'Invalid op message')); | ||
return this._submit(request.c, request.d, op, callback); | ||
@@ -365,3 +368,3 @@ case 'nf': | ||
default: | ||
callback({code: 4000, message: 'Invalid or unknown message'}); | ||
callback(new ShareDBError(ERROR_CODE.ERR_MESSAGE_BADLY_FORMED, 'Invalid or unknown message')); | ||
} | ||
@@ -612,6 +615,6 @@ } catch (err) { | ||
if (err) { | ||
// Occassional 'Op already submitted' errors are expected to happen as | ||
// Occasional 'Op already submitted' errors are expected to happen as | ||
// part of normal operation, since inflight ops need to be resent after | ||
// disconnect. In this case, ack the op so the client can proceed | ||
if (err.code === 4001) return callback(null, ack); | ||
if (err.code === ERROR_CODE.ERR_OP_ALREADY_SUBMITTED) return callback(null, ack); | ||
return callback(err); | ||
@@ -618,0 +621,0 @@ } |
@@ -11,2 +11,3 @@ var async = require('async'); | ||
var QueryEmitter = require('./query-emitter'); | ||
var ShareDBError = require('./error'); | ||
var Snapshot = require('./snapshot'); | ||
@@ -16,12 +17,4 @@ var StreamSocket = require('./stream-socket'); | ||
var warnDeprecatedDoc = true; | ||
var warnDeprecatedAfterSubmit = true; | ||
var ERROR_CODE = ShareDBError.CODES; | ||
var DOC_ACTION_DEPRECATION_WARNING = 'DEPRECATED: "doc" middleware action. Use "readSnapshots" instead. ' + | ||
'Pass `disableDocAction: true` option to ShareDB to disable the "doc" action and this warning.'; | ||
var AFTER_SUBMIT_ACTION_DEPRECATION_WARNING = 'DEPRECATED: "after submit" and "afterSubmit" middleware actions. ' + | ||
'Use "afterWrite" instead. Pass `disableSpaceDelimitedActions: true` option to ShareDB to ' + | ||
'disable the "after submit" and "afterSubmit" actions and this warning.'; | ||
function Backend(options) { | ||
@@ -50,11 +43,2 @@ if (!(this instanceof Backend)) return new Backend(options); | ||
this.remoteAgentsCount = 0; | ||
// The below shims are for backwards compatibility. These options will be | ||
// removed in a future major version | ||
if (!options.disableDocAction) { | ||
this._shimDocAction(); | ||
} | ||
if (!options.disableSpaceDelimitedActions) { | ||
this._shimAfterSubmit(); | ||
} | ||
} | ||
@@ -65,6 +49,2 @@ module.exports = Backend; | ||
Backend.prototype.MIDDLEWARE_ACTIONS = { | ||
// DEPRECATED: Synonym for 'afterWrite' | ||
afterSubmit: 'afterSubmit', | ||
// DEPRECATED: Synonym for 'afterWrite' | ||
'after submit': 'after submit', | ||
// An operation was successfully written to the database. | ||
@@ -78,4 +58,2 @@ afterWrite: 'afterWrite', | ||
connect: 'connect', | ||
// DEPRECATED: A snapshot was loaded from the database. | ||
doc: 'doc', | ||
// An operation was loaded from the database | ||
@@ -108,34 +86,2 @@ op: 'op', | ||
Backend.prototype._shimDocAction = function() { | ||
if (warnDeprecatedDoc) { | ||
warnDeprecatedDoc = false; | ||
console.warn(DOC_ACTION_DEPRECATION_WARNING); | ||
} | ||
var backend = this; | ||
this.use(this.MIDDLEWARE_ACTIONS.readSnapshots, function(request, callback) { | ||
async.each(request.snapshots, function(snapshot, eachCb) { | ||
var docRequest = {collection: request.collection, id: snapshot.id, snapshot: snapshot}; | ||
backend.trigger(backend.MIDDLEWARE_ACTIONS.doc, request.agent, docRequest, eachCb); | ||
}, callback); | ||
}); | ||
}; | ||
// Shim for backwards compatibility with deprecated middleware action name. | ||
// The actions 'after submit' and 'afterSubmit' are now 'afterWrite'. | ||
Backend.prototype._shimAfterSubmit = function() { | ||
if (warnDeprecatedAfterSubmit) { | ||
warnDeprecatedAfterSubmit = false; | ||
console.warn(AFTER_SUBMIT_ACTION_DEPRECATION_WARNING); | ||
} | ||
var backend = this; | ||
this.use(backend.MIDDLEWARE_ACTIONS.afterWrite, function(request, callback) { | ||
backend.trigger(backend.MIDDLEWARE_ACTIONS['after submit'], request.agent, request, callback); | ||
}); | ||
this.use(backend.MIDDLEWARE_ACTIONS.afterWrite, function(request, callback) { | ||
backend.trigger(backend.MIDDLEWARE_ACTIONS['afterSubmit'], request.agent, request, callback); | ||
}); | ||
}; | ||
Backend.prototype.close = function(callback) { | ||
@@ -491,3 +437,6 @@ var wait = 4; | ||
// subscribe() signature so that it remains consistent with getOps() and fetch(). | ||
return callback({code: 4025, message: 'Passing options to subscribe has not been implemented'}); | ||
return callback(new ShareDBError( | ||
ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, | ||
'Passing options to subscribe has not been implemented' | ||
)); | ||
} | ||
@@ -603,3 +552,3 @@ var start = Date.now(); | ||
// skipPoll: function(collection, id, op, query) {return true or false; } | ||
// this is a syncronous function which can be used as an early filter for | ||
// this is a synchronous function which can be used as an early filter for | ||
// operations going through the system to reduce the load on the DB. | ||
@@ -615,3 +564,6 @@ // pollDebounce: Minimum delay between subsequent database polls. This is | ||
if (request.db.disableSubscribe) { | ||
return callback({code: 4002, message: 'DB does not support subscribe'}); | ||
return callback(new ShareDBError( | ||
ERROR_CODE.ERR_DATABASE_DOES_NOT_SUPPORT_SUBSCRIBE, | ||
'DB does not support subscribe' | ||
)); | ||
} | ||
@@ -662,3 +614,3 @@ backend.pubsub.subscribe(request.channel, function(err, stream) { | ||
request.db = (options.db) ? backend.extraDbs[options.db] : backend.db; | ||
if (!request.db) return callback({code: 4003, message: 'DB not found'}); | ||
if (!request.db) return callback(new ShareDBError(ERROR_CODE.ERR_DATABASE_ADAPTER_NOT_FOUND, 'DB not found')); | ||
request.snapshotProjection = backend._getSnapshotProjection(request.db, projection); | ||
@@ -744,3 +696,6 @@ callback(null, request); | ||
if (version > snapshot.v) { | ||
return callback({code: 4024, message: 'Requested version exceeds latest snapshot version'}); | ||
return callback(new ShareDBError( | ||
ERROR_CODE.ERR_OP_VERSION_NEWER_THAN_CURRENT_SNAPSHOT, | ||
'Requested version exceeds latest snapshot version' | ||
)); | ||
} | ||
@@ -747,0 +702,0 @@ |
@@ -11,2 +11,4 @@ var Doc = require('./doc'); | ||
var ERROR_CODE = ShareDBError.CODES; | ||
function connectionState(socket) { | ||
@@ -190,11 +192,17 @@ if (socket.readyState === 0 || socket.readyState === 1) return 'connecting'; | ||
if (message.protocol !== 1) { | ||
err = new ShareDBError(4019, 'Invalid protocol version'); | ||
err = new ShareDBError( | ||
ERROR_CODE.ERR_PROTOCOL_VERSION_NOT_SUPPORTED, | ||
'Unsupported protocol version: ' + message.protocol | ||
); | ||
return this.emit('error', err); | ||
} | ||
if (types.map[message.type] !== types.defaultType) { | ||
err = new ShareDBError(4020, 'Invalid default type'); | ||
err = new ShareDBError( | ||
ERROR_CODE.ERR_DEFAULT_TYPE_MISMATCH, | ||
message.type + ' does not match the server default type' | ||
); | ||
return this.emit('error', err); | ||
} | ||
if (typeof message.id !== 'string') { | ||
err = new ShareDBError(4021, 'Invalid client id'); | ||
err = new ShareDBError(ERROR_CODE.ERR_CLIENT_ID_BADLY_FORMED, 'Client id must be a string'); | ||
return this.emit('error', err); | ||
@@ -308,3 +316,6 @@ } | ||
) { | ||
var err = new ShareDBError(5007, 'Cannot transition directly from ' + this.state + ' to ' + newState); | ||
var err = new ShareDBError( | ||
ERROR_CODE.ERR_CONNECTION_STATE_TRANSITION_INVALID, | ||
'Cannot transition directly from ' + this.state + ' to ' + newState | ||
); | ||
return this.emit('error', err); | ||
@@ -311,0 +322,0 @@ } |
@@ -6,2 +6,4 @@ var emitter = require('../emitter'); | ||
var ERROR_CODE = ShareDBError.CODES; | ||
/** | ||
@@ -145,3 +147,3 @@ * A Doc is a client's view on a sharejs document. | ||
} else { | ||
var err = new ShareDBError(4008, 'Missing type ' + newType); | ||
var err = new ShareDBError(ERROR_CODE.ERR_DOC_TYPE_NOT_RECOGNIZED, 'Missing type ' + newType); | ||
return this.emit('error', err); | ||
@@ -163,3 +165,6 @@ } | ||
if (typeof snapshot.v !== 'number') { | ||
var err = new ShareDBError(5008, 'Missing version in ingested snapshot. ' + this.collection + '.' + this.id); | ||
var err = new ShareDBError( | ||
ERROR_CODE.ERR_INGESTED_SNAPSHOT_HAS_NO_VERSION, | ||
'Missing version in ingested snapshot. ' + this.collection + '.' + this.id | ||
); | ||
if (callback) return callback(err); | ||
@@ -185,3 +190,3 @@ return this.emit('error', err); | ||
var err = new ShareDBError( | ||
5009, | ||
ERROR_CODE.ERR_DOC_MISSING_VERSION, | ||
'Cannot ingest snapshot in doc with null version. ' + this.collection + '.' + this.id | ||
@@ -290,5 +295,5 @@ ); | ||
// The server has rejected submission of the current operation. If we get | ||
// an error code 4002 "Op submit rejected", this was done intentionally | ||
// an "Op submit rejected" error, this was done intentionally | ||
// and we should roll back but not return an error to the user. | ||
if (err.code === 4002 || err.code === 'ERR_OP_SUBMIT_REJECTED') err = null; | ||
if (err.code === ERROR_CODE.ERR_OP_SUBMIT_REJECTED) err = null; | ||
return this._rollback(err); | ||
@@ -479,6 +484,6 @@ } | ||
if (server.del) { | ||
return new ShareDBError(4017, 'Document was deleted'); | ||
return new ShareDBError(ERROR_CODE.ERR_DOC_WAS_DELETED, 'Document was deleted'); | ||
} | ||
if (server.create) { | ||
return new ShareDBError(4018, 'Document alredy created'); | ||
return new ShareDBError(ERROR_CODE.ERR_DOC_ALREADY_CREATED, 'Document already created'); | ||
} | ||
@@ -491,3 +496,3 @@ | ||
if (client.create) { | ||
return new ShareDBError(4018, 'Document already created'); | ||
return new ShareDBError(ERROR_CODE.ERR_DOC_ALREADY_CREATED, 'Document already created'); | ||
} | ||
@@ -530,3 +535,6 @@ | ||
// Throw here, because all usage of _otApply should be wrapped with a try/catch | ||
throw new ShareDBError(4015, 'Cannot apply op to uncreated document. ' + this.collection + '.' + this.id); | ||
throw new ShareDBError( | ||
ERROR_CODE.ERR_DOC_DOES_NOT_EXIST, | ||
'Cannot apply op to uncreated document. ' + this.collection + '.' + this.id | ||
); | ||
} | ||
@@ -622,3 +630,3 @@ | ||
if (!op) { | ||
var err = new ShareDBError(5010, 'No op to send on call to _sendOp'); | ||
var err = new ShareDBError(ERROR_CODE.ERR_INFLIGHT_OP_MISSING, 'No op to send on call to _sendOp'); | ||
return this.emit('error', err); | ||
@@ -667,3 +675,3 @@ } | ||
var err = new ShareDBError( | ||
4015, | ||
ERROR_CODE.ERR_DOC_DOES_NOT_EXIST, | ||
'Cannot submit op. Document has not been created. ' + this.collection + '.' + this.id | ||
@@ -806,3 +814,3 @@ ); | ||
if (this.type) { | ||
var err = new ShareDBError(4016, 'Document already exists'); | ||
var err = new ShareDBError(ERROR_CODE.ERR_DOC_ALREADY_CREATED, 'Document already exists'); | ||
if (callback) return callback(err); | ||
@@ -829,3 +837,3 @@ return this.emit('error', err); | ||
if (!this.type) { | ||
var err = new ShareDBError(4015, 'Document does not exist'); | ||
var err = new ShareDBError(ERROR_CODE.ERR_DOC_DOES_NOT_EXIST, 'Document does not exist'); | ||
if (callback) return callback(err); | ||
@@ -832,0 +840,0 @@ return this.emit('error', err); |
var async = require('async'); | ||
var ShareDBError = require('../error'); | ||
var ERROR_CODE = ShareDBError.CODES; | ||
function DB(options) { | ||
@@ -19,7 +21,7 @@ // pollDebounce is the minimum time in ms between query polls | ||
DB.prototype.commit = function(collection, id, op, snapshot, options, callback) { | ||
callback(new ShareDBError(5011, 'commit DB method unimplemented')); | ||
callback(new ShareDBError(ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, 'commit DB method unimplemented')); | ||
}; | ||
DB.prototype.getSnapshot = function(collection, id, fields, options, callback) { | ||
callback(new ShareDBError(5012, 'getSnapshot DB method unimplemented')); | ||
callback(new ShareDBError(ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, 'getSnapshot DB method unimplemented')); | ||
}; | ||
@@ -43,3 +45,3 @@ | ||
DB.prototype.getOps = function(collection, id, from, to, options, callback) { | ||
callback(new ShareDBError(5013, 'getOps DB method unimplemented')); | ||
callback(new ShareDBError(ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, 'getOps DB method unimplemented')); | ||
}; | ||
@@ -82,3 +84,3 @@ | ||
DB.prototype.query = function(collection, query, fields, options, callback) { | ||
callback(new ShareDBError(4022, 'query DB method unimplemented')); | ||
callback(new ShareDBError(ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, 'query DB method unimplemented')); | ||
}; | ||
@@ -99,3 +101,3 @@ | ||
DB.prototype.queryPollDoc = function(collection, id, query, options, callback) { | ||
callback(new ShareDBError(5014, 'queryPollDoc DB method unimplemented')); | ||
callback(new ShareDBError(ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, 'queryPollDoc DB method unimplemented')); | ||
}; | ||
@@ -102,0 +104,0 @@ |
@@ -1,10 +0,49 @@ | ||
var makeError = require('make-error'); | ||
function ShareDBError(code, message) { | ||
ShareDBError.super.call(this, message); | ||
this.code = code; | ||
this.message = message || ''; | ||
if (Error.captureStackTrace) { | ||
Error.captureStackTrace(this, ShareDBError); | ||
} else { | ||
this.stack = new Error().stack; | ||
} | ||
} | ||
makeError(ShareDBError); | ||
ShareDBError.prototype = Object.create(Error.prototype); | ||
ShareDBError.prototype.constructor = ShareDBError; | ||
ShareDBError.prototype.name = 'ShareDBError'; | ||
ShareDBError.CODES = { | ||
ERR_APPLY_OP_VERSION_DOES_NOT_MATCH_SNAPSHOT: 'ERR_APPLY_OP_VERSION_DOES_NOT_MATCH_SNAPSHOT', | ||
ERR_APPLY_SNAPSHOT_NOT_PROVIDED: 'ERR_APPLY_SNAPSHOT_NOT_PROVIDED', | ||
ERR_CLIENT_ID_BADLY_FORMED: 'ERR_CLIENT_ID_BADLY_FORMED', | ||
ERR_CONNECTION_STATE_TRANSITION_INVALID: 'ERR_CONNECTION_STATE_TRANSITION_INVALID', | ||
ERR_DATABASE_ADAPTER_NOT_FOUND: 'ERR_DATABASE_ADAPTER_NOT_FOUND', | ||
ERR_DATABASE_DOES_NOT_SUPPORT_SUBSCRIBE: 'ERR_DATABASE_DOES_NOT_SUPPORT_SUBSCRIBE', | ||
ERR_DATABASE_METHOD_NOT_IMPLEMENTED: 'ERR_DATABASE_METHOD_NOT_IMPLEMENTED', | ||
ERR_DEFAULT_TYPE_MISMATCH: 'ERR_DEFAULT_TYPE_MISMATCH', | ||
ERR_DOC_MISSING_VERSION: 'ERR_DOC_MISSING_VERSION', | ||
ERR_DOC_ALREADY_CREATED: 'ERR_DOC_ALREADY_CREATED', | ||
ERR_DOC_DOES_NOT_EXIST: 'ERR_DOC_DOES_NOT_EXIST', | ||
ERR_DOC_TYPE_NOT_RECOGNIZED: 'ERR_DOC_TYPE_NOT_RECOGNIZED', | ||
ERR_DOC_WAS_DELETED: 'ERR_DOC_WAS_DELETED', | ||
ERR_INFLIGHT_OP_MISSING: 'ERR_INFLIGHT_OP_MISSING', | ||
ERR_INGESTED_SNAPSHOT_HAS_NO_VERSION: 'ERR_INGESTED_SNAPSHOT_HAS_NO_VERSION', | ||
ERR_MAX_SUBMIT_RETRIES_EXCEEDED: 'ERR_MAX_SUBMIT_RETRIES_EXCEEDED', | ||
ERR_MESSAGE_BADLY_FORMED: 'ERR_MESSAGE_BADLY_FORMED', | ||
ERR_MILESTONE_ARGUMENT_INVALID: 'ERR_MILESTONE_ARGUMENT_INVALID', | ||
ERR_OP_ALREADY_SUBMITTED: 'ERR_OP_ALREADY_SUBMITTED', | ||
ERR_OP_NOT_ALLOWED_IN_PROJECTION: 'ERR_OP_NOT_ALLOWED_IN_PROJECTION', | ||
ERR_OP_SUBMIT_REJECTED: 'ERR_OP_SUBMIT_REJECTED', | ||
ERR_OP_VERSION_MISMATCH_AFTER_TRANSFORM: 'ERR_OP_VERSION_MISMATCH_AFTER_TRANSFORM', | ||
ERR_OP_VERSION_MISMATCH_DURING_TRANSFORM: 'ERR_OP_VERSION_MISMATCH_DURING_TRANSFORM', | ||
ERR_OP_VERSION_NEWER_THAN_CURRENT_SNAPSHOT: 'ERR_OP_VERSION_NEWER_THAN_CURRENT_SNAPSHOT', | ||
ERR_OT_OP_BADLY_FORMED: 'ERR_OT_OP_BADLY_FORMED', | ||
ERR_OT_OP_NOT_PROVIDED: 'ERR_OT_OP_NOT_PROVIDED', | ||
ERR_PROTOCOL_VERSION_NOT_SUPPORTED: 'ERR_PROTOCOL_VERSION_NOT_SUPPORTED', | ||
ERR_QUERY_EMITTER_LISTENER_NOT_ASSIGNED: 'ERR_QUERY_EMITTER_LISTENER_NOT_ASSIGNED', | ||
ERR_SUBMIT_TRANSFORM_OPS_NOT_FOUND: 'ERR_SUBMIT_TRANSFORM_OPS_NOT_FOUND', | ||
ERR_TYPE_CANNOT_BE_PROJECTED: 'ERR_TYPE_CANNOT_BE_PROJECTED', | ||
ERR_UNKNOWN_ERROR: 'ERR_UNKNOWN_ERROR' | ||
}; | ||
module.exports = ShareDBError; |
@@ -5,2 +5,4 @@ var emitter = require('../emitter'); | ||
var ERROR_CODE = ShareDBError.CODES; | ||
module.exports = MilestoneDB; | ||
@@ -29,3 +31,6 @@ function MilestoneDB(options) { | ||
MilestoneDB.prototype.getMilestoneSnapshot = function(collection, id, version, callback) { | ||
var error = new ShareDBError(5019, 'getMilestoneSnapshot MilestoneDB method unimplemented'); | ||
var error = new ShareDBError( | ||
ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, | ||
'getMilestoneSnapshot MilestoneDB method unimplemented' | ||
); | ||
this._callBackOrEmitError(error, callback); | ||
@@ -41,3 +46,6 @@ }; | ||
MilestoneDB.prototype.saveMilestoneSnapshot = function(collection, snapshot, callback) { | ||
var error = new ShareDBError(5020, 'saveMilestoneSnapshot MilestoneDB method unimplemented'); | ||
var error = new ShareDBError( | ||
ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, | ||
'saveMilestoneSnapshot MilestoneDB method unimplemented' | ||
); | ||
this._callBackOrEmitError(error, callback); | ||
@@ -47,3 +55,6 @@ }; | ||
MilestoneDB.prototype.getMilestoneSnapshotAtOrBeforeTime = function(collection, id, timestamp, callback) { | ||
var error = new ShareDBError(5021, 'getMilestoneSnapshotAtOrBeforeTime MilestoneDB method unimplemented'); | ||
var error = new ShareDBError( | ||
ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, | ||
'getMilestoneSnapshotAtOrBeforeTime MilestoneDB method unimplemented' | ||
); | ||
this._callBackOrEmitError(error, callback); | ||
@@ -53,3 +64,6 @@ }; | ||
MilestoneDB.prototype.getMilestoneSnapshotAtOrAfterTime = function(collection, id, timestamp, callback) { | ||
var error = new ShareDBError(5022, 'getMilestoneSnapshotAtOrAfterTime MilestoneDB method unimplemented'); | ||
var error = new ShareDBError( | ||
ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, | ||
'getMilestoneSnapshotAtOrAfterTime MilestoneDB method unimplemented' | ||
); | ||
this._callBackOrEmitError(error, callback); | ||
@@ -56,0 +70,0 @@ }; |
var MilestoneDB = require('./index'); | ||
var ShareDBError = require('../error'); | ||
var ERROR_CODE = ShareDBError.CODES; | ||
/** | ||
@@ -26,3 +28,5 @@ * In-memory ShareDB milestone database | ||
MemoryMilestoneDB.prototype.getMilestoneSnapshot = function(collection, id, version, callback) { | ||
if (!this._isValidVersion(version)) return process.nextTick(callback, new ShareDBError(4001, 'Invalid version')); | ||
if (!this._isValidVersion(version)) { | ||
return process.nextTick(callback, new ShareDBError(ERROR_CODE.ERR_MILESTONE_ARGUMENT_INVALID, 'Invalid version')); | ||
} | ||
@@ -39,4 +43,4 @@ var predicate = versionLessThanOrEqualTo(version); | ||
if (!collection) return callback(new ShareDBError(4001, 'Missing collection')); | ||
if (!snapshot) return callback(new ShareDBError(4001, 'Missing snapshot')); | ||
if (!collection) return callback(new ShareDBError(ERROR_CODE.ERR_MILESTONE_ARGUMENT_INVALID, 'Missing collection')); | ||
if (!snapshot) return callback(new ShareDBError(ERROR_CODE.ERR_MILESTONE_ARGUMENT_INVALID, 'Missing snapshot')); | ||
@@ -54,3 +58,3 @@ var milestoneSnapshots = this._getMilestoneSnapshotsSync(collection, snapshot.id); | ||
if (!this._isValidTimestamp(timestamp)) { | ||
return process.nextTick(callback, new ShareDBError(4001, 'Invalid timestamp')); | ||
return process.nextTick(callback, new ShareDBError(ERROR_CODE.ERR_MILESTONE_ARGUMENT_INVALID, 'Invalid timestamp')); | ||
} | ||
@@ -64,3 +68,3 @@ | ||
if (!this._isValidTimestamp(timestamp)) { | ||
return process.nextTick(callback, new ShareDBError(4001, 'Invalid timestamp')); | ||
return process.nextTick(callback, new ShareDBError(ERROR_CODE.ERR_MILESTONE_ARGUMENT_INVALID, 'Invalid timestamp')); | ||
} | ||
@@ -82,4 +86,8 @@ | ||
MemoryMilestoneDB.prototype._findMilestoneSnapshot = function(collection, id, breakCondition, callback) { | ||
if (!collection) return process.nextTick(callback, new ShareDBError(4001, 'Missing collection')); | ||
if (!id) return process.nextTick(callback, new ShareDBError(4001, 'Missing ID')); | ||
if (!collection) { | ||
return process.nextTick( | ||
callback, new ShareDBError(ERROR_CODE.ERR_MILESTONE_ARGUMENT_INVALID, 'Missing collection') | ||
); | ||
} | ||
if (!id) return process.nextTick(callback, new ShareDBError(ERROR_CODE.ERR_MILESTONE_ARGUMENT_INVALID, 'Missing ID')); | ||
@@ -86,0 +94,0 @@ var milestoneSnapshots = this._getMilestoneSnapshotsSync(collection, id); |
@@ -7,7 +7,10 @@ // This contains the master OT functions for the database. They look like | ||
var types = require('./types').map; | ||
var ShareDBError = require('./error'); | ||
var ERROR_CODE = ShareDBError.CODES; | ||
// Returns an error string on failure. Rockin' it C style. | ||
exports.checkOp = function(op) { | ||
if (op == null || typeof op !== 'object') { | ||
return {code: 4004, message: 'Missing op'}; | ||
return new ShareDBError(ERROR_CODE.ERR_OT_OP_BADLY_FORMED, 'Op must be an object'); | ||
} | ||
@@ -17,23 +20,23 @@ | ||
if (typeof op.create !== 'object') { | ||
return {code: 4006, message: 'create data must be an object'}; | ||
return new ShareDBError(ERROR_CODE.ERR_OT_OP_BADLY_FORMED, 'Create data must be an object'); | ||
} | ||
var typeName = op.create.type; | ||
if (typeof typeName !== 'string') { | ||
return {code: 4007, message: 'Missing create type'}; | ||
return new ShareDBError(ERROR_CODE.ERR_OT_OP_BADLY_FORMED, 'Missing create type'); | ||
} | ||
var type = types[typeName]; | ||
if (type == null || typeof type !== 'object') { | ||
return {code: 4008, message: 'Unknown type'}; | ||
return new ShareDBError(ERROR_CODE.ERR_DOC_TYPE_NOT_RECOGNIZED, 'Unknown type'); | ||
} | ||
} else if (op.del != null) { | ||
if (op.del !== true) return {code: 4009, message: 'del value must be true'}; | ||
if (op.del !== true) return new ShareDBError(ERROR_CODE.ERR_OT_OP_BADLY_FORMED, 'del value must be true'); | ||
} else if (op.op == null) { | ||
return {code: 4010, message: 'Missing op, create, or del'}; | ||
return new ShareDBError(ERROR_CODE.ERR_OT_OP_BADLY_FORMED, 'Missing op, create, or del'); | ||
} | ||
if (op.src != null && typeof op.src !== 'string') { | ||
return {code: 4011, message: 'Invalid src'}; | ||
return new ShareDBError(ERROR_CODE.ERR_OT_OP_BADLY_FORMED, 'src must be a string'); | ||
} | ||
if (op.seq != null && typeof op.seq !== 'number') { | ||
return {code: 4012, message: 'Invalid seq'}; | ||
return new ShareDBError(ERROR_CODE.ERR_OT_OP_BADLY_FORMED, 'seq must be a string'); | ||
} | ||
@@ -44,7 +47,7 @@ if ( | ||
) { | ||
return {code: 4013, message: 'Both src and seq must be set together'}; | ||
return new ShareDBError(ERROR_CODE.ERR_OT_OP_BADLY_FORMED, 'Both src and seq must be set together'); | ||
} | ||
if (op.m != null && typeof op.m !== 'object') { | ||
return {code: 4014, message: 'op.m invalid'}; | ||
return new ShareDBError(ERROR_CODE.ERR_OT_OP_BADLY_FORMED, 'op.m must be an object or null'); | ||
} | ||
@@ -62,6 +65,6 @@ }; | ||
if (typeof snapshot !== 'object') { | ||
return {code: 5002, message: 'Missing snapshot'}; | ||
return new ShareDBError(ERROR_CODE.ERR_APPLY_SNAPSHOT_NOT_PROVIDED, 'Missing snapshot'); | ||
} | ||
if (snapshot.v != null && op.v != null && snapshot.v !== op.v) { | ||
return {code: 5003, message: 'Version mismatch'}; | ||
return new ShareDBError(ERROR_CODE.ERR_APPLY_OP_VERSION_DOES_NOT_MATCH_SNAPSHOT, 'Version mismatch'); | ||
} | ||
@@ -71,3 +74,3 @@ | ||
if (op.create) { | ||
if (snapshot.type) return {code: 4016, message: 'Document already exists'}; | ||
if (snapshot.type) return new ShareDBError(ERROR_CODE.ERR_DOC_ALREADY_CREATED, 'Document already exists'); | ||
@@ -77,3 +80,3 @@ // The document doesn't exist, although it might have once existed | ||
var type = types[create.type]; | ||
if (!type) return {code: 4008, message: 'Unknown type'}; | ||
if (!type) return new ShareDBError(ERROR_CODE.ERR_DOC_TYPE_NOT_RECOGNIZED, 'Unknown type'); | ||
@@ -107,7 +110,7 @@ try { | ||
function applyOpEdit(snapshot, edit) { | ||
if (!snapshot.type) return {code: 4015, message: 'Document does not exist'}; | ||
if (!snapshot.type) return new ShareDBError(ERROR_CODE.ERR_DOC_DOES_NOT_EXIST, 'Document does not exist'); | ||
if (edit == null) return {code: 5004, message: 'Missing op'}; | ||
if (edit == null) return new ShareDBError(ERROR_CODE.ERR_OT_OP_NOT_PROVIDED, 'Missing op'); | ||
var type = types[snapshot.type]; | ||
if (!type) return {code: 4008, message: 'Unknown type'}; | ||
if (!type) return new ShareDBError(ERROR_CODE.ERR_DOC_TYPE_NOT_RECOGNIZED, 'Unknown type'); | ||
@@ -125,3 +128,3 @@ try { | ||
if (op.v != null && op.v !== appliedOp.v) { | ||
return {code: 5006, message: 'Version mismatch'}; | ||
return new ShareDBError(ERROR_CODE.ERR_OP_VERSION_MISMATCH_DURING_TRANSFORM, 'Version mismatch'); | ||
} | ||
@@ -131,3 +134,3 @@ | ||
if (op.create || op.op) { | ||
return {code: 4017, message: 'Document was deleted'}; | ||
return new ShareDBError(ERROR_CODE.ERR_DOC_WAS_DELETED, 'Document was deleted'); | ||
} | ||
@@ -140,10 +143,10 @@ } else if ( | ||
// also means the document exists remotely. | ||
return {code: 4018, message: 'Document was created remotely'}; | ||
return new ShareDBError(ERROR_CODE.ERR_DOC_ALREADY_CREATED, 'Document was created remotely'); | ||
} else if (appliedOp.op && op.op) { | ||
// If we reach here, they both have a .op property. | ||
if (!type) return {code: 5005, message: 'Document does not exist'}; | ||
if (!type) return new ShareDBError(ERROR_CODE.ERR_DOC_DOES_NOT_EXIST, 'Document does not exist'); | ||
if (typeof type === 'string') { | ||
type = types[type]; | ||
if (!type) return {code: 4008, message: 'Unknown type'}; | ||
if (!type) return new ShareDBError(ERROR_CODE.ERR_DOC_TYPE_NOT_RECOGNIZED, 'Unknown type'); | ||
} | ||
@@ -173,3 +176,3 @@ | ||
type = types[snapshot.type]; | ||
if (!type) return {code: 4008, message: 'Unknown type'}; | ||
if (!type) return new ShareDBError(ERROR_CODE.ERR_DOC_TYPE_NOT_RECOGNIZED, 'Unknown type'); | ||
} | ||
@@ -184,3 +187,3 @@ | ||
type = types[op.create.type]; | ||
if (!type) return {code: 4008, message: 'Unknown type'}; | ||
if (!type) return new ShareDBError(ERROR_CODE.ERR_DOC_TYPE_NOT_RECOGNIZED, 'Unknown type'); | ||
snapshot.data = type.create(op.create.data); | ||
@@ -187,0 +190,0 @@ snapshot.type = type.uri; |
var json0 = require('ot-json0').type; | ||
var ShareDBError = require('./error'); | ||
var ERROR_CODE = ShareDBError.CODES; | ||
exports.projectSnapshot = projectSnapshot; | ||
@@ -14,3 +17,3 @@ exports.projectSnapshots = projectSnapshots; | ||
if (snapshot.type && snapshot.type !== json0.uri) { | ||
throw new Error(4023, 'Cannot project snapshots of type ' + snapshot.type); | ||
throw new Error(ERROR_CODE.ERR_TYPE_CANNOT_BE_PROJECTED, 'Cannot project snapshots of type ' + snapshot.type); | ||
} | ||
@@ -17,0 +20,0 @@ snapshot.data = projectData(fields, snapshot.data); |
@@ -6,2 +6,4 @@ var emitter = require('../emitter'); | ||
var ERROR_CODE = ShareDBError.CODES; | ||
function PubSub(options) { | ||
@@ -42,3 +44,6 @@ if (!(this instanceof PubSub)) return new PubSub(options); | ||
process.nextTick(function() { | ||
callback(new ShareDBError(5015, '_subscribe PubSub method unimplemented')); | ||
callback(new ShareDBError( | ||
ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, | ||
'_subscribe PubSub method unimplemented' | ||
)); | ||
}); | ||
@@ -49,3 +54,6 @@ }; | ||
process.nextTick(function() { | ||
callback(new ShareDBError(5016, '_unsubscribe PubSub method unimplemented')); | ||
callback(new ShareDBError( | ||
ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, | ||
'_unsubscribe PubSub method unimplemented' | ||
)); | ||
}); | ||
@@ -56,3 +64,3 @@ }; | ||
process.nextTick(function() { | ||
callback(new ShareDBError(5017, '_publish PubSub method unimplemented')); | ||
callback(new ShareDBError(ERROR_CODE.ERR_DATABASE_METHOD_NOT_IMPLEMENTED, '_publish PubSub method unimplemented')); | ||
}); | ||
@@ -128,3 +136,3 @@ }; | ||
// Synchronously clear subscribed state. We won't actually be unsubscribed | ||
// until some unkown time in the future. If subscribe is called in this | ||
// until some unknown time in the future. If subscribe is called in this | ||
// period, we want to send a subscription message and wait for it to | ||
@@ -131,0 +139,0 @@ // complete before we can count on being subscribed again |
@@ -6,2 +6,4 @@ var arraydiff = require('arraydiff'); | ||
var ERROR_CODE = ShareDBError.CODES; | ||
function QueryEmitter(request, stream, ids, extra) { | ||
@@ -164,3 +166,3 @@ this.backend = request.backend; | ||
// | ||
// This isn't neccessary for the document polling case, since they operate | ||
// This isn't necessary for the document polling case, since they operate | ||
// on a given id and won't accidentally modify the wrong doc. Also, those | ||
@@ -289,3 +291,3 @@ // queries should be faster and are less likely to be the same, so there is | ||
// Clients must assign each of these functions syncronously after constructing | ||
// Clients must assign each of these functions synchronously after constructing | ||
// an instance of QueryEmitter. The instance is subscribed to an op stream at | ||
@@ -299,3 +301,6 @@ // construction time, and does not buffer emitted events. Diff events assume | ||
QueryEmitter.prototype.onOp = function() { | ||
throw new ShareDBError(5018, 'Required QueryEmitter listener not assigned'); | ||
throw new ShareDBError( | ||
ERROR_CODE.ERR_QUERY_EMITTER_LISTENER_NOT_ASSIGNED, | ||
'Required QueryEmitter listener not assigned' | ||
); | ||
}; | ||
@@ -302,0 +307,0 @@ |
var ot = require('./ot'); | ||
var projections = require('./projections'); | ||
var ShareDBError = require('./error'); | ||
var ERROR_CODE = ShareDBError.CODES; | ||
function SubmitRequest(backend, agent, index, id, op, options) { | ||
@@ -243,32 +246,47 @@ this.backend = backend; | ||
SubmitRequest.prototype.alreadySubmittedError = function() { | ||
return {code: 4001, message: 'Op already submitted'}; | ||
return new ShareDBError(ERROR_CODE.ERR_OP_ALREADY_SUBMITTED, 'Op already submitted'); | ||
}; | ||
SubmitRequest.prototype.rejectedError = function() { | ||
return {code: 4002, message: 'Op submit rejected'}; | ||
return new ShareDBError(ERROR_CODE.ERR_OP_SUBMIT_REJECTED, 'Op submit rejected'); | ||
}; | ||
// Fatal client errors: | ||
SubmitRequest.prototype.alreadyCreatedError = function() { | ||
return {code: 4010, message: 'Invalid op submitted. Document already created'}; | ||
return new ShareDBError(ERROR_CODE.ERR_DOC_ALREADY_CREATED, 'Invalid op submitted. Document already created'); | ||
}; | ||
SubmitRequest.prototype.newerVersionError = function() { | ||
return {code: 4011, message: 'Invalid op submitted. Op version newer than current snapshot'}; | ||
return new ShareDBError( | ||
ERROR_CODE.ERR_OP_VERSION_NEWER_THAN_CURRENT_SNAPSHOT, | ||
'Invalid op submitted. Op version newer than current snapshot' | ||
); | ||
}; | ||
SubmitRequest.prototype.projectionError = function() { | ||
return {code: 4012, message: 'Invalid op submitted. Operation invalid in projected collection'}; | ||
return new ShareDBError( | ||
ERROR_CODE.ERR_OP_NOT_ALLOWED_IN_PROJECTION, | ||
'Invalid op submitted. Operation invalid in projected collection' | ||
); | ||
}; | ||
// Fatal internal errors: | ||
SubmitRequest.prototype.missingOpsError = function() { | ||
return { | ||
code: 5001, | ||
message: 'Op submit failed. DB missing ops needed to transform it up to the current snapshot version' | ||
}; | ||
return new ShareDBError( | ||
ERROR_CODE.ERR_SUBMIT_TRANSFORM_OPS_NOT_FOUND, | ||
'Op submit failed. DB missing ops needed to transform it up to the current snapshot version' | ||
); | ||
}; | ||
SubmitRequest.prototype.versionDuringTransformError = function() { | ||
return {code: 5002, message: 'Op submit failed. Versions mismatched during op transform'}; | ||
return new ShareDBError( | ||
ERROR_CODE.ERR_OP_VERSION_MISMATCH_DURING_TRANSFORM, | ||
'Op submit failed. Versions mismatched during op transform' | ||
); | ||
}; | ||
SubmitRequest.prototype.versionAfterTransformError = function() { | ||
return {code: 5003, message: 'Op submit failed. Op version mismatches snapshot after op transform'}; | ||
return new ShareDBError( | ||
ERROR_CODE.ERR_OP_VERSION_MISMATCH_AFTER_TRANSFORM, | ||
'Op submit failed. Op version mismatches snapshot after op transform' | ||
); | ||
}; | ||
SubmitRequest.prototype.maxRetriesError = function() { | ||
return {code: 5004, message: 'Op submit failed. Maximum submit retries exceeded'}; | ||
return new ShareDBError( | ||
ERROR_CODE.ERR_MAX_SUBMIT_RETRIES_EXCEEDED, | ||
'Op submit failed. Exceeded max submit retries of ' + this.maxRetries | ||
); | ||
}; |
{ | ||
"name": "sharedb", | ||
"version": "1.0.0-beta.31", | ||
"version": "1.0.0", | ||
"description": "JSON OT database backend", | ||
@@ -11,3 +11,2 @@ "main": "lib/index.js", | ||
"hat": "0.0.3", | ||
"make-error": "^1.1.1", | ||
"ot-json0": "^1.0.1" | ||
@@ -14,0 +13,0 @@ }, |
132
README.md
@@ -654,67 +654,83 @@ # ShareDB | ||
## Error codes | ||
## Errors | ||
ShareDB returns errors as plain JavaScript objects with the format: | ||
ShareDB returns errors as an instance of `ShareDBError`, with a machine-parsable `code`, as well as more details in the human-readable `message`. | ||
### Common error codes | ||
#### `ERR_OP_SUBMIT_REJECTED` | ||
The op submitted by the client has been rejected by the server for a non-critical reason. | ||
When the client receives this code, it will attempt to roll back the rejected op, leaving the client in a usable state. | ||
This error might be used as part of standard control flow. For example, consumers may define a middleware that validates document structure, and rejects operations that do not conform to this schema using this error code to reset the client to a valid state. | ||
#### `ERR_OP_ALREADY_SUBMITTED` | ||
The same op has been received by the server twice. | ||
This is non-critical, and part of normal control flow, and is sent as an error in order to short-circuit the op processing. It is eventually swallowed by the server, and shouldn't need further handling. | ||
#### `ERR_SUBMIT_TRANSFORM_OPS_NOT_FOUND` | ||
The ops needed to transform the submitted op up to the current version of the snapshot could not be found. | ||
If a client on an old version of a document submits an op, that op needs to be transformed by all the ops that have been applied to the document in the meantime. If the server cannot fetch these ops from the database, then this error is returned. | ||
The most common case of this would be ops being deleted from the database. For example, let's assume we have a TTL set up on the ops in our database. Let's also say we have a client that is so old that the op corresponding to its version has been deleted by the TTL policy. If this client then attempts to submit an op, the server will not be able to find the ops required to transform the op to apply to the current version of the snapshot. | ||
Other causes of this error may be dropping the ops collection all together, or having the database corrupted in some other way. | ||
#### `ERR_MAX_SUBMIT_RETRIES_EXCEEDED` | ||
The number of retries defined by the `maxSubmitRetries` option has been exceeded by a submission. | ||
#### `ERR_DOC_ALREADY_CREATED` | ||
The creation request has failed, because the document was already created by another client. | ||
This can happen when two clients happen to simultaneously try to create the same document, and is potentially recoverable by simply fetching the already-created document. | ||
#### `ERR_DOC_WAS_DELETED` | ||
The deletion request has failed, because the document was already deleted by another client. | ||
This can happen when two clients happen to simultaneously try to delete the same document. Given that the end result is the same, this error can potentially just be ignored. | ||
#### `ERR_DOC_TYPE_NOT_RECOGNIZED` | ||
The specified document type has not been registered with ShareDB. | ||
This error can usually be remedied by remembering to register any types you need: | ||
```javascript | ||
var ShareDB = require('sharedb'); | ||
var richText = require('rich-text'); | ||
ShareDB.types.register(richText.type); | ||
``` | ||
{ | ||
code: 5000, | ||
message: 'ShareDB internal error' | ||
} | ||
#### `ERR_DEFAULT_TYPE_MISMATCH` | ||
The default type being used by the client does not match the default type expected by the server. | ||
This will typically only happen when using a different default type to the built-in `json0` used by ShareDB by default (eg if using a fork). The exact same type must be used by both the client and the server, and should be registered as the default type: | ||
```javascript | ||
var ShareDB = require('sharedb'); | ||
var forkedJson0 = require('forked-json0'); | ||
// Make sure to also do this on your client | ||
ShareDB.types.defaultType = forkedJson0.type; | ||
``` | ||
Additional fields may be added to the error object for debugging context depending on the error. Common additional fields include `collection`, `id`, and `op`. | ||
#### `ERR_OP_NOT_ALLOWED_IN_PROJECTION` | ||
### 4000 - Bad request | ||
The submitted op is not valid when applied to the projection. | ||
* 4001 - Unknown error type | ||
* 4002 - Database adapter does not support subscribe | ||
* 4003 - Database adapter not found | ||
* 4004 - Missing op | ||
* 4005 - Op must be an array | ||
* 4006 - Create data in op must be an object | ||
* 4007 - Create op missing type | ||
* 4008 - Unknown type | ||
* 4009 - del value must be true | ||
* 4010 - Missing op, create or del | ||
* 4011 - Invalid src | ||
* 4012 - Invalid seq | ||
* 4013 - Found seq but not src | ||
* 4014 - op.m invalid | ||
* 4015 - Document does not exist | ||
* 4016 - Document already exists | ||
* 4017 - Document was deleted | ||
* 4018 - Document was created remotely | ||
* 4019 - Invalid protocol version | ||
* 4020 - Invalid default type | ||
* 4021 - Invalid client id | ||
* 4022 - Database adapter does not support queries | ||
* 4023 - Cannot project snapshots of this type | ||
* 4024 - Invalid version | ||
* 4025 - Passing options to subscribe has not been implemented | ||
This may happen if the op targets some property that is not included in the projection. | ||
### 5000 - Internal error | ||
#### `ERR_TYPE_CANNOT_BE_PROJECTED` | ||
The `41xx` and `51xx` codes are reserved for use by ShareDB DB adapters, and the `42xx` and `52xx` codes are reserved for use by ShareDB PubSub adapters. | ||
* 5001 - No new ops returned when retrying unsuccessful submit | ||
* 5002 - Missing snapshot | ||
* 5003 - Snapshot and op version don't match | ||
* 5004 - Missing op | ||
* 5005 - Missing document | ||
* 5006 - Version mismatch | ||
* 5007 - Invalid state transition | ||
* 5008 - Missing version in snapshot | ||
* 5009 - Cannot ingest snapshot with null version | ||
* 5010 - No op to send | ||
* 5011 - Commit DB method unimplemented | ||
* 5012 - getSnapshot DB method unimplemented | ||
* 5013 - getOps DB method unimplemented | ||
* 5014 - queryPollDoc DB method unimplemented | ||
* 5015 - _subscribe PubSub method unimplemented | ||
* 5016 - _unsubscribe PubSub method unimplemented | ||
* 5017 - _publish PubSub method unimplemented | ||
* 5018 - Required QueryEmitter listener not assigned | ||
* 5019 - getMilestoneSnapshot MilestoneDB method unimplemented | ||
* 5020 - saveMilestoneSnapshot MilestoneDB method unimplemented | ||
* 5021 - getMilestoneSnapshotAtOrBeforeTime MilestoneDB method unimplemented | ||
* 5022 - getMilestoneSnapshotAtOrAfterTime MilestoneDB method unimplemented | ||
The document's type cannot be projected. `json0` is currently the only type that supports projections. |
@@ -98,3 +98,3 @@ var Backend = require('../lib/backend'); | ||
backend.subscribe(null, 'books', '1984', null, options, function(error) { | ||
expect(error.code).to.equal(4025); | ||
expect(error.code).to.equal('ERR_DATABASE_METHOD_NOT_IMPLEMENTED'); | ||
done(); | ||
@@ -101,0 +101,0 @@ }); |
@@ -145,3 +145,3 @@ var Backend = require('../../lib/backend'); | ||
backend.connect().fetchSnapshot('books', 'don-quixote', 4, function(error, snapshot) { | ||
expect(error.code).to.equal(4024); | ||
expect(error.code).to.equal('ERR_OP_VERSION_NEWER_THAN_CURRENT_SNAPSHOT'); | ||
expect(snapshot).to.equal(undefined); | ||
@@ -148,0 +148,0 @@ done(); |
@@ -640,3 +640,3 @@ var async = require('async'); | ||
doc.submitOp({p: ['age'], na: 1}, function(err) { | ||
expect(err.code).to.equal(4017); | ||
expect(err.code).to.equal('ERR_DOC_WAS_DELETED'); | ||
expect(doc.version).equal(2); | ||
@@ -665,3 +665,3 @@ expect(doc.data).eql(undefined); | ||
doc.create({age: 9}, function(err) { | ||
expect(err.code).to.equal(4018); | ||
expect(err.code).to.equal('ERR_DOC_ALREADY_CREATED'); | ||
expect(doc.version).equal(3); | ||
@@ -773,3 +773,3 @@ expect(doc.data).eql({age: 5}); | ||
var doc = this.backend.connect().get('dogs', 'fido'); | ||
this.backend.use('doc', function(request, next) { | ||
this.backend.use('readSnapshots', function(request, next) { | ||
doc.create({age: 3}); | ||
@@ -787,3 +787,3 @@ doc.del(next); | ||
var doc = this.backend.connect().get('dogs', 'fido'); | ||
this.backend.use('doc', function(request, next) { | ||
this.backend.use('readSnapshots', function(request, next) { | ||
doc.create({age: 3}, function(err) { | ||
@@ -790,0 +790,0 @@ if (err) return done(err); |
@@ -260,4 +260,4 @@ var expect = require('chai').expect; | ||
it(method + ' returns error passed to doc read middleware', function(done) { | ||
this.backend.use('doc', function(request, next) { | ||
it(method + ' returns error passed to readSnapshots middleware', function(done) { | ||
this.backend.use('readSnapshots', function(request, next) { | ||
next({message: 'Reject doc read'}); | ||
@@ -278,4 +278,4 @@ }); | ||
it(method + ' emits error passed to doc read middleware', function(done) { | ||
this.backend.use('doc', function(request, next) { | ||
it(method + ' emits error passed to readSnapshots middleware', function(done) { | ||
this.backend.use('readSnapshots', function(request, next) { | ||
next({message: 'Reject doc read'}); | ||
@@ -282,0 +282,0 @@ }); |
@@ -62,3 +62,37 @@ var Backend = require('../lib/backend'); | ||
function testReadDoc(expectFidoOnly, expectFidoAndSpot) { | ||
describe('readSnapshots', function() { | ||
function expectFido(request) { | ||
expect(request.collection).to.equal('dogs'); | ||
expect(request.snapshots[0]).to.have.property('id', 'fido'); | ||
expect(request.snapshots[0]).to.have.property('data').eql({age: 3}); | ||
} | ||
function expectSpot(request) { | ||
expect(request.collection).to.equal('dogs'); | ||
expect(request.snapshots[1]).to.have.property('id', 'spot'); | ||
expect(request.snapshots[1]).to.have.property('type').equal(null); | ||
} | ||
function expectFidoOnly(backend, done) { | ||
var doneAfter = util.callAfter(1, done); | ||
backend.use('readSnapshots', function(request, next) { | ||
expect(request.snapshots).to.have.length(1); | ||
expectFido(request); | ||
doneAfter(); | ||
next(); | ||
}); | ||
return doneAfter; | ||
} | ||
function expectFidoAndSpot(backend, done) { | ||
var doneAfter = util.callAfter(1, done); | ||
backend.use('readSnapshots', function(request, next) { | ||
expect(request.snapshots).to.have.length(2); | ||
expectFido(request); | ||
expectSpot(request); | ||
doneAfter(); | ||
next(); | ||
}); | ||
return doneAfter; | ||
} | ||
beforeEach('Add fido to db', function(done) { | ||
@@ -112,113 +146,4 @@ this.snapshot = {v: 1, type: 'json0', data: {age: 3}}; | ||
}); | ||
} | ||
describe('doc', function() { | ||
describe('with default options for backend constructor', function() { | ||
function expectFido(request) { | ||
expect(request.collection).to.equal('dogs'); | ||
expect(request.id).to.equal('fido'); | ||
expect(request.snapshot).to.have.property('data').eql({age: 3}); | ||
} | ||
function expectSpot(request) { | ||
expect(request.collection).to.equal('dogs'); | ||
expect(request.id).to.equal('spot'); | ||
expect(request.snapshot).to.have.property('type').equal(null); | ||
} | ||
function expectFidoOnly(backend, done) { | ||
var doneAfter = util.callAfter(1, done); | ||
backend.use('doc', function(request, next) { | ||
expectFido(request); | ||
doneAfter(); | ||
next(); | ||
}); | ||
return doneAfter; | ||
} | ||
function expectFidoAndSpot(backend, done) { | ||
var doneAfter = util.callAfter(2, done); | ||
backend.use('doc', function(request, next) { | ||
doneAfter(); | ||
if (doneAfter.called === 1) { | ||
expectFido(request); | ||
} else { | ||
expectSpot(request); | ||
} | ||
next(); | ||
}); | ||
return doneAfter; | ||
} | ||
testReadDoc(expectFidoOnly, expectFidoAndSpot); | ||
}); | ||
describe('with disableDocAction option set to true for backend constructor', function() { | ||
beforeEach('Create backend with disableDocAction option', function() { | ||
this.backend = new Backend({disableDocAction: true}); | ||
}); | ||
it('is not triggered when a document is retrieved with fetch', function(done) { | ||
this.backend.use('doc', passError); | ||
this.backend.fetch({}, 'dogs', 'fido', done); | ||
}); | ||
it('is not triggered when a document is retrieved with subscribe', function(done) { | ||
this.backend.use('doc', passError); | ||
this.backend.subscribe({}, 'dogs', 'fido', null, done); | ||
}); | ||
['queryFetch', 'querySubscribe'].forEach(function(queryMethod) { | ||
it('is not triggered when multiple documents are retrieved with ' + queryMethod, function(done) { | ||
this.backend.use('doc', passError); | ||
this.backend[queryMethod]({}, 'dogs', {age: 3}, {}, done); | ||
}); | ||
}); | ||
['fetchBulk', 'subscribeBulk'].forEach(function(bulkMethod) { | ||
it('is not triggered when a document is retrieved with ' + bulkMethod, function(done) { | ||
this.backend.use('doc', passError); | ||
this.backend[bulkMethod]({}, 'dogs', ['fido', 'spot'], done); | ||
}); | ||
}); | ||
}); | ||
}); | ||
describe('readSnapshots', function() { | ||
function expectFido(request) { | ||
expect(request.collection).to.equal('dogs'); | ||
expect(request.snapshots[0]).to.have.property('id', 'fido'); | ||
expect(request.snapshots[0]).to.have.property('data').eql({age: 3}); | ||
} | ||
function expectSpot(request) { | ||
expect(request.collection).to.equal('dogs'); | ||
expect(request.snapshots[1]).to.have.property('id', 'spot'); | ||
expect(request.snapshots[1]).to.have.property('type').equal(null); | ||
} | ||
function expectFidoOnly(backend, done) { | ||
var doneAfter = util.callAfter(1, done); | ||
backend.use('readSnapshots', function(request, next) { | ||
expect(request.snapshots).to.have.length(1); | ||
expectFido(request); | ||
doneAfter(); | ||
next(); | ||
}); | ||
return doneAfter; | ||
} | ||
function expectFidoAndSpot(backend, done) { | ||
var doneAfter = util.callAfter(1, done); | ||
backend.use('readSnapshots', function(request, next) { | ||
expect(request.snapshots).to.have.length(2); | ||
expectFido(request); | ||
expectSpot(request); | ||
doneAfter(); | ||
next(); | ||
}); | ||
return doneAfter; | ||
} | ||
testReadDoc(expectFidoOnly, expectFidoAndSpot); | ||
}); | ||
describe('reply', function() { | ||
@@ -293,4 +218,3 @@ beforeEach(function(done) { | ||
describe('submit lifecycle', function() { | ||
// DEPRECATED: 'after submit' and 'afterSubmit' are synonyms for 'afterWrite' | ||
['submit', 'apply', 'commit', 'afterWrite', 'afterSubmit', 'after submit'].forEach(function(action) { | ||
['submit', 'apply', 'commit', 'afterWrite'].forEach(function(action) { | ||
it(action + ' gets options passed to backend.submit', function(done) { | ||
@@ -297,0 +221,0 @@ var doneAfter = util.callAfter(1, done); |
@@ -17,3 +17,3 @@ var expect = require('chai').expect; | ||
db.getMilestoneSnapshot('books', '123', 1, function(error) { | ||
expect(error.code).to.equal(5019); | ||
expect(error.code).to.equal('ERR_DATABASE_METHOD_NOT_IMPLEMENTED'); | ||
done(); | ||
@@ -25,3 +25,3 @@ }); | ||
db.on('error', function(error) { | ||
expect(error.code).to.equal(5019); | ||
expect(error.code).to.equal('ERR_DATABASE_METHOD_NOT_IMPLEMENTED'); | ||
done(); | ||
@@ -35,3 +35,3 @@ }); | ||
db.saveMilestoneSnapshot('books', {}, function(error) { | ||
expect(error.code).to.equal(5020); | ||
expect(error.code).to.equal('ERR_DATABASE_METHOD_NOT_IMPLEMENTED'); | ||
done(); | ||
@@ -43,3 +43,3 @@ }); | ||
db.on('error', function(error) { | ||
expect(error.code).to.equal(5020); | ||
expect(error.code).to.equal('ERR_DATABASE_METHOD_NOT_IMPLEMENTED'); | ||
done(); | ||
@@ -53,3 +53,3 @@ }); | ||
db.getMilestoneSnapshotAtOrBeforeTime('books', '123', 1000, function(error) { | ||
expect(error.code).to.equal(5021); | ||
expect(error.code).to.equal('ERR_DATABASE_METHOD_NOT_IMPLEMENTED'); | ||
done(); | ||
@@ -61,3 +61,3 @@ }); | ||
db.getMilestoneSnapshotAtOrAfterTime('books', '123', 1000, function(error) { | ||
expect(error.code).to.equal(5022); | ||
expect(error.code).to.equal('ERR_DATABASE_METHOD_NOT_IMPLEMENTED'); | ||
done(); | ||
@@ -64,0 +64,0 @@ }); |
@@ -17,3 +17,3 @@ var MemoryPubSub = require('../lib/pubsub/memory'); | ||
expect(err).instanceOf(Error); | ||
expect(err.code).to.equal(5015); | ||
expect(err.code).to.equal('ERR_DATABASE_METHOD_NOT_IMPLEMENTED'); | ||
done(); | ||
@@ -27,3 +27,3 @@ }); | ||
expect(err).instanceOf(Error); | ||
expect(err.code).to.equal(5015); | ||
expect(err.code).to.equal('ERR_DATABASE_METHOD_NOT_IMPLEMENTED'); | ||
done(); | ||
@@ -43,3 +43,3 @@ }); | ||
expect(err).instanceOf(Error); | ||
expect(err.code).to.equal(5016); | ||
expect(err.code).to.equal('ERR_DATABASE_METHOD_NOT_IMPLEMENTED'); | ||
done(); | ||
@@ -56,3 +56,3 @@ }); | ||
expect(err).instanceOf(Error); | ||
expect(err.code).to.equal(5017); | ||
expect(err.code).to.equal('ERR_DATABASE_METHOD_NOT_IMPLEMENTED'); | ||
done(); | ||
@@ -66,3 +66,3 @@ }); | ||
expect(err).instanceOf(Error); | ||
expect(err.code).to.equal(5017); | ||
expect(err.code).to.equal('ERR_DATABASE_METHOD_NOT_IMPLEMENTED'); | ||
done(); | ||
@@ -69,0 +69,0 @@ }); |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
2013604
5
95
12498
1
736
- Removedmake-error@^1.1.1
- Removedmake-error@1.3.6(transitive)