Skip to content

Commit

Permalink
Merge branch 'release/4.0.15'
Browse files Browse the repository at this point in the history
  • Loading branch information
thetutlage committed Aug 22, 2017
2 parents c9d0592 + 7c652a8 commit 08503da
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 1 deletion.
10 changes: 10 additions & 0 deletions CHANGELOG.md
@@ -1,3 +1,13 @@
<a name="4.0.15"></a>
## [4.0.15](https://github.com/adonisjs/adonis-lucid/compare/v4.0.14...v4.0.15) (2017-08-22)


### Features

* **validation:** add unique validation rule for validator ([74a9a3e](https://github.com/adonisjs/adonis-lucid/commit/74a9a3e))



<a name="4.0.14"></a>
## [4.0.14](https://github.com/adonisjs/adonis-lucid/compare/v4.0.13...v4.0.14) (2017-08-22)

Expand Down
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "@adonisjs/lucid",
"version": "4.0.14",
"version": "4.0.15",
"description": "SQL ORM built on top of Active Record pattern",
"main": "index.js",
"scripts": {
Expand Down
22 changes: 22 additions & 0 deletions providers/LucidProvider.js
Expand Up @@ -61,6 +61,26 @@ class LucidProvider extends ServiceProvider {
this.app.alias('Adonis/Traits/DatabaseTransactions', 'DatabaseTransactions')
}

/**
* Adds the unique rule to the validator
*
* @method _addUniqueRule
*
* @private
*/
_addUniqueRule () {
try {
const { extend } = this.app.use('Adonis/Addons/Validator')
const Database = this.app.use('Adonis/Src/Database')
const validatorRules = new (require('../src/Validator'))(Database)

/**
* Extend by adding the rule
*/
extend('unique', validatorRules.unique.bind(validatorRules), '{{field}} has already been taken by someone else')
} catch (error) {}
}

/**
* Register all the required providers
*
Expand All @@ -82,6 +102,8 @@ class LucidProvider extends ServiceProvider {
* @return {void}
*/
boot () {
this._addUniqueRule()

/**
* Setup ioc resolver for internally accessing fold
* methods.
Expand Down
90 changes: 90 additions & 0 deletions src/Validator/index.js
@@ -0,0 +1,90 @@
'use strict'

/*
* adonis-lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

/**
* This class exposes the validator rules
* related to database
*/
class ValidatorRules {
constructor (Database) {
this.Database = Database
}

/**
* Verify whether a field inside the database is unique
* or not.
*
* @method unique
*
* @param {Object} data
* @param {String} field
* @param {String} message
* @param {Array} args
* @param {Function} get
*
* @return {Promise}
*
* @example
* ```js
* email: 'unique:users' // define table
* email: 'unique:users,user_email' // define table + field
* email: 'unique:users,user_email,id:1' // where id !== 1
*
* // Via new rule method
* email: [rule('unique', ['users', 'user_email', 'id', 1])]
* ```
*/
unique (data, field, message, args, get) {
return new Promise((resolve, reject) => {
const value = get(data, field)

/**
* if value is not defined, then skip the validation
* since required rule should be added for required
* fields
*/
if (!value) {
return resolve('validation skipped')
}

/**
* Extracting values of the args array
*/
const [ table, fieldName, ignoreKey, ignoreValue ] = args

/**
* Base query to select where key=value
*/
const query = this.Database.table(table).where(fieldName || field, value)

/**
* If a ignore key and value is defined, then add a whereNot clause
*/
if (ignoreKey && ignoreValue) {
query.whereNot(ignoreKey, ignoreValue)
}

query
.then((rows) => {
/**
* Unique validation fails when a row has been found
*/
if (rows && rows.length) {
return reject(message)
}
resolve('validation passed')
})
.catch(reject)
})
}
}

module.exports = ValidatorRules
74 changes: 74 additions & 0 deletions test/unit/validation-rules.spec.js
@@ -0,0 +1,74 @@
'use strict'

/*
* adonis-lucid
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

const test = require('japa')
const fs = require('fs-extra')
const _ = require('lodash')
const path = require('path')
const Database = require('../../src/Database')
const Validator = require('../../src/Validator')
const helpers = require('./helpers')
const message = 'unique validation failed'

test.group('Validator | Unique', (group) => {
group.before(async () => {
await fs.ensureDir(path.join(__dirname, './tmp'))
this.database = new Database(helpers.getConfig())
await helpers.createTables(this.database)
})

group.beforeEach(async () => {
await this.database.truncate('users')
})

group.after(async () => {
await helpers.dropTables(this.database)
this.database.close()
try {
await fs.remove(path.join(__dirname, './tmp'))
} catch (error) {
if (process.platform !== 'win32' || error.code !== 'EBUSY') {
throw error
}
}
}).timeout(0)

test('pass validation when row is found', async (assert) => {
const validator = new Validator(this.database)
const result = await validator.unique({ email: 'foo@bar.com' }, 'email', message, ['users'], _.get)
assert.equal(result, 'validation passed')
})

test('skip validation when data does not have field', async (assert) => {
const validator = new Validator(this.database)
const result = await validator.unique({}, 'email', message, ['users'], _.get)
assert.equal(result, 'validation skipped')
})

test('throw exception when there is a row', async (assert) => {
assert.plan(1)
const validator = new Validator(this.database)
await this.database.table('users').insert({ username: 'foo' })
try {
await validator.unique({ username: 'foo' }, 'username', message, ['users'], _.get)
} catch (error) {
assert.equal(error, 'unique validation failed')
}
})

test('pass when whereNot key/value pairs are passed', async (assert) => {
const validator = new Validator(this.database)
await this.database.table('users').insert({ username: 'foo' })
const args = ['users', 'username', 'id', 1]
const result = await validator.unique({ username: 'foo' }, 'username', message, args, _.get)
assert.equal(result, 'validation passed')
})
})

0 comments on commit 08503da

Please sign in to comment.