Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

nothinkdb

Package Overview
Dependencies
Maintainers
1
Versions
55
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nothinkdb - npm Package Compare versions

Comparing version 0.0.1 to 0.1.0

.mailmap

4

package.json
{
"name": "nothinkdb",
"version": "0.0.1",
"version": "0.1.0",
"description": "ORM: Object-Rethinkdb-Mapping",

@@ -21,3 +21,3 @@ "main": "lib/nothinkdb.js",

],
"author": "ironhee",
"author": "ironhee <leechulhee95@gmail.com>",
"license": "MIT",

@@ -24,0 +24,0 @@ "bugs": {

@@ -9,17 +9,17 @@ import { expect } from 'chai';

describe('constructor', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
const fooTable = new Table({
table: 'foo',
schema: () => ({
foo: Joi.string(),
bar: Joi.string(),
});
}
}),
});
it('should create link', () => {
const link = new Link({
linker: { Table: Foo, key: 'foo' },
linkee: { Table: Foo, key: 'bar' },
left: { table: fooTable, field: 'foo' },
right: { table: fooTable, field: 'bar' },
});
expect(link.linker).to.deep.equal({ Table: Foo, key: 'foo' });
expect(link.linkee).to.deep.equal({ Table: Foo, key: 'bar' });
expect(link.left).to.deep.equal({ table: fooTable, field: 'foo' });
expect(link.right).to.deep.equal({ table: fooTable, field: 'bar' });
});

@@ -30,20 +30,20 @@

expect(() => new Link({
linker: {},
linkee: {},
left: {},
right: {},
})).to.throw(Error);
expect(() => new Link({
linker: { Table: {}, key: null },
linkee: { Table: {}, key: null },
left: { table: {}, field: null },
right: { table: {}, field: null },
})).to.throw(Error);
expect(() => new Link({
linker: { Table: Foo, key: null },
linkee: { Table: Foo, key: null },
left: { table: fooTable, field: null },
right: { table: fooTable, field: null },
})).to.throw(Error);
expect(() => new Link({
linker: { Table: Foo, key: 'noop' },
linkee: { Table: Foo, key: 'noop' },
left: { table: fooTable, field: 'noop' },
right: { table: fooTable, field: 'noop' },
})).to.throw(Error);
expect(() => new Link({
linker: { Table: Foo, key: 'foo' },
linkee: { Table: Foo, key: 'noop' },
left: { table: fooTable, field: 'foo' },
right: { table: fooTable, field: 'noop' },
})).to.throw(Error);

@@ -50,0 +50,0 @@ });

@@ -0,302 +1,688 @@

import r from 'rethinkdb';
import Joi from 'joi';
import uuid from 'node-uuid';
import { expect } from 'chai';
import uuid from 'node-uuid';
import Joi from 'joi';
import Table from '../Table';
import Link from '../Link';
import { hasOne, belongsTo, hasMany, belongsToMany } from '../relations';
describe('Table', () => {
describe('constructor', () => {
it('should throw Error if \'table\' is not overrided', () => {
expect(() => new Table()).to.throw(Error);
});
let connection;
before(async () => {
connection = await r.connect({});
await r.branch(r.dbList().contains('test').not(), r.dbCreate('test'), null).run(connection);
r.dbCreate('test');
});
it('should not throw Error if \'table\' is overrided', () => {
class Foo extends Table {
static table = 'foo';
}
expect(() => new Foo()).to.not.throw(Error);
});
beforeEach(async () => {
await r.branch(r.tableList().contains('foo').not(), r.tableCreate('foo'), null).run(connection);
await r.branch(r.tableList().contains('bar').not(), r.tableCreate('bar'), null).run(connection);
await r.branch(r.tableList().contains('foobar').not(), r.tableCreate('foobar'), null).run(connection);
});
describe('static', () => {
after(async () => {
await connection.close();
});
describe('staic', () => {
describe('schema', () => {
it('has default property', () => {
class Base extends Table {
static table = 'base';
static schema = () => ({
...Table.schema(),
name: Joi.string().default('hello'),
});
}
expect(Base.schema()).to.have.property('id');
expect(Base.schema()).to.have.property('createdAt');
expect(Base.schema()).to.have.property('updatedAt');
expect(Base.schema()).to.have.property('name');
expect(Table.schema).to.have.property('id');
expect(Table.schema).to.have.property('createdAt');
expect(Table.schema).to.have.property('updatedAt');
});
});
});
it('could be extended', () => {
class Base extends Table {
static table = 'base';
static schema = () => ({
...Table.schema(),
name: Joi.string().default('hello'),
});
}
expect(Base.schema()).to.have.property('id');
expect(Base.schema()).to.have.property('createdAt');
expect(Base.schema()).to.have.property('updatedAt');
expect(Base.schema()).to.have.property('name');
describe('constructor', () => {
it('schema could be extended', () => {
const baseTable = new Table({
table: 'base',
schema: () => ({
...Table.schema,
name: Joi.string().default('hello'),
}),
});
expect(baseTable.schema()).to.have.property('id');
expect(baseTable.schema()).to.have.property('createdAt');
expect(baseTable.schema()).to.have.property('updatedAt');
expect(baseTable.schema()).to.have.property('name');
});
});
describe('validate', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
name: Joi.string().required(),
});
}
describe('validate', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
name: Joi.string().required(),
}),
});
it('should return true when data is valid', () => {
expect(Foo.validate({ name: 'foo' })).to.be.true;
it('should return true when data is valid', () => {
expect(fooTable.validate({ name: 'foo' })).to.be.true;
});
it('should throw error when invalid', () => {
expect(fooTable.validate({})).to.be.false;
});
});
describe('attempt', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
foo: Joi.string().default('foo'),
bar: Joi.string().required(),
}),
});
it('should return with default properties', () => {
const result = fooTable.attempt({ bar: 'bar' });
expect(result).to.have.property('foo', 'foo');
expect(result).to.have.property('bar', 'bar');
});
it('should throw error when invalid', () => {
expect(() => fooTable.attempt({})).to.throw(Error);
});
});
describe('create', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
foo: Joi.string().default('foo'),
bar: Joi.string().required(),
}),
});
it('should return with default properties', () => {
const result = fooTable.create({ bar: 'bar' });
expect(result).to.have.property('foo', 'foo');
expect(result).to.have.property('bar', 'bar');
});
it('should throw error when invalid', () => {
expect(() => fooTable.create({})).to.throw(Error);
});
});
describe('hasField', () => {
it('should return true when specified fieldName is given', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
name: Joi.string(),
}),
});
expect(fooTable.hasField('name')).to.be.true;
});
it('should throw error when invalid', () => {
expect(Foo.validate({})).to.be.false;
it('should return false when unspecified fieldName is given', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({}),
});
expect(fooTable.hasField('name')).to.be.false;
});
});
describe('attempt', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
foo: Joi.string().default('foo'),
bar: Joi.string().required(),
});
}
describe('assertField', () => {
it('should not throw error when specified fieldName is given', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
name: Joi.string(),
}),
});
expect(() => fooTable.assertField('name')).to.not.throw(Error);
});
it('should update default properties', () => {
const result = Foo.attempt({ bar: 'bar' });
expect(result).to.have.property('foo', 'foo');
expect(result).to.have.property('bar', 'bar');
it('should throw error when unspecified fieldName is given', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({}),
});
expect(() => fooTable.assertField('name')).to.throw(Error);
});
});
it('should throw error when invalid', () => {
expect(() => Foo.attempt({})).to.throw(Error);
describe('getField', () => {
it('should return field schema when specified fieldName is given', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
name: Joi.string(),
}),
});
const field = fooTable.getField('name');
expect(field).to.be.ok;
expect(() => Joi.assert('string', field)).to.not.throw(Error);
});
describe('hasColumn', () => {
it('should return true when specified columnName is given', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
name: Joi.string(),
});
}
expect(Foo.hasColumn('name')).to.be.true;
it('should throw error when unspecified fieldName is given', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({}),
});
expect(() => fooTable.getField('name')).to.throw(Error);
});
});
it('should return false when unspecified columnName is given', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({});
}
expect(Foo.hasColumn('name')).to.be.false;
describe('getForeignKey', () => {
it('should return primary key schema when any argument is not given', () => {
const fooTable = new Table({
table: 'foo',
pk: 'name',
schema: () => ({
name: Joi.string().default(() => uuid.v4(), 'pk'),
}),
});
const field = fooTable.getForeignKey();
expect(field).to.be.ok;
expect(() => Joi.assert('string', field)).to.not.throw(Error);
});
describe('assertColumn', () => {
it('should not throw error when specified columnName is given', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
name: Joi.string(),
});
}
expect(() => Foo.assertColumn('name')).to.not.throw(Error);
it('should return field schema when options.fieldName is given', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
name: Joi.string().default(() => uuid.v4(), 'pk'),
}),
});
it('should throw error when unspecified columnName is given', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({});
}
expect(() => Foo.assertColumn('name')).to.throw(Error);
const field = fooTable.getForeignKey({ fieldName: 'name' });
expect(field).to.be.ok;
expect(() => Joi.assert('string', field)).to.not.throw(Error);
});
it('should return and default(null) schema when options.isManyToMany is not given', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
}),
});
const field = fooTable.getForeignKey();
expect(field).to.be.ok;
expect(Joi.attempt(undefined, field)).to.be.null;
});
describe('getColumn', () => {
it('should return column schema when specified columnName is given', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
name: Joi.string(),
});
}
it('should return required() field schema when options.isManyToMany is given', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
}),
});
const column = Foo.getColumn('name');
expect(column).to.be.ok;
expect(() => Joi.assert('string', column)).to.not.throw(Error);
const field = fooTable.getForeignKey({ isManyToMany: true });
expect(field).to.be.ok;
expect(() => Joi.assert(undefined, field)).to.throw(Error);
});
});
describe('linkTo', () => {
it('should return link', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
barId: barTable.getForeignKey(),
}),
});
const barTable = new Table({
table: 'bar',
schema: () => ({
...Table.schema,
}),
});
it('should throw error when unspecified columnName is given', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({});
}
expect(() => Foo.getColumn('name')).to.throw(Error);
const foo2bar = fooTable.linkTo(barTable, 'barId');
expect(foo2bar).to.be.ok;
expect(foo2bar.constructor).to.equal(Link);
expect(foo2bar.left).to.deep.equal({
table: fooTable, field: 'barId',
});
expect(foo2bar.right).to.deep.equal({
table: barTable, field: 'id',
});
});
});
describe('getForeignKey', () => {
it('should return primary key schema when any argument is not given', () => {
class Foo extends Table {
static table = 'foo';
static pk = 'name';
static schema = () => ({
name: Joi.string().default(() => uuid.v4(), 'pk'),
});
}
describe('linkedBy', () => {
it('should return reverse link', () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
}),
});
const barTable = new Table({
table: 'bar',
schema: () => ({
...Table.schema,
fooId: fooTable.getForeignKey(),
}),
});
const column = Foo.getForeignKey();
expect(column).to.be.ok;
expect(() => Joi.assert('string', column)).to.not.throw(Error);
const foo2bar = fooTable.linkedBy(barTable, 'fooId');
expect(foo2bar).to.be.ok;
expect(foo2bar.constructor).to.equal(Link);
expect(foo2bar.left).to.deep.equal({
table: barTable, field: 'fooId',
});
expect(foo2bar.right).to.deep.equal({
table: fooTable, field: 'id',
});
});
});
it('should return column schema when options.columnName is given', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
name: Joi.string().default(() => uuid.v4(), 'pk'),
});
}
describe('query', () => {
it('should return table query', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
}),
});
const config = await fooTable.query().config().run(connection);
expect(config).to.have.property('name', 'foo');
});
});
const column = Foo.getForeignKey({ columnName: 'name' });
expect(column).to.be.ok;
expect(() => Joi.assert('string', column)).to.not.throw(Error);
describe('insert', () => {
it('should insert data into database', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
name: Joi.string().required(),
}),
});
const foo = fooTable.attempt({ name: 'foo' });
await fooTable.insert(foo).run(connection);
const fetchedfooTable = await fooTable.query().get(foo.id).run(connection);
expect(foo).to.deep.equal(fetchedfooTable);
});
});
it('should return default(null) schema when options.isManyToMany is not given', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
...Table.schema(),
});
}
describe('get', () => {
it('should get data from database', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
name: Joi.string().required(),
}),
});
const foo = fooTable.attempt({ name: 'foo' });
await fooTable.insert(foo).run(connection);
const fetchedfooTable = await fooTable.get(foo.id).run(connection);
expect(foo).to.deep.equal(fetchedfooTable);
});
});
const column = Foo.getForeignKey();
expect(Joi.attempt(undefined, column)).to.be.null;
describe('update', () => {
it('should update data into database', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
name: Joi.string().required(),
}),
});
const foo = fooTable.attempt({ name: 'foo' });
await fooTable.insert(foo).run(connection);
await fooTable.update(foo.id, { name: 'bar' }).run(connection);
const fetchedfooTable = await fooTable.get(foo.id).run(connection);
expect(fetchedfooTable).to.have.property('name', 'bar');
});
});
it('should return required() column schema when options.isManyToMany is given', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
...Table.schema(),
});
}
describe('delete', () => {
it('should delete data from database', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
name: Joi.string().required(),
}),
});
const foo = fooTable.attempt({ name: 'foo' });
await fooTable.insert(foo).run(connection);
await fooTable.delete(foo.id).run(connection);
const fetchedfooTable = await fooTable.query().get(foo.id).run(connection);
expect(fetchedfooTable).to.be.null;
});
});
const column = Foo.getForeignKey({ isManyToMany: true });
expect(column).to.be.ok;
expect(() => Joi.assert(undefined, column)).to.throw(Error);
describe('withJoin', () => {
it('should query hasOne relation', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
}),
relations: () => ({
bar: hasOne(fooTable.linkedBy(barTable, 'fooId')),
}),
});
const barTable = new Table({
table: 'bar',
schema: () => ({
...Table.schema,
fooId: fooTable.getForeignKey(),
}),
});
await fooTable.sync(connection);
await barTable.sync(connection);
const foo = fooTable.create({});
const bar = barTable.create({ fooId: foo.id });
await fooTable.insert(foo).run(connection);
await barTable.insert(bar).run(connection);
let query = fooTable.get(foo.id);
query = await fooTable.withJoin(query, { bar: true });
const fetchedfooTable = await query.run(connection);
expect(bar).to.deep.equal(fetchedfooTable.bar);
});
describe('linkTo', () => {
it('should return link', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
...Table.schema(),
barId: Bar.getForeignKey(),
});
}
class Bar extends Table {
static table = 'bar';
static schema = () => ({
...Table.schema(),
});
}
const foo2bar = Foo.linkTo(Bar, 'barId');
expect(foo2bar).to.be.ok;
expect(foo2bar.constructor).to.equal(Link);
expect(foo2bar.linker).to.deep.equal({
Table: Foo, key: 'barId',
});
expect(foo2bar.linkee).to.deep.equal({
Table: Bar, key: 'id',
});
it('should query belongsTo relation', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
barId: barTable.getForeignKey(),
}),
relations: () => ({
bar: belongsTo(fooTable.linkTo(barTable, 'barId')),
}),
});
const barTable = new Table({
table: 'bar',
schema: () => ({
...Table.schema,
}),
});
await fooTable.sync(connection);
await barTable.sync(connection);
const bar = barTable.create({});
const foo = fooTable.create({ barId: bar.id });
await fooTable.insert(foo).run(connection);
await barTable.insert(bar).run(connection);
let query = fooTable.get(foo.id);
query = fooTable.withJoin(query, { bar: true });
const fetchedfooTable = await query.run(connection);
expect(bar).to.deep.equal(fetchedfooTable.bar);
});
describe('linkedBy', () => {
it('should return reverse link', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
...Table.schema(),
});
}
class Bar extends Table {
static table = 'bar';
static schema = () => ({
...Table.schema(),
fooId: Foo.getForeignKey(),
});
}
const foo2bar = Foo.linkedBy(Bar, 'fooId');
expect(foo2bar).to.be.ok;
expect(foo2bar.constructor).to.equal(Link);
expect(foo2bar.linker).to.deep.equal({
Table: Bar, key: 'fooId',
});
expect(foo2bar.linkee).to.deep.equal({
Table: Foo, key: 'id',
});
it('should query hasMany relation', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
}),
relations: () => ({
bars: hasMany(fooTable.linkedBy(barTable, 'fooId')),
}),
});
const barTable = new Table({
table: 'bar',
schema: () => ({
...Table.schema,
fooId: fooTable.getForeignKey(),
}),
});
await fooTable.sync(connection);
await barTable.sync(connection);
const foo = fooTable.create({});
const bar = barTable.create({ fooId: foo.id });
await fooTable.insert(foo).run(connection);
await barTable.insert(bar).run(connection);
let query = fooTable.get(foo.id);
query = fooTable.withJoin(query, { bars: true });
const fetchedfooTable = await query.run(connection);
expect(fetchedfooTable.bars).to.have.length(1);
expect(bar).to.deep.equal(fetchedfooTable.bars[0]);
});
it('should query belongsToMany relation', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
}),
relations: () => ({
bars: belongsToMany([fooTable.linkedBy(foobarTable, 'fooId'), foobarTable.linkTo(barTable, 'barId')]),
}),
});
const barTable = new Table({
table: 'bar',
schema: () => ({
...Table.schema,
}),
relations: () => ({
foos: belongsToMany([barTable.linkedBy(foobarTable, 'barId'), foobarTable.linkTo(fooTable, 'fooId')]),
}),
});
const foobarTable = new Table({
table: 'foobar',
schema: () => ({
...Table.schema,
fooId: fooTable.getForeignKey({ isManyToMany: true }),
barId: barTable.getForeignKey({ isManyToMany: true }),
}),
});
await fooTable.sync(connection);
await barTable.sync(connection);
await foobarTable.sync(connection);
const foo = fooTable.create({});
const bar = barTable.create({});
const foobar = foobarTable.create({ fooId: foo.id, barId: bar.id });
await fooTable.insert(foo).run(connection);
await barTable.insert(bar).run(connection);
await foobarTable.insert(foobar).run(connection);
let query = fooTable.get(foo.id);
query = fooTable.withJoin(query, { bars: true });
const fetchedfooTable = await query.run(connection);
expect(fetchedfooTable.bars).to.have.length(1);
expect(bar).to.deep.equal(fetchedfooTable.bars[0]);
query = barTable.get(bar.id);
query = barTable.withJoin(query, { foos: true });
const fetchedbarTable = await query.run(connection);
expect(fetchedbarTable.foos).to.have.length(1);
expect(foo).to.deep.equal(fetchedbarTable.foos[0]);
});
});
describe('isValid', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
name: Joi.string().required(),
describe('createRelation', () => {
it('should add hasMany relation', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
}),
relations: () => ({
bars: hasMany(fooTable.linkedBy(barTable, 'fooId')),
}),
});
}
const barTable = new Table({
table: 'bar',
schema: () => ({
...Table.schema,
fooId: fooTable.getForeignKey(),
}),
});
await fooTable.sync(connection);
await barTable.sync(connection);
it('should return true when data is valid', () => {
const foo = new Foo({ name: 'foo' });
expect(foo.isValid()).to.be.true;
const foo = fooTable.create({});
const bar = barTable.create({});
await fooTable.insert(foo).run(connection);
await barTable.insert(bar).run(connection);
await fooTable.createRelation('bars', foo.id, bar.id).run(connection);
let fooQuery = fooTable.get(foo.id);
fooQuery = fooTable.withJoin(fooQuery, { bars: true });
const fetchedfooTable = await fooQuery.run(connection);
expect(fetchedfooTable.bars).to.have.length(1);
expect(fetchedfooTable.bars[0]).to.have.property('fooId', foo.id);
});
it('should throw error when invalid', () => {
const foo = new Foo({});
expect(foo.isValid()).to.be.false;
it('should add belongsToMany relation', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
}),
relations: () => ({
bars: belongsToMany([fooTable.linkedBy(foobarTable, 'fooId'), foobarTable.linkTo(barTable, 'barId')]),
}),
});
const barTable = new Table({
table: 'bar',
schema: () => ({
...Table.schema,
}),
relations: () => ({
foos: belongsToMany([barTable.linkedBy(foobarTable, 'barId'), foobarTable.linkTo(fooTable, 'fooId')]),
}),
});
const foobarTable = new Table({
table: 'foobar',
schema: () => ({
...Table.schema,
fooId: fooTable.getForeignKey({ isManyToMany: true }),
barId: barTable.getForeignKey({ isManyToMany: true }),
}),
});
await fooTable.sync(connection);
await barTable.sync(connection);
await foobarTable.sync(connection);
const foo = fooTable.create({});
const bar = barTable.create({});
await fooTable.insert(foo).run(connection);
await barTable.insert(bar).run(connection);
await fooTable.createRelation('bars', foo.id, bar.id).run(connection);
const fooQuery = fooTable.get(foo.id);
const fetchedfooTable = await fooTable.withJoin(fooQuery, { bars: true }).run(connection);
expect(bar.id).to.equal(fetchedfooTable.bars[0].id);
const barQuery = barTable.get(bar.id);
const fetchedbarTable = await barTable.withJoin(barQuery, { foos: true }).run(connection);
expect(foo.id).to.equal(fetchedbarTable.foos[0].id);
});
});
describe('attempt', () => {
class Foo extends Table {
static table = 'foo';
static schema = () => ({
foo: Joi.string().default('foo'),
bar: Joi.string().required(),
describe('removeRelation', () => {
it('should remove hasMany relation', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
}),
relations: () => ({
bars: hasMany(fooTable.linkedBy(barTable, 'fooId')),
}),
});
}
const barTable = new Table({
table: 'bar',
schema: () => ({
...Table.schema,
fooId: fooTable.getForeignKey(),
}),
});
await fooTable.sync(connection);
await barTable.sync(connection);
it('should update default properties', () => {
const foo = new Foo({ bar: 'bar' });
foo.attempt();
expect(foo.data).to.have.property('foo', 'foo');
expect(foo.data).to.have.property('bar', 'bar');
const foo = fooTable.create({});
const bar1 = barTable.create({});
const bar2 = barTable.create({});
await fooTable.insert(foo).run(connection);
await barTable.insert(bar1).run(connection);
await barTable.insert(bar2).run(connection);
await fooTable.createRelation('bars', foo.id, bar1.id).run(connection);
await fooTable.createRelation('bars', foo.id, bar2.id).run(connection);
await fooTable.removeRelation('bars', foo.id, bar1.id).run(connection);
let fooQuery = fooTable.get(foo.id);
fooQuery = fooTable.withJoin(fooQuery, { bars: true });
const fetchedfooTable = await fooQuery.run(connection);
expect(fetchedfooTable.bars).to.have.length(1);
expect(bar2.id).to.equal(fetchedfooTable.bars[0].id);
});
it('should throw error when invalid', () => {
const foo = new Foo({});
expect(() => foo.attempt()).to.throw(Error);
it('should remove belongsToMany relation', async () => {
const fooTable = new Table({
table: 'foo',
schema: () => ({
...Table.schema,
}),
relations: () => ({
bars: belongsToMany([fooTable.linkedBy(foobarTable, 'fooId'), foobarTable.linkTo(barTable, 'barId')]),
}),
});
const barTable = new Table({
table: 'bar',
schema: () => ({
...Table.schema,
}),
relations: () => ({
foos: belongsToMany([barTable.linkedBy(foobarTable, 'barId'), foobarTable.linkTo(fooTable, 'fooId')]),
}),
});
const foobarTable = new Table({
table: 'foobar',
schema: () => ({
...Table.schema,
fooId: fooTable.getForeignKey({ isManyToMany: true }),
barId: barTable.getForeignKey({ isManyToMany: true }),
}),
});
await fooTable.sync(connection);
await barTable.sync(connection);
await foobarTable.sync(connection);
const foo = fooTable.create({});
const bar1 = barTable.create({});
const bar2 = barTable.create({});
await fooTable.insert(foo).run(connection);
await barTable.insert(bar1).run(connection);
await barTable.insert(bar2).run(connection);
await fooTable.createRelation('bars', foo.id, bar1.id).run(connection);
await fooTable.createRelation('bars', foo.id, bar2.id).run(connection);
await fooTable.removeRelation('bars', foo.id, bar1.id).run(connection);
const fooQuery = fooTable.get(foo.id);
const fetchedfooTable = await fooTable.withJoin(fooQuery, { bars: true }).run(connection);
expect(fetchedfooTable.bars).to.have.length(1);
expect(bar2.id).to.equal(fetchedfooTable.bars[0].id);
const barQuery = barTable.get(bar2.id);
const fetchedbarTable = await barTable.withJoin(barQuery, { foos: true }).run(connection);
expect(fetchedbarTable.foos).to.have.length(1);
expect(foo.id).to.equal(fetchedbarTable.foos[0].id);
});
});
});

@@ -7,18 +7,28 @@ import assert from 'assert';

return linkData &&
linkData.Table &&
linkData.key &&
linkData.Table.hasColumn(linkData.key);
linkData.table &&
linkData.field &&
linkData.table.hasField(linkData.field);
}
static assertLinkData(linkData) {
assert.ok(this.validateLinkData(linkData));
assert.ok(this.validateLinkData(linkData), 'invalid link data');
}
async sync(connection) {
await this.syncTable(connection, this.right);
await this.syncTable(connection, this.left);
}
async syncTable(connection, { table, field }) {
await table.ensureTable(connection);
await table.ensureIndex(connection, field);
}
constructor(options = {}) {
const { linker, linkee } = options;
Link.assertLinkData(linker);
Link.assertLinkData(linkee);
this.linker = linker;
this.linkee = linkee;
const { left, right } = options;
Link.assertLinkData(left);
Link.assertLinkData(right);
this.left = left;
this.right = right;
}
}

@@ -1,11 +0,2 @@

import Model from './Model';
import Link from './Link';
import Table from './Table';
const nothinkdb = {
Model,
Link,
Table,
};
export default nothinkdb;
export Table from './Table';
export * from './relations';

@@ -0,1 +1,3 @@

/* eslint no-shadow: 0, no-param-reassign: 0 */
import r from 'rethinkdb';
import Joi from 'joi';

@@ -9,67 +11,167 @@ import _ from 'lodash';

export default class Table {
static table = null;
static pk = 'id';
static schema = () => ({
id: Joi.string().max(32).default(() => uuid.v4(), 'primary key').meta({ index: true }),
static schema = {
id: Joi.string().max(36).default(() => uuid.v4(), 'primary key').meta({ index: true }),
createdAt: Joi.date().default(() => new Date(), 'time of creation'),
updatedAt: Joi.date().default(() => new Date(), 'time of updated'),
});
};
static validate(data = null) {
constructor(options = {}) {
const { table, pk, schema, relations } = Joi.attempt(options, {
table: Joi.string().required(),
pk: Joi.string().default(Table.pk),
schema: Joi.func().required(),
relations: Joi.func().default(() => () => ({}), 'relation'),
});
// assert.equal(_.has(schema(), pk), true, `'${pk}' is not specified in schema`);
this.table = table;
this.pk = pk;
this.schema = schema;
this.relations = relations;
}
validate(data = null) {
return !Joi.validate(data, this.schema()).error;
}
static attempt(data = null) {
attempt(data = null) {
return Joi.attempt(data, this.schema());
}
static hasColumn(columnName) {
return _.has(this.schema(), columnName);
create(data = null) {
return this.attempt(data);
}
static assertColumn(columnName) {
return assert.ok(this.hasColumn(columnName), `Column '${columnName}' is unspecified in table '${this.table}'.`);
hasField(fieldName) {
return _.has(this.schema(), fieldName);
}
static getColumn(columnName) {
this.assertColumn(columnName);
return this.schema()[columnName];
assertField(fieldName) {
return assert.ok(this.hasField(fieldName), `Field '${fieldName}' is unspecified in table '${this.table}'.`);
}
static getForeignKey(options = {}) {
const { columnName = this.pk, isManyToMany = false } = options;
const column = this.getColumn(columnName);
getField(fieldName) {
this.assertField(fieldName);
return this.schema()[fieldName];
}
getForeignKey(options = {}) {
const { fieldName = this.pk, isManyToMany = false } = options;
const field = this.getField(fieldName);
if (isManyToMany) {
return column.required();
return field.required();
}
return column.default(null);
return field.allow(null).default(null);
}
static linkTo(OtherTable, foreignKey, targetKey = OtherTable.pk) {
linkTo(rightTable, leftField, options = {}) {
const { index = rightTable.pk } = options;
return new Link({
linker: { Table: this, key: foreignKey },
linkee: { Table: OtherTable, key: targetKey },
left: { table: this, field: leftField },
right: { table: rightTable, field: index },
});
}
static linkedBy(OtherTable, foreignKey, targetKey = OtherTable.pk) {
return OtherTable.linkTo(this, foreignKey, targetKey);
linkedBy(leftTable, leftField, options) {
return leftTable.linkTo(this, leftField, options);
}
constructor(data = {}) {
assert.ok(this.constructor.table, 'Table should have static property \'table\'.');
assert.ok(this.constructor.pk, 'Table should have static property \'pk\'.');
assert.ok(_.isObject(data), 'data should be object type.');
this.data = data;
async sync(connection) {
await this.ensureTable(connection);
await this.syncRelations(connection);
}
isValid() {
return this.constructor.validate(this.data);
async ensureTable(connection) {
await r.branch(
r.tableList().contains(this.table).not(),
r.tableCreate(this.table),
null
).run(connection);
}
attempt() {
this.data = this.constructor.attempt(this.data);
async ensureIndex(connection, field) {
if (this.pk === field) return;
await r.branch(
this.query().indexList().contains(field).not(),
this.query().indexCreate(field),
null
).run(connection);
await this.query().indexWait(field).run(connection);
}
async syncRelations(connection) {
await _.reduce(this.relations(), (promise, relation) => {
return promise.then(() => relation.sync(connection));
}, Promise.resolve());
}
query() {
assert.ok(this.table, 'Table should have property \'table\'.');
return r.table(this.table);
}
insert(data) {
return this.query().insert(this.attempt(data));
}
get(pk) {
return this.query().get(pk);
}
update(pk, data) {
return this.query().get(pk).update(data);
}
delete(pk) {
return this.query().get(pk).delete();
}
getRelation(relation) {
const relationObj = this.relations()[relation];
assert.ok(relationObj, `Relation '${this.table}.${relation}' is not exist.`);
return relationObj;
}
_withJoinOne(query, key, options) {
const relation = this.getRelation(key);
return relation.join(key, query, options);
}
withJoin(query, relations) {
return _.reduce(relations, (query, value, key) => {
let options = {};
if (_.isObject(value)) {
options = _.chain(value)
.omitBy((value, key) => !_.startsWith(key, '_'))
.reduce((memo, value, key) => {
return { [key.slice(1)]: value };
}, {})
.value();
}
query = this._withJoinOne(query, key, options);
if (_.isObject(value)) {
const relations = _.omitBy(value, (value, key) => _.startsWith(key, '_'));
const { targetTable } = this.getRelation(key);
query = query.merge(function(row) {
return { [key]: targetTable.withJoin(row(key), relations) };
});
}
return query;
}, query);
}
createRelation(as, onePk, otherPk) {
const relation = this.getRelation(as);
assert.ok(relation.create, 'unsupported relation.');
return relation.create(onePk, otherPk);
}
removeRelation(as, onePk, otherPk) {
const relation = this.getRelation(as);
assert.ok(relation.remove, 'unsupported relation.');
return relation.remove(onePk, otherPk);
}
}

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc