Skip to content

Commit

Permalink
#268: Standardise Storage constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
groenroos committed Oct 23, 2021
1 parent 7eb01fa commit a19b798
Show file tree
Hide file tree
Showing 16 changed files with 142 additions and 243 deletions.
15 changes: 4 additions & 11 deletions core/loadModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import Storage from '../lib/Storage.js';
*/
export default async function loadModel(next) {
const modelPath = path.join(this.dir, this.config.modelsDir);
const structure = {};
const schema = {};
let files = {};

/* Load all models in the model directory */
Expand All @@ -41,7 +41,7 @@ export default async function loadModel(next) {

const model = fs.readFileSync(path.join(modelPath, file));

/* Read the model JSON into the structure */
/* Read the model JSON into the schema */
try {
/* Attempt to parse the JSON */
const parsedModel = JSON.parse(model.toString());
Expand All @@ -63,21 +63,14 @@ export default async function loadModel(next) {
}

/* Save */
structure[table] = parsedModel;
schema[table] = parsedModel;
} catch {
throw new SaplingError(`Error parsing model \`${table}\``);
}
}

this.structure = structure;

/* Create a storage instance based on the models */
this.storage = new Storage(this, {
name: this.name,
schema: this.structure,
config: this.config,
dir: this.dir,
});
this.storage = new Storage(this, schema);

if (next) {
next();
Expand Down
20 changes: 8 additions & 12 deletions lib/Storage.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,12 @@ export default class Storage {
* Initialise the Storage class
*
* @param {object} App The App instance
* @param {object} opts Initialisation options
* @param {object} schema Data structure
*/
constructor(App, options) {
constructor(App, schema) {
/* Load the options into the class */
this.app = App;
this.options = options;
this.name = options.name;
this.schema = options.schema;
this.config = options.config;
this.dir = options.dir;
this.schema = schema || {};

/* Every app with storage needs a users collection */
if ('users' in this.schema) {
Expand All @@ -98,7 +94,7 @@ export default class Storage {
async importDriver() {
if (this.db === null) {
/* Connect to the database backend with the desired driver */
const driver = String(this.config.db.driver).toLowerCase();
const driver = String(this.app.config.db.driver).toLowerCase();

if (driver === 'memory') {
/* eslint-disable-next-line new-cap */
Expand Down Expand Up @@ -128,9 +124,9 @@ export default class Storage {
async createDatabase() {
await this.importDriver();

const dbConfig = this.config.db;
dbConfig.name = this.name;
dbConfig.dataLimit = this.config.dataLimit;
const dbConfig = this.app.config.db;
dbConfig.name = this.app.name || 'app';
dbConfig.dataLimit = this.app.config.dataLimit;

await this.db.connect(dbConfig);

Expand Down Expand Up @@ -232,7 +228,7 @@ export default class Storage {
this.app.user.isUserAuthenticatedForRoute(request, response);

/* Parse max limit */
const limit = (this.config.limit && this.config.limit > 0) ? this.config.limit : false;
const limit = (this.app.config.limit && this.app.config.limit > 0) ? this.app.config.limit : false;

/* Parse limit options */
if ('limit' in request.query) {
Expand Down
6 changes: 5 additions & 1 deletion test/_utils/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export default () => {
render: {
driver: 'html'
},
db: {
driver: 'Memory'
},
hooksDir: 'hooks/',
viewsDir: 'views/',
extension: 'html'
Expand All @@ -26,7 +29,8 @@ export default () => {
get: [],
post: []
},
hooks: {}
hooks: {},
schema: {}
};

app.utils = new Utils(app);
Expand Down
13 changes: 2 additions & 11 deletions test/core/loadCustomTags.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import test from 'ava';
import _ from 'underscore';
import path from 'path';
import { fileURLToPath } from 'url';

import Request from '../../lib/Request.js';
import Storage from '../../lib/Storage.js';
Expand All @@ -10,9 +8,6 @@ import User from '../../lib/User.js';
import loadCustomTags from '../../core/loadCustomTags.js';


const __dirname = path.dirname(fileURLToPath(import.meta.url));


test.beforeEach(async t => {
t.context.app = (await import('../_utils/app.js')).default();

Expand All @@ -25,12 +20,8 @@ test.beforeEach(async t => {
t.context.app.user = new User(t.context.app);
t.context.app.request = new Request(t.context.app);

t.context.app.storage = new Storage(t.context.app, {
name: 'test',
schema: {},
config: { db: { driver: 'Memory' } },
dir: __dirname
});
t.context.app.name = 'test';
t.context.app.storage = new Storage(t.context.app);
await t.context.app.storage.importDriver();
});

Expand Down
72 changes: 36 additions & 36 deletions test/core/loadModel.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ test('loads string based model definition', async t => {
await loadModel.call(t.context.app);
});

t.true('posts' in t.context.app.structure);
t.true('title' in t.context.app.structure.posts);
t.true('viewCount' in t.context.app.structure.posts);
t.true(_.isObject(t.context.app.structure.posts.title));
t.true(_.isObject(t.context.app.structure.posts.viewCount));
t.is(t.context.app.structure.posts.title.type, 'string');
t.is(t.context.app.structure.posts.viewCount.type, 'number');
t.true('posts' in t.context.app.storage.schema);
t.true('title' in t.context.app.storage.schema.posts);
t.true('viewCount' in t.context.app.storage.schema.posts);
t.true(_.isObject(t.context.app.storage.schema.posts.title));
t.true(_.isObject(t.context.app.storage.schema.posts.viewCount));
t.is(t.context.app.storage.schema.posts.title.type, 'string');
t.is(t.context.app.storage.schema.posts.viewCount.type, 'number');
});

test('loads object based model definition', async t => {
Expand All @@ -42,16 +42,16 @@ test('loads object based model definition', async t => {
await loadModel.call(t.context.app);
});

t.true('posts' in t.context.app.structure);
t.true('title' in t.context.app.structure.posts);
t.true('viewCount' in t.context.app.structure.posts);
t.true(_.isObject(t.context.app.structure.posts.title));
t.true(_.isObject(t.context.app.structure.posts.viewCount));
t.is(t.context.app.structure.posts.title.type, 'string');
t.is(t.context.app.structure.posts.title.required, true);
t.is(t.context.app.structure.posts.title.maxlen, 140);
t.is(t.context.app.structure.posts.viewCount.type, 'number');
t.is(t.context.app.structure.posts.viewCount.default, 0);
t.true('posts' in t.context.app.storage.schema);
t.true('title' in t.context.app.storage.schema.posts);
t.true('viewCount' in t.context.app.storage.schema.posts);
t.true(_.isObject(t.context.app.storage.schema.posts.title));
t.true(_.isObject(t.context.app.storage.schema.posts.viewCount));
t.is(t.context.app.storage.schema.posts.title.type, 'string');
t.is(t.context.app.storage.schema.posts.title.required, true);
t.is(t.context.app.storage.schema.posts.title.maxlen, 140);
t.is(t.context.app.storage.schema.posts.viewCount.type, 'number');
t.is(t.context.app.storage.schema.posts.viewCount.default, 0);
});

test('normalises access object', async t => {
Expand All @@ -61,23 +61,23 @@ test('normalises access object', async t => {
await loadModel.call(t.context.app);
});

t.true('posts' in t.context.app.structure);
t.true('title' in t.context.app.structure.posts);
t.true('viewCount' in t.context.app.structure.posts);
t.true('content' in t.context.app.structure.posts);
t.true('access' in t.context.app.structure.posts.title);
t.true('access' in t.context.app.structure.posts.viewCount);
t.true('access' in t.context.app.structure.posts.content);
t.true(_.isObject(t.context.app.structure.posts.title.access));
t.true(_.isObject(t.context.app.structure.posts.viewCount.access));
t.true(_.isObject(t.context.app.structure.posts.content.access));

t.is(t.context.app.structure.posts.title.access.r, 'anyone');
t.is(t.context.app.structure.posts.title.access.w, 'owner');
t.is(t.context.app.structure.posts.viewCount.access.r, 'anyone');
t.is(t.context.app.structure.posts.viewCount.access.w, 'anyone');
t.is(t.context.app.structure.posts.content.access.r, 'anyone');
t.is(t.context.app.structure.posts.content.access.w, 'anyone');
t.true('posts' in t.context.app.storage.schema);
t.true('title' in t.context.app.storage.schema.posts);
t.true('viewCount' in t.context.app.storage.schema.posts);
t.true('content' in t.context.app.storage.schema.posts);
t.true('access' in t.context.app.storage.schema.posts.title);
t.true('access' in t.context.app.storage.schema.posts.viewCount);
t.true('access' in t.context.app.storage.schema.posts.content);
t.true(_.isObject(t.context.app.storage.schema.posts.title.access));
t.true(_.isObject(t.context.app.storage.schema.posts.viewCount.access));
t.true(_.isObject(t.context.app.storage.schema.posts.content.access));

t.is(t.context.app.storage.schema.posts.title.access.r, 'anyone');
t.is(t.context.app.storage.schema.posts.title.access.w, 'owner');
t.is(t.context.app.storage.schema.posts.viewCount.access.r, 'anyone');
t.is(t.context.app.storage.schema.posts.viewCount.access.w, 'anyone');
t.is(t.context.app.storage.schema.posts.content.access.r, 'anyone');
t.is(t.context.app.storage.schema.posts.content.access.w, 'anyone');
});

test('throws an error for a mangled model definition', async t => {
Expand All @@ -99,8 +99,8 @@ test('does not load dot files', async t => {
await loadModel.call(t.context.app);
});

t.is(Object.keys(t.context.app.structure).length, 1);
t.false('dotfile' in t.context.app.structure);
t.is(Object.keys(t.context.app.storage.schema).length, 1);
t.false('dotfile' in t.context.app.storage.schema);
});

test('warns about a non-existant model path', async t => {
Expand Down
8 changes: 2 additions & 6 deletions test/core/loadPermissions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,8 @@ test.beforeEach(async t => {
t.context.app.user = new User(t.context.app);
t.context.app.request = new Request(t.context.app);

t.context.app.storage = new Storage(t.context.app, {
name: 'test',
schema: {},
config: { db: { driver: 'Memory' } },
dir: __dirname
});
t.context.app.name = 'test';
t.context.app.storage = new Storage(t.context.app);
await t.context.app.storage.importDriver();

t.context.request = (await import('../_utils/request.js')).default();
Expand Down
13 changes: 2 additions & 11 deletions test/core/loadRest.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import express from 'express';
import session from 'express-session';
import bodyParser from 'body-parser';
import request from 'supertest';
import path from 'path';
import { fileURLToPath } from 'url';

import Request from '../../lib/Request.js';
import Storage from '../../lib/Storage.js';
Expand All @@ -15,9 +13,6 @@ import runHook from '../../core/runHook.js';
import loadRest from '../../core/loadRest.js';


const __dirname = path.dirname(fileURLToPath(import.meta.url));


test.beforeEach(async t => {
t.context.app = _.extend({
name: 'test'
Expand All @@ -31,12 +26,8 @@ test.beforeEach(async t => {
t.context.app.user = new User(t.context.app);
t.context.app.request = new Request(t.context.app);

t.context.app.storage = new Storage(t.context.app, {
name: 'test',
schema: { posts: { title: { type: 'string' } } },
config: { db: { driver: 'Memory' } },
dir: __dirname
});
t.context.app.name = 'test';
t.context.app.storage = new Storage(t.context.app, { posts: { title: { type: 'string' } } });
await t.context.app.storage.importDriver();

t.context.app.runHook = runHook;
Expand Down
8 changes: 2 additions & 6 deletions test/hooks/model/retrieve.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ import Storage from '../../../lib/Storage.js';
import retrieve from '../../../hooks/sapling/model/retrieve.js';


const __dirname = path.dirname(fileURLToPath(import.meta.url));


test.beforeEach(async t => {
t.context.app = _.defaults({
storage: new Storage({}, {
storage: new Storage({
name: 'test',
schema: {},
config: { db: { driver: 'Memory' } },
dir: __dirname
config: { db: { driver: 'Memory' } }
})
}, (await import('../../_utils/app.js')).default());
await t.context.app.storage.importDriver();
Expand Down
13 changes: 2 additions & 11 deletions test/hooks/user/forgot.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import test from 'ava';
import _ from 'underscore';
import path from 'path';
import { fileURLToPath } from 'url';

import Request from '../../../lib/Request.js';
import Response from '../../../lib/Response.js';
Expand All @@ -12,9 +10,6 @@ import User from '../../../lib/User.js';
import forgot from '../../../hooks/sapling/user/forgot.js';


const __dirname = path.dirname(fileURLToPath(import.meta.url));


test.beforeEach(async t => {
t.context.app = _.extend({
name: 'untitled'
Expand All @@ -23,12 +18,8 @@ test.beforeEach(async t => {
t.context.app.user = new User(t.context.app);
t.context.app.request = new Request(t.context.app);

t.context.app.storage = new Storage(t.context.app, {
name: 'test',
schema: {},
config: { db: { driver: 'Memory' } },
dir: __dirname
});
t.context.app.name = 'test';
t.context.app.storage = new Storage(t.context.app);
await t.context.app.storage.importDriver();

t.context.request = (await import('../../_utils/request.js')).default();
Expand Down
13 changes: 2 additions & 11 deletions test/hooks/user/logged.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import test from 'ava';
import _ from 'underscore';
import path from 'path';
import { fileURLToPath } from 'url';

import Request from '../../../lib/Request.js';
import Response from '../../../lib/Response.js';
Expand All @@ -11,21 +9,14 @@ import User from '../../../lib/User.js';
import logged from '../../../hooks/sapling/user/logged.js';


const __dirname = path.dirname(fileURLToPath(import.meta.url));


test.beforeEach(async t => {
t.context.app = (await import('../../_utils/app.js')).default();

t.context.app.user = new User(t.context.app);
t.context.app.request = new Request(t.context.app);

t.context.app.storage = new Storage(t.context.app, {
name: 'test',
schema: {},
config: { db: { driver: 'Memory' } },
dir: __dirname
});
t.context.app.name = 'test';
t.context.app.storage = new Storage(t.context.app);
await t.context.app.storage.importDriver();

t.context.request = (await import('../../_utils/request.js')).default();
Expand Down
Loading

0 comments on commit a19b798

Please sign in to comment.