Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Refactor CouchDB Integration #9

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions sandbox/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,14 @@ <h3>Result</h3>
<script>
var callUrl;
truman.initialize({
database: {
url: 'http://127.0.0.1:5984/fixtures'
}
storage: {
couchDB: {
url: 'http://127.0.0.1:5984/fixtures',
user: '',
password: ''
}
},
fixtures: {}
}).then(function() {
callUrl = function(){
$.ajax({
Expand Down
6 changes: 3 additions & 3 deletions src/helpers/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ let stateHelper = module.exports = {

updateState(newState) {
if (!newState) {
return localStorage.removeItem('autoFixture');
return localStorage.removeItem('truman');
}

let state = stateHelper.loadState();
localStorage.setItem('autoFixture', JSON.stringify(_.assign(state, newState)));
localStorage.setItem('truman', JSON.stringify(_.assign(state, newState)));
},

loadState() {
return JSON.parse(localStorage.getItem('autoFixture') || '{}');
return JSON.parse(localStorage.getItem('truman') || '{}');
}

};
Original file line number Diff line number Diff line change
Expand Up @@ -2,70 +2,52 @@

require('Base64');

let _ = require('lodash');
let PouchDB = require('pouchdb');
const _ = require('lodash');
const PouchDB = window.PouchDB = require('pouchdb');
const DB_NAME = 'truman';
const REQUEST_TIMEOUT = 120000;

const STORAGE_PREFIX = 'fixture-';
const NO_NAME_ERR_MSG = 'Fixture collection name not provided.';

let config = {};
let localDB = null;
let remoteDB = null;
let cachedRevisionMapping = null;

let fixtureHelper = module.exports = {
initialize(options) {
_.assign(config, options);
window.PouchDB = PouchDB; // Necessary for the PouchDB Chrome inspector
localDB = new PouchDB('truman');

if (config.database) {
let remoteConfig = {
ajax: {
timeout: 120000
}
};
localDB = new PouchDB(DB_NAME);

if (config.database.user && config.database.password) {
remoteConfig.ajax.headers = {
Authorization: 'Basic ' + window.btoa(config.database.user + ':' + config.database.password)
};
const remoteConfig = {
ajax: {
timeout: REQUEST_TIMEOUT
}
};

remoteDB = new PouchDB(config.database.url, remoteConfig);
}
},

load(fixtureCollectionName) {
if (!fixtureCollectionName) {
throw new Error(NO_NAME_ERR_MSG);
if (options.user && options.password) {
remoteCOnfig.ajax.headers = {
Authorization: 'Basic ' + window.btoa(options.user + ':' + options.password)
};
}

const id = fixtureHelper._buildId(fixtureCollectionName);
remoteDB = new PouchDB(options.url, remoteConfig);
},

load(id) {
return fixtureHelper._loadFromDatabase(localDB, id);
},

store(fixtures, fixtureCollectionName) {
if (!fixtureCollectionName) {
throw new Error(NO_NAME_ERR_MSG);
}

const id = fixtureHelper._buildId(fixtureCollectionName);
let fixtureRecord = { _id: id, fixtures: fixtures };

return fixtureHelper._storeToDatabase(localDB, id, fixtureRecord);
store(fixtures, id) {
return fixtureHelper._storeToDatabase(localDB, id, {
_id: id,
fixtures
});
},

push(fixtureCollectionName, tag) {
if (!fixtureCollectionName) {
throw new Error(NO_NAME_ERR_MSG);
}

return fixtureHelper.load(fixtureCollectionName)
push(id, tag) {
return fixtureHelper.load(id)
.then((fixtures) => {
const id = fixtureHelper._buildId(fixtureCollectionName);
const fixtureRecord = { _id: id, fixtures: fixtures };
const fixtureRecord = {
_id: id,
fixtures
};

return fixtureHelper._storeToDatabase(remoteDB, id, fixtureRecord, tag)
.then(() => fixtures)
Expand All @@ -75,30 +57,15 @@ let fixtureHelper = module.exports = {
});
},

pull(fixtureCollectionName, tags) {
if (!fixtureCollectionName) {
throw new Error(NO_NAME_ERR_MSG);
}

return fixtureHelper.getLatestRevisionMapping(fixtureCollectionName, tags)
pull(id, tags) {
return fixtureHelper.getLatestRevisionMapping(id, tags)
.then((latestRevisionMapping) => {
const id = fixtureHelper._buildId(fixtureCollectionName);

if (!latestRevisionMapping) {
return fixtureHelper._copyFromRemote(fixtureCollectionName, id);
}

return fixtureHelper._copyFromRemote(fixtureCollectionName, id, latestRevisionMapping.revision);
const latestRevision = _.result(latestRevisionMapping, 'revision');
return fixtureHelper._copyFromRemote(id, latestRevision)
});
},

clear(fixtureCollectionName) {
if (!fixtureCollectionName) {
throw new Error(NO_NAME_ERR_MSG);
}

const id = fixtureHelper._buildId(fixtureCollectionName);

clear(id) {
return localDB.get(id)
.catch(fixtureHelper._swallow404)
.then((existingFixtureRecord) => {
Expand All @@ -109,32 +76,19 @@ let fixtureHelper = module.exports = {
});
},

getLatestRevisionMapping(fixtureCollectionName, tags) {
if (!fixtureCollectionName) {
throw new Error(NO_NAME_ERR_MSG);
}

if (!_.isArray(tags)) {
tags = _.compact([tags]);
}
getLatestRevisionMapping(id, tags) {
tags = _.compact([].concat(tags)); // Forces an array and removes empty values

return fixtureHelper._getRevisionMapping(fixtureCollectionName)
return fixtureHelper._getRevisionMapping(id)
.then((fixtureRevisionMappings) => {
return fixtureRevisionMappings.find((fixtureRevisionMapping) => _.includes(tags, fixtureRevisionMapping.tag));
});
},

_getRevisionMapping(fixtureCollectionName) {
if (!fixtureCollectionName) {
throw new Error(NO_NAME_ERR_MSG);
}

_getRevisionMapping(id) {
if (cachedRevisionMapping) {
return Promise.resolve(cachedRevisionMapping);
}

const id = fixtureHelper._buildId(fixtureCollectionName);

return remoteDB.get(id, { revs_info: true })
.catch(fixtureHelper._swallow404)
.then((response) => {
Expand Down Expand Up @@ -204,10 +158,10 @@ let fixtureHelper = module.exports = {
});
},

_copyFromRemote(fixtureCollectionName, id, revision) {
_copyFromRemote(id, revision) {
return fixtureHelper._loadFromDatabase(remoteDB, id, revision)
.then((fixtures) => {
return fixtureHelper.store(fixtures, fixtureCollectionName)
return fixtureHelper.store(fixtures, id)
.then(() => fixtures);
});
},
Expand All @@ -216,10 +170,6 @@ let fixtureHelper = module.exports = {
return Number.parseInt(revision.match(/[^-]+/)[0], 10) + 1;
},

_buildId(fixtureCollectionName) {
return STORAGE_PREFIX + fixtureCollectionName;
},

// Swallow the error if the record doesn't exist yet...
_swallow404(err) {
if (err.status !== 404) {
Expand Down
53 changes: 52 additions & 1 deletion src/storage/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,54 @@
'use strict';

module.exports = require('./adaptors/couchDB');
const couchDB = require('./adaptors/couchDB');

module.exports = {
initialize(options) {
return couchDB.initialize(options.couchDB);
},

/*
* Load the latest version of the fixture with a given id from local storage.
*/
load(id) {
return couchDB.load(id);
},

/*
* Store an array of fixtures under the the given id to local storage.
* If a record already exists under this id, create a new version. Otherwise,
* create the first version.
*/
store(fixtures, id) {
return couchDB.store(fixtures, id);
},

/*
* Push the fixture record with the given id to remote storage, stored under
* the given tag.
*/
push(id, tag) {
return couchDB.push(id, tag);
},

/*
* Pull the fixture record with the given id and tag from remote storage.
*/
pull(id, tags) {
return couchDB.pull(id, tags);
},

/*
* Remove the local fixture record with the given id.
*/
clear(id) {
return couchDB.clear(id);
},

/*
* Remove the local fixture record with the given id.
*/
getLatestRevisionMapping(id, tags) {
return couchDB.getLatestRevisionMapping(id, tags);
}
}
23 changes: 20 additions & 3 deletions src/truman.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ let storage = require('./storage');

let Promise = require('lie');
let _ = require('lodash');
var storageFixtures = [];
let storageFixtures = [];

const NO_NAME_ERR_MSG = 'Fixture collection name not provided.';
const RECORDING_STATE = 'recording';
const REPLAYING_STATE = 'replaying';

Expand All @@ -29,8 +30,8 @@ let truman = module.exports = {
return Promise.resolve(message);
}

storage.initialize(options);
fixtureHelper.initialize(options);
storage.initialize(options.storage);
fixtureHelper.initialize(options.fixtures);

return truman._restoreState().then(() => {
truman._initialized = true;
Expand All @@ -43,6 +44,9 @@ let truman = module.exports = {
},

pull(fixtureCollectionName, tags, callback) {
if (!fixtureCollectionName) {
throw new Error(NO_NAME_ERR_MSG);
}
if (truman.currentStatus()) {
throw new Error('Cannot pull when in either a recording or replaying state, call `truman.restore()` first.');
}
Expand All @@ -65,6 +69,9 @@ let truman = module.exports = {
},

push(fixtureCollectionName, tag, callback) {
if (!fixtureCollectionName) {
throw new Error(NO_NAME_ERR_MSG);
}
if (truman.currentStatus()) {
throw new Error('Cannot push when in either a recording or replaying state, call `truman.restore()` first.');
}
Expand All @@ -85,6 +92,9 @@ let truman = module.exports = {
},

record(fixtureCollectionName, callback) {
if (!fixtureCollectionName) {
throw new Error(NO_NAME_ERR_MSG);
}
if (truman.currentStatus() === REPLAYING_STATE) {
truman.restore();
}
Expand Down Expand Up @@ -121,6 +131,9 @@ let truman = module.exports = {
},

replay(fixtureCollectionName, callback) {
if (!fixtureCollectionName) {
throw new Error(NO_NAME_ERR_MSG);
}
if (truman.currentStatus() === RECORDING_STATE) {
truman.restore();
}
Expand Down Expand Up @@ -187,6 +200,10 @@ let truman = module.exports = {
},

clear(fixtureCollectionName, callback) {
if (!fixtureCollectionName) {
throw new Error(NO_NAME_ERR_MSG);
}

return storage.clear(fixtureCollectionName)
.then(() => {
loggingHelper.log('%cCLEARED%c: All local fixtures cleared.', 'color: green', 'color: black');
Expand Down