Skip to content

Commit

Permalink
feat(sql.js): add connection pool for managing sq.js backend
Browse files Browse the repository at this point in the history
Use `generic-pool` to handle the `sql.js` connection in the same way `knex` internally handles its driver connections.
  • Loading branch information
citycide committed Jan 8, 2017
1 parent b1f4cd9 commit 2df8381
Show file tree
Hide file tree
Showing 18 changed files with 275 additions and 289 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"dependencies": {
"component-type": "^1.2.1",
"fs-jetpack": "^0.10.5",
"generic-pool": "^3.1.6",
"knex": "^0.12.6",
"osom": "^2.1.2",
"sql.js": "^0.4.0"
Expand Down
33 changes: 18 additions & 15 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,21 +87,24 @@ export function runQuery (instance, query, needResponse) {
return query.then(res => res ? res.length : 0)
}

let response

if (needResponse) {
response = parseResponse(instance.db.exec(query.toString()))
if (query._sequence && query._sequence[0].method === 'hasTable') {
response = !!response.length
return instance.pool.acquire().then(db => {
let response

if (needResponse) {
response = parseResponse(db.exec(query.toString()))
if (query._sequence && query._sequence[0].method === 'hasTable') {
response = !!response.length
}
} else {
db.run(query.toString())

if (util.isOneOf(['insert', 'update', 'delete'], query._method)) {
response = db.getRowsModified()
}
}
} else {
instance.db.run(query.toString())

if (util.isOneOf(['insert', 'update', 'delete'], query._method)) {
response = instance.db.getRowsModified()
}
}

writeDatabase(instance)
return Promise.resolve(response)
writeDatabase(instance, db)
instance.pool.release(db)
return response
})
}
6 changes: 3 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { resolve } from 'path'

import Model from './model'
import * as types from './types'
import { readDatabase } from './sqljs-handler'
import { connect } from './sqljs-handler'
import { runQuery } from './helpers'
import { setup } from './enforcers'
import { invariant } from './util'
Expand All @@ -25,7 +25,7 @@ class Trilogy {
this.knex = knex({ ...config, connection: this.options.connection })
} else {
this.knex = knex(config)
readDatabase(this, this.options.connection.filename)
this.pool = connect(this)
}

this.definitions = new Map()
Expand Down Expand Up @@ -87,7 +87,7 @@ class Trilogy {
if (this.isNative) {
return this.knex.destroy()
} else {
return this.db.close()
return this.pool.drain()
}
}

Expand Down
44 changes: 25 additions & 19 deletions src/sqljs-handler.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,40 @@
import jetpack from 'fs-jetpack'
import pool from 'generic-pool'
import SQL from 'sql.js'

import constants from './constants'

export function readDatabase (instance) {
let client

let atPath = instance.options.connection.filename
if (jetpack.exists(atPath) === 'file') {
let file = jetpack.read(atPath, 'buffer')
instance.db = new SQL.Database(file)
client = new SQL.Database(file)
} else {
instance.db = new SQL.Database()
writeDatabase(instance)
client = new SQL.Database()
writeDatabase(instance, client)
}

return client
}

export function writeDatabase (instance) {
if (!instance.db) {
throw new Error(constants.ERR_NO_DATABASE)
}
export function writeDatabase (instance, db) {
let data = db.export()
let buffer = new Buffer(data)

try {
let data = instance.db.export()
let buffer = new Buffer(data)
jetpack.file(instance.options.connection.filename, {
content: buffer, mode: '777'
})
}

let atPath = instance.options.connection.filename
export function connect (instance) {
return pool.createPool({
create () {
return Promise.resolve(readDatabase(instance))
},

jetpack.file(atPath, {
content: buffer, mode: '777'
})
} catch (e) {
throw new Error(e.message)
}
destroy (client) {
client.close()
return Promise.resolve()
}
}, { min: 1, max: 1 })
}
45 changes: 45 additions & 0 deletions tests/create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Trilogy from '../dist/trilogy'

import test from 'ava'
import { remove } from 'fs-jetpack'
import { join, basename } from 'path'

const filePath = join(__dirname, `${basename(__filename, '.js')}.db`)
const db = new Trilogy(filePath)

const schema = {
first: String,
second: Number
}

const tables = [
{ name: 'one', schema },
{ name: 'two', schema },
{ name: 'three', schema }
]

test.before(() => {
return Promise.all(tables.map(table => {
return db.model(table.name, table.schema)
}))
})

test.after.always('remove test database file', () => {
return db.close().then(() => remove(filePath))
})

test('inserts objects into the database', async t => {
let inserts = [
{ table: 'one', object: { first: 'hello', second: 1 } },
{ table: 'two', object: { first: 'hello', second: 2 } },
{ table: 'three', object: { first: 'hello', second: 3 } }
]

await Promise.all(
inserts.map(({ table, object }) => db.create(table, object))
)

inserts.forEach(async ({ table, object }) => {
t.deepEqual(await db.find(table, object), [object])
})
})
36 changes: 36 additions & 0 deletions tests/drop-model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Trilogy from '../dist/trilogy'

import test from 'ava'
import { remove } from 'fs-jetpack'
import { join, basename } from 'path'

const filePath = join(__dirname, `${basename(__filename, '.js')}.db`)
const db = new Trilogy(filePath)

const schema = { name: String }

const tables = [
{ name: 'one', schema },
{ name: 'two', schema },
{ name: 'three', schema }
]

test.before(() => {
return Promise.all(tables.map(table => {
db.model(table.name, table.schema)
}))
})

test.after.always('remove test database file', () => {
return db.close().then(() => remove(filePath))
})

test('removes tables from the database', async t => {
let removals = await Promise.all(
tables.map(({ name }) => {
return db.dropModel(name).then(() => db.hasModel(name))
})
)

removals.forEach(v => t.false(v))
})
31 changes: 0 additions & 31 deletions tests/drop-table.js

This file was deleted.

35 changes: 35 additions & 0 deletions tests/find-one.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import Trilogy from '../dist/trilogy'

import test from 'ava'
import { remove } from 'fs-jetpack'
import { join, basename } from 'path'

const filePath = join(__dirname, `${basename(__filename, '.js')}.db`)
const db = new Trilogy(filePath)

test.before(async () => {
await db.model('first', {
first: String,
second: String
})

await db.create('first', {
first: 'fee',
second: 'blah'
})
})

test.after.always('remove test database file', () => {
return db.close().then(() => remove(filePath))
})

test('retrieves a single object', async t => {
let expected = { first: 'fee', second: 'blah' }
let res = await db.findOne('first')
t.deepEqual(res, expected)
})

test('allows retrieving a specific property', async t => {
let res = await db.findOne('first.second')
t.deepEqual(res, 'blah')
})
19 changes: 12 additions & 7 deletions tests/select.js → tests/find.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,22 @@ const db = new Trilogy(filePath)
const arr = ['fee', 'fi', 'fo', 'fum']

test.before(async () => {
await db.createTable('select', ['first', 'second'])
arr.forEach(async v => await db.insert('select', {
first: v,
second: 'blah'
}))
await db.model('select', {
first: String,
second: String
})

await Promise.all(
arr.map(v => db.create('select', { first: v, second: 'blah' }))
)
})

test.after.always('remove test database file', () => remove(filePath))
test.after.always('remove test database file', () => {
return db.close().then(() => remove(filePath))
})

test('retrieves rows as arrays of objects', async t => {
let res = await db.select('select')
let res = await db.find('select')

t.true(Array.isArray(res))
res.forEach((obj, i) => t.is(obj.first, arr[i]))
Expand Down
24 changes: 0 additions & 24 deletions tests/first.js

This file was deleted.

30 changes: 0 additions & 30 deletions tests/get-value.js

This file was deleted.

Loading

0 comments on commit 2df8381

Please sign in to comment.