-
-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: addt'l createTable forms, coercion config, modularize, cjs export
Add two new forms to createTable, in addition to the existing Array form: Object syntax & Function syntax. Function syntax allows passing the same function as you might use with knex itself for greater control over table schema. Introduce a coercion option to allow control over how trilogy handles boolean values on insert / update / retrieval. Create `helpers` and move almost all previous static methdos into it - these are functions like `parseResponse` and such that shouldn't necessarily be exposed. Drop `lodash.foreach` in favor of functions written in `util.js`. Drop `is-plain-obj` in favor of a function written in `util.js`. Replace `native-or-lie` with `bluebird`. Remove all flowtypes from the code. Remove all inline JSDoc comments. These will be replaced by external documentation. Centralize default values into `constants` like `where` and `columns` to avoid creating new Objects or Arrays all the time. Use `let` instead of `const` for most variables, for 2 main reasons: 1) stylistic and 2) const is kind of a flimsy shield. Use `module.exports` commonjs syntax rather than `export default` ES2015 syntax to allow commonjs users to `require` trilogy without using `.default`. BREAKING CHANGE: Any commonjs users `require`ing trilogy no longer need `.default` due to using commonjs export instead of Babel's `export default` fill.
- Loading branch information
citycide
committed
Dec 17, 2016
1 parent
5de888b
commit d3bab02
Showing
5 changed files
with
444 additions
and
858 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,12 @@ | ||
export default { | ||
ERR_UNKNOWN: | ||
`an unknown error occurred. Check the stacktrace or report an | ||
issue if there is a problem with trilogy itself.`, | ||
'an unknown error occurred. Check the stacktrace or report an ' + | ||
'issue if there is a problem with trilogy itself.', | ||
ERR_COL_MISSING: | ||
`column name is required. Pass it as an independent argument | ||
or as dot-notation along with the table argument.`, | ||
ERR_NO_DATABASE: `Could not write - no database initialized.` | ||
'column name is required. Pass it as an independent argument ' + | ||
'or as dot-notation along with the table argument.', | ||
ERR_NO_DATABASE: 'could not write - no database initialized.', | ||
|
||
DEFAULT_WHERE: {}, | ||
DEFAULT_COLUMNS: ['*'] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
import { map, each, isBoolean, isFunction, isObject, isString } from './util' | ||
|
||
export let coercion = { active: true } | ||
|
||
export function parseResponse (contents) { | ||
if (contents.length) { | ||
let columns = contents[0].columns | ||
let values = contents[0].values | ||
let results = [] | ||
for (let i = 0; i < values.length; i++) { | ||
let line = {} | ||
for (let j = 0; j < columns.length; j++) { | ||
line[columns[j]] = coercion.active | ||
? stringToBoolean(values[i][j]) | ||
: values[i][j] | ||
} | ||
results.push(line) | ||
} | ||
return results | ||
} else { | ||
return [] | ||
} | ||
} | ||
|
||
// parse a dot or bracket notated string into table, column, & row | ||
// the row value isn't actually used currently | ||
export function parseTablePath (table, column, row) { | ||
if (table.includes('.')) { | ||
let [top, inner, nested] = table.split('.') | ||
return parseTablePath(top, inner, nested) | ||
} else if (table.includes('[')) { | ||
let opener = table.indexOf('[') | ||
let closer = table.indexOf(']', opener) | ||
|
||
let top = table.substr(0, opener) | ||
let inner = table.slice(opener + 1, closer) | ||
|
||
let rowIndex = top.length + inner.length + 2 | ||
|
||
let extra, nested | ||
if (rowIndex < table.length) { | ||
extra = table.slice(rowIndex + 1) | ||
let rowCloser = extra.indexOf(']') | ||
nested = extra.substr(0, rowCloser) | ||
} | ||
|
||
return parseTablePath(top, inner, nested) | ||
} else { | ||
return [table, column, row] | ||
} | ||
} | ||
|
||
export function sanitizeOrder (order, partial) { | ||
if (Array.isArray(order) && order.length === 2) { | ||
return partial.orderBy(...order) | ||
} else if (isString(order)) { | ||
return partial.orderBy(order) | ||
} else { | ||
return partial | ||
} | ||
} | ||
|
||
export function sanitizeWhere (where, partial) { | ||
if (Array.isArray(where)) { | ||
let arr = coercion.active | ||
? where.map(booleanToString) : where | ||
return partial.where(...arr) | ||
} else if (isFunction(where)) { | ||
return partial.where(where.bind(partial)) | ||
} else { | ||
// it's an object | ||
return partial.where(map(where, v => { | ||
return coercion.active ? booleanToString(v) : v | ||
})) | ||
} | ||
} | ||
|
||
export function getConflictString (conflict) { | ||
switch (conflict.toLowerCase()) { | ||
case 'fail': return ' or fail ' | ||
case 'abort': return ' or abort ' | ||
case 'ignore': return ' or ignore ' | ||
case 'replace': return ' or replace ' | ||
case 'rollback': return ' or rollback ' | ||
default: return ' ' | ||
} | ||
} | ||
|
||
export function sanitizeColumns (columns) { | ||
if (Array.isArray(columns)) return columns | ||
if (isString(columns)) return [columns] | ||
return ['*'] | ||
} | ||
|
||
export function isValidWhere (where) { | ||
if (isObject(where)) return true | ||
|
||
if (Array.isArray(where)) { | ||
let len = where.length | ||
return len === 2 || len === 3 | ||
} | ||
|
||
return false | ||
} | ||
|
||
export function processColumn (table, column) { | ||
if (!column.name) { | ||
throw new Error('column name required') | ||
} | ||
|
||
let { name, type = 'text' } = column | ||
|
||
if (column.unique === 'inline') { | ||
// bypass knex's usual unique method | ||
column['__TYPE__'] = `${type} unique` | ||
type = 'specificType' | ||
delete column.unique | ||
} | ||
|
||
let partial = table[type](name, column['__TYPE__']) | ||
|
||
mapColumnProperties(partial, column) | ||
} | ||
|
||
export function processArraySchema (table, columns) { | ||
each(columns, column => { | ||
if (isString(column)) { | ||
table.text(column) | ||
return | ||
} | ||
|
||
if (isObject(column)) { | ||
processColumn(table, column) | ||
} | ||
}) | ||
} | ||
|
||
export function processObjectSchema (table, columns) { | ||
each(columns, (value, name) => { | ||
if (isString(value) && isFunction(table[value])) { | ||
table[value](name) | ||
} else if (isObject(value)) { | ||
let column = Object.assign({}, { name }, value) | ||
processColumn(table, column) | ||
} | ||
}) | ||
} | ||
|
||
export function mapColumnProperties (partial, column) { | ||
return Object.keys(column).reduce((acc, key) => { | ||
// name & type are handled already | ||
if (key === 'name' || key === 'type') return acc | ||
|
||
let value = column[key] | ||
let method = acc[key] | ||
|
||
if (typeof method !== 'function') { | ||
return | ||
} | ||
|
||
return value === undefined | ||
? method.call(acc) | ||
: method.call(acc, value) | ||
}, partial) | ||
} | ||
|
||
export function stringToBoolean (value) { | ||
if (value !== 'true' && value !== 'false') return value | ||
return value === 'true' | ||
} | ||
|
||
export function booleanToString (value) { | ||
return isBoolean ? `${value}` : value | ||
} |
Oops, something went wrong.