Skip to content
This repository was archived by the owner on Sep 22, 2020. It is now read-only.
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
15 changes: 15 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ node_js:
- "7"
- "8"
sudo: false

before_script:
- mysql -e "CREATE USER grind_test;" -u root
- mysql -e "GRANT ALL PRIVILEGES ON *.* TO grind_test;" -u root
- mysql -e "CREATE DATABASE grind_orm_test;" -u root
- psql -c "CREATE USER grind_test SUPERUSER;" -U postgres
- psql -c "CREATE DATABASE grind_orm_test;" -U postgres

script:
- "npm run lint"
- "npm test"

services:
- mysql
- postgresql

addons:
postgresql: '9.5'
16 changes: 16 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,22 @@ Grind ORM provides an integrated ORM for [Grind](https://github.com/grindjs/fram

Full documentation for Grind ORM is available on the [Grind website](https://grind.rocks/docs/guides/orm).

## Testing MySQL and PostgreSQL
Install [MySQL](https://dev.mysql.com/downloads/mysql/) and [PostgreSQL](https://www.postgresql.org/download/). Then, create users and databases:

MySQL:
```bash
> "CREATE USER grind_test;"
> "GRANT ALL PRIVILEGES ON `grind_orm_test`.* TO 'grind_test'@'%';"
> "CREATE DATABASE grind_orm_test;"
```

PostgreSQL:
```bash
> "CREATE USER grind_test SUPERUSER;"
> "CREATE DATABASE grind_orm_test;"
```

## License

Grind was created by [Shaun Harrison](https://github.com/shnhrrsn) and is made available under the [MIT license](LICENSE).
2 changes: 1 addition & 1 deletion bin/ava
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ if [ "$NODE_VERSION" == "7" ]; then
FLAGS="--harmony-async-await"
fi

NODE_ENV=test node $FLAGS node_modules/.bin/ava "$@"
NODE_ENV=test node $FLAGS node_modules/.bin/ava "$@" --serial
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
"grind-cli": "^0.7.0",
"grind-db": "^0.7.0",
"grind-framework": "^0.7.1",
"mysql": "^2.15.0",
"pg": "^7.3.0",
"sqlite": "^2.8.0"
},
"engines": {
Expand Down
1 change: 1 addition & 0 deletions src/MakeModelCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import './Inflect'
import path from 'path'

export class MakeModelCommand extends Command {

name = 'make:model'
description = 'Create a model class'

Expand Down
2 changes: 2 additions & 0 deletions src/Model.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable max-lines */
import { Model as ObjectionModel } from 'objection'

import './Inflect'
Expand All @@ -8,6 +9,7 @@ import './RelationValidator'
const as = require('as-type')

export class Model extends ObjectionModel {

static descriptiveName = null
static eager = null
static eagerFilters = null
Expand Down
1 change: 1 addition & 0 deletions src/QueryBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { QueryBuilder as ObjectionQueryBuilder } from 'objection'
import './ModelNotFoundError'

export class QueryBuilder extends ObjectionQueryBuilder {

static registeredFilters = { }

_cyclicalEagerProtection = [ ]
Expand Down
1 change: 1 addition & 0 deletions src/RelationSynchronizer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export class RelationSynchronizer {

model = null
modelClass = null
relation = null
Expand Down
2 changes: 1 addition & 1 deletion test/QueryBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ test('orFail', async t => {
}

try {
await t.context.UserModel.query().where('id', Date.now()).orFail()
await t.context.UserModel.query().where('id', Math.round(Date.now() / 10000)).orFail()
t.fail('Should have thrown an error')
} catch(err) {
if(err instanceof ModelNotFoundError) {
Expand Down
2 changes: 1 addition & 1 deletion test/RelationValidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { transaction } from 'objection'
test('validate missing', async t => {
try {
await t.context.UserAvatarModel.query().insert({
user_id: Date.now(),
user_id: Math.round(Date.now() / 10000),
url: 'test'
})

Expand Down
18 changes: 18 additions & 0 deletions test/fixtures/config/database.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,24 @@
"driver": "sqlite3",
"filename": "./database.sqlite",
"useNullAsDefault": true
},

"mysql": {
"driver": "mysql",
"host": "127.0.0.1",
"user": "grind_test",
"database": "grind_orm_test",
"charset": "utf8",
"pool": {
"min": 1,
"max": 1
}
},

"pg": {
"driver": "pg",
"host": "127.0.0.1",
"database": "grind_orm_test"
}

}
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/database/migrations/01-create_users_table.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export function up(db) {
return db.schema.createTable('users', table => {
table.integer('id').unsigned().primary()
table.increments('id').unsigned().primary()
table.string('name', 128).notNullable().index()
table.timestamps()
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export function up(db) {
return db.schema.createTable('user_avatars', table => {
table.integer('id').unsigned().primary()
table.increments('id').unsigned().primary()
table.integer('user_id').unsigned().nullable().index().references('id').inTable('users').onDelete('CASCADE')
table.string('url', 128).notNullable().index()
table.timestamps()
Expand Down
37 changes: 37 additions & 0 deletions test/helpers/Databases/BaseDatabase.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export class BaseDatabase {

static seedTables = [ 'users', 'user_avatars' ]

static ready(app) {
app.config.set('database.default', this.dbName)
}

static async runMigration(app) {
await app.db.migrate.latest()
await app.db.seed.run()

// Reset autoincrementing, which can break when primary keys are set explicitly in seed files
return app.db.transaction(trx => {
return Promise.all(this.seedTables.map(async table => {
try {
let maxId = await trx.max('id as max').from(table)
maxId = maxId[0].max || 10

return this.resequence(trx, table, maxId)
} catch(err) {
throw new Error(err)
}
}))
})
}

static async resequence(/* db */) {
throw new Error('Subclass must implement')
}

static shutdown(/* app */) {
throw new Error('Subclass must implement')
}


}
29 changes: 29 additions & 0 deletions test/helpers/Databases/Mysql.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import './BaseDatabase'

export class Mysql extends BaseDatabase {

static dbName = 'mysql'

static runMigration(app) {
return app.db.migrate.currentVersion().then(version => {
if(version === 'none') {
return super.runMigration(app)
}

return app.db.migrate.rollback().then(() => super.runMigration(app))
})
}

static resequence(trx, table, maxId) {
return trx.raw(`ALTER TABLE ${table} AUTO_INCREMENT = ${maxId + 1}`)
}

static async shutdown(app) {
try {
await app.db.destroy()
} catch(err) {
Log.error('Unable to destroy test db', err)
}
}

}
29 changes: 29 additions & 0 deletions test/helpers/Databases/Postgres.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import './BaseDatabase'

export class Postgres extends BaseDatabase {

static dbName = 'pg'

static runMigration(app) {
return app.db.migrate.currentVersion().then(version => {
if(version === 'none') {
return super.runMigration(app)
}

return app.db.migrate.rollback().then(() => super.runMigration(app))
})
}

static resequence(trx, table, maxId) {
return trx.raw(`ALTER SEQUENCE "${table}_id_seq" RESTART WITH ${maxId + 1}`)
}

static async shutdown(app) {
try {
await app.db.destroy()
} catch(err) {
Log.error('Unable to destroy test db', err)
}
}

}
30 changes: 30 additions & 0 deletions test/helpers/Databases/Sqlite3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import './BaseDatabase'

const path = require('path')
const crypto = require('crypto')
const fs = require('fs')

export class Sqlite3 extends BaseDatabase {

static dbName = 'sqlite'
static dbPath = path.join(__dirname, `../../fixtures/database/database-${crypto.randomBytes(4).toString('hex')}.sqlite`)

static ready(app) {
super.ready(app)
app.config.set('database.connections.sqlite.filename', this.dbPath)
}

static resequence(trx, table, maxId) {
return trx.raw(`UPDATE sqlite_sequence SET seq = ${maxId} WHERE name = '${table}'`)
}

static shutdown(/* app */) {
try {
// eslint-disable-next-line no-sync
fs.unlinkSync(this.dbPath)
} catch(err) {
Log.error('Unable to remove test db', err)
}
}

}
9 changes: 9 additions & 0 deletions test/helpers/Databases/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import './Postgres'
import './Sqlite3'
import './Mysql'

export const Databases = {
[Postgres.dbName]: Postgres,
[Sqlite3.dbName]: Sqlite3,
[Mysql.dbName]: Mysql
}
4 changes: 3 additions & 1 deletion test/helpers/Models/UserAvatarModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@ import { Model } from '../../../src'
import './UserModel'

export class UserAvatarModel extends Model {

static tableName = 'user_avatars'
static eager = '[user]'

static jsonSchema = {
type: 'object',

properties: {
id: { type: 'number' },
id: { type: 'integer' },
user_id: { type: 'integer', relation: 'user' },
url: { type: 'string', maxLength: 128 },
created_at: { type: 'string', format: 'date-time' },
Expand All @@ -22,4 +23,5 @@ export class UserAvatarModel extends Model {
user: this.belongsTo(UserModel)
}
}

}
1 change: 1 addition & 0 deletions test/helpers/Models/UserModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Model } from '../../../src'
import './UserAvatarModel'

export class UserModel extends Model {

static tableName = 'users'

static buildRelations() {
Expand Down
24 changes: 6 additions & 18 deletions test/helpers/makeApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,22 @@ require('babel-polyfill')
import './Grind'
import { DatabaseProvider } from 'grind-db'
import { OrmProvider } from '../../src'
import { Databases } from './Databases'

const path = require('path')
const crypto = require('crypto')
const fs = require('fs')

export async function makeApp(boot = () => { }) {
export async function makeApp(dbName, boot = () => { }) {
const app = new Grind
const dbPath = path.join(__dirname, `../fixtures/database/database-${crypto.randomBytes(4).toString('hex')}.sqlite`)

app.config.set('database.connections.sqlite.filename', dbPath)
const db = Databases[dbName]
await db.ready(app)

app.providers.add(DatabaseProvider)
app.providers.add(OrmProvider)

await app.boot()
await boot()

await app.db.migrate.latest()
await app.db.seed.run()

app.on('shutdown', () => {
try {
// eslint-disable-next-line no-sync
fs.unlinkSync(dbPath)
} catch(err) {
Log.error('Unable to remove test db', err)
}
})
await db.runMigration(app)
app.on('shutdown', async () => db.shutdown(app))

return app
}
11 changes: 8 additions & 3 deletions test/helpers/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import '../helpers/Models/UserModel'
import '../helpers/Models/UserAvatarModel'

test.beforeEach(async t => {
t.context.app = await makeApp()

t.context.app = await makeApp(t.title.match(/\*(sqlite|mysql|pg)\*/)[1])
UserModel.app(t.context.app)
UserModel.knex(t.context.app.db)
t.context.UserModel = UserModel
Expand All @@ -17,6 +16,12 @@ test.beforeEach(async t => {

test.afterEach.always(t => t.context.app.shutdown())

export function testDBs(name, cb, dbs = [ 'sqlite', 'mysql', 'pg' ]) {
for(const db of dbs) {
test.serial(`*${db}*: ${name}`, cb)
}
}

module.exports = {
test: test.serial
test: testDBs
}