streamsql
Version:
Streaming SQL ORM
385 lines (337 loc) • 9.9 kB
JavaScript
const test = require('tap').test
const useDb = require('./testdb')
test('table.get', function (t) {
useDb(t, ['user'], function (db, done) {
const user = makeUserTable(db)
user.row.fullname = function fullname() {
return this.first_name + ' ' + this.last_name
}
user.get({ last_name: 'Hannah' }, {
sort: 'first_name',
debug: true
}, function (err, row) {
t.notOk(err, 'no errors')
t.same(row[0].fullname(), 'Barry Hannah')
user.getOne({last_name: 'Hannah'}, function (err, row) {
t.notOk(err, 'no errors')
t.same(row.fullname(), 'Barry Hannah')
t.end()
})
})
})
})
test('table.get, pagination', function (t) {
useDb(t, ['user'], function (db, done) {
const user = makeUserTable(db)
const options = {
limit: 1,
page: 1,
includeTotal: true,
debug: true
};
const query = {
age: {
operation: ">",
value: 45,
}
}
user.get(query, function (err, rows) {
const expectedTotal = rows.length
const expectedFirstRow = rows[0]
user.get(query, options, function (err, data) {
t.same(expectedTotal, data.total, 'has correct total')
t.same(expectedFirstRow, data.rows[0], 'has correct first row')
t.same(data.rows.length, 1, 'has correct limit');
t.end();
})
})
})
})
test('table.get, ordering', function (t) {
useDb(t, ['user'], function (db, done) {
const user = makeUserTable(db)
user.get({}, {
sort: {age: 'desc'},
debug: true
}, function (err, rows) {
t.notOk(err, 'No error thrown')
t.ok(rows[0].age > rows[1].age, 'Sorted by age descending')
user.get({}, {order: {age: 'desc'}}, function (err, moreRows) {
t.deepEquals(rows, moreRows, '`sort` and `order` synonymous')
t.end()
})
})
})
})
test('table.get, complex where', function (t) {
useDb(t, ['user'], function (db, done) {
const user = makeUserTable(db)
user.get({
age: [
{ value: 40, op: '>=' },
{ value: 60, op: '<=' },
]
}, {
sort: 'age',
debug: true
}, function (err, rows) {
const expect = ['Link', 'Saunders']
const result = rows.map(value('last_name'))
t.same(result, expect, 'should have the right values')
t.end()
})
})
})
test('table.get, complex where', function (t) {
useDb(t, ['user'], function (db, done) {
const user = makeUserTable(db)
const sql = 'select last_name AS `last` from $table where first_name = ? OR first_name = ?'
user.get([sql, ['George', 'Kelly']], function (err, rows) {
console.dir(err)
const expect = ['Saunders', 'Link']
const result = rows.map(value('last'))
t.same(result, expect, 'should have the right values')
t.end()
})
})
})
test('table.get, relationships', function (t) {
useDb(t, ['user', 'book'], function (db, done) {
const user = makeUserTable(db)
const book = makeBookTable(db)
const review = makeReviewTable(db)
book.get({}, {
debug: true,
relationships: true
}, function (err, allBooks) {
t.notOk(err, 'no errors')
t.equal(allBooks.length, 17, 'all books accounted for')
book.get({ author_id: 1 }, {
debug: true,
relationships: true
}, function (err, someBooks) {
t.notOk(err, 'no errors')
t.ok(someBooks.length < allBooks.length, 'query returns subset of books')
t.equal(someBooks.length, 6, 'all requested books accounted for')
t.end()
})
})
})
})
test('table.get, relationships', function (t) {
useDb(t, ['user', 'book'], function (db, done) {
const user = makeUserTable(db)
const book = makeBookTable(db)
user.getOne({ id: 1 }, {
debug: true,
relationships: true
}, function (err, author) {
t.notOk(err, 'no errors')
t.equal(author.last_name, 'Saunders', 'We\'ve found Mr Saunders')
book.get({ author_id: 1 }, {
debug: true,
}, function (err, books) {
t.notOk(err, 'no errors')
t.equal(author.books.length, books.length, 'All of author\'s books found correctly')
t.end()
})
})
})
})
test('table.get, nested relationships', function (t) {
useDb(t, ['user', 'book', 'review'], function (db, done) {
const user = makeUserTable(db)
const book = makeBookTable(db)
const review = makeReviewTable(db)
review.getOne({ id: 1 }, {
debug: true,
relationships: true,
relationshipsDepth: -1
}, function (err, review) {
t.notOk(err, 'no errors')
t.same(review.test(), 'This is a review', 'review is model instance')
t.ok(review.book, 'review book returned')
t.same(review.book.test(), 'This is a book', 'book is model instance')
t.ok(review.book.author, 'review book author returned')
t.same(review.book.author.test(), 'This is a user', 'author is model instance')
t.ok(review.book.author.books, 'review book author publications returned')
t.same(review.book.author.books[0].test(), 'This is a book', 'review book author publications are model instances')
t.end()
})
})
})
test('table.get, many-to-many relationships', function (t) {
useDb(t, ['via'], function (db, done) {
const primary = makeViaPrimaryTable(db);
const secondary = makeViaSecondaryTable(db);
const via = makeViaThroughTable(db);
primary.get({}, {
debug: true,
relationships: true
}, function (err, rows) {
t.same(rows.length, 3)
t.same(rows[0].things.length, 3)
secondary.get({id: 2}, {
debug: true,
relationships: true
}, function (err, rows) {
t.same(rows.length, 1)
t.same(rows[0].things.length, 2)
t.end()
});
})
})
})
test('table.get, OR query', function (t) {
useDb(t, ['user'], function (db, done) {
const user = makeUserTable(db)
user.get([{age: {value: 65, operation: '>='}}, {first_name: 'George'}], {
debug: true
}, function (err, rows) {
t.notOk(err, 'No errors')
t.same(rows.length, 2)
t.same(rows[0].first_name, 'George')
t.same(rows[1].first_name, 'Barry')
t.end()
});
})
})
// https://github.com/brianloveswords/streamsql/issues/10
test('table.get, relationships should not hang when query returns empty set', function (t) {
useDb(t, ['user', 'book'], function (db, done) {
const user = makeUserTable(db)
const book = makeBookTable(db)
user.get({ id: 'whatever' }, {
debug: true,
relationships: true
}, function (err, authors) {
t.same(authors, [])
t.end()
})
})
})
// https://github.com/brianloveswords/streamsql/issues/5
test('table.getOne, should not hang on empty rows', function (t) {
useDb(t, ['empty'], function (db, done) {
const empty = db.table('empty', ['space'])
empty.getOne({ id: 1 }, {
debug: true,
}, function (err, row) {
console.dir(row)
t.end()
})
})
})
// https://github.com/brianloveswords/streamsql/issues/8
test('table.get, better raw sql handling', function (t) {
useDb(t, ['empty'], function (db, done) {
const empty = db.table('empty', ['space'])
empty.getOne('select 1 as `lol`', {
debug: true,
}, function (err, row) {
t.same(row, {lol: 1})
t.end()
})
})
})
test('table.get, better error messaging', function (t) {
useDb(t, ['empty'], function (db, done) {
const empty = db.table('empty', ['space'])
empty.getOne({id: undefined}, {
debug: true,
}, function (err, row) {
t.same(err.name, 'RangeError')
t.end()
})
})
})
function value(name) { return function (obj) { return obj[name] } }
function makeUserTable(db) {
return db.table('user', {
fields: ['first_name', 'last_name', 'age'],
methods: {
test: function testUserMethods () {
return 'This is a user'
}
},
relationships: {
books: {
type: 'hasMany',
local: 'id',
foreign: { table: 'book', key: 'author_id' },
optional: true,
}
},
})
}
function makeBookTable(db) {
return db.table('book', {
fields: [ 'id', 'author_id', 'title', 'release_date' ],
methods: {
test: function testBookMethods () {
return 'This is a book'
}
},
relationships: {
author: {
type: 'hasOne',
local: 'author_id',
foreign: { table: 'user', key: 'id' },
},
reviews: {
type: 'hasMany',
local: 'id',
foreign: { table: 'review', key: 'book_id' },
optional: true,
},
},
})
}
function makeReviewTable(db) {
return db.table('review', {
fields: ['id', 'book_id', 'link'],
methods: {
test: function testReviewMethods () {
return 'This is a review'
}
},
relationships: {
book: {
type: 'hasOne',
local: 'book_id',
foreign: { table: 'book', key: 'id' },
}
}
})
}
function makeViaPrimaryTable(db) {
return db.table('viaPrimary', {
fields: ['id', 'label'],
relationships: {
things: {
type: 'hasMany',
local: 'id',
foreign: { table: 'viaSecondary', key: 'id' },
via: { table: 'viaThrough', local: 'primary_id', foreign: 'secondary_id' }
}
}
})
}
function makeViaSecondaryTable(db) {
return db.table('viaSecondary', {
fields: ['id', 'label'],
relationships: {
things: {
type: 'hasMany',
local: 'id',
foreign: { table: 'viaPrimary', key: 'id' },
via: { table: 'viaThrough', local: 'secondary_id', foreign: 'primary_id' }
}
}
})
}
function makeViaThroughTable(db) {
return db.table('viaThrough', {
fields: ['primary_id', 'secondary_id']
})
}