@kinshipjs/adapter-tests v0.2.6
KinshipJS
Adapter Tests
Testing suite for testing a custom adapter with Kinship
.
Custom Adapter Development
Kinship is a database agnostic ORM thanks to the adapter support built in with it. While there are many adapters available, this suite guides you on how to build your own adapter as well as testing it so it is ready to be packaged and deployed.
Get Started
Install the necessary libraries
npm i @kinshipjs/core
npm i -D @kinshipjs/adapter-tests
Set up your database so it appears as the following:
NOTE: Avoid adding any constraints, as truncations of the tables occur, and if the SQL engine used prevents truncation for constraints, then the testAdapter
function will never pass.
Serializing
forQuery()
The forQuery()
function handles any sort of querying function in your database engine, such as a SELECT * FROM
query.
The data you have access to is contained in one SerializationQueryHandlerData
object.
SerializationQueryHandlerData
Property | Type | Description |
---|---|---|
from | [MainTableFromClauseProperty, ...FromClauseProperty[]] | Array of objects where each object represents a table to join on. The first object will represent the main table the context is connected to. |
group_by | GroupByClauseProperty[]|undefined | Array of objects where each object represents a column to group by. If undefined, then no GROUP BY clause was given. |
limit | number|undefined | Number representing the number of records to grab. If undefined, then no LIMIT clause was given. |
offset | number|undefined | Number representing the number of records to skip before grabbing. If undefined, then no OFFSET clause was given. |
order_by | SortByClauseProperty[]|undefined | Array of objects where each object represents a column to order by. If undefined, then no ORDER BY clause was given. |
select | Column[] | Array of objects where each object represents a column to select. |
where | WhereClausePropertyArray|undefined | Recursively nested array of objects where each object represents a condition. If the element is an array, then that means the condition is nested with the last element from that array. If undefined, then no WHERE clause was given. |
With the information given to the adapter using SerializationQueryHandlerData, you can construct a command for use within the engine that you are setting the adapter up.
Below are some examples and templates.
Template: createReductionFunction
Definition:
/**
* Various tools to set up the reduction function used for serializing WHERE clauses.
* @typedef {object} WhereClauseReduceTools
* @prop {{[key: WhereChain]: string}=} chains
* A map of each `WhereChain` (used in Kinship) to the actual string it should use in your SQL engine.
* (e.g., AND, OR, AND NOT, OR NOT, etc.)
* @prop {{[key: WhereOperator]: (...args: string[]) => string}=} operators
* A map of each `WhereOperator` (used in Kinship) to a function that gets the actual string (with the values)
* it should use in your SQL engine.
*
* __NOTE: The values are already sanitized, so you will not have to worry about sanitizing them again.__
*
* e.g.,, in MSSQL:
* ```js
* const reduceTools = {
* operators: {
* [WhereOperator.BETWEEN]: (x,y) => `BETWEEN ${x} AND ${y}`
* }
* }
* ```
* @prop {((n: number) => string)=} sanitize
* Sanitizes the argument, where `n` is the index of the argument it would pass into `for.execute()`
*
* e.g., in MySQL:
* ```js
* const reduceTools = {
* sanitize: (n) => `?`
* }
* ```
* @prop {number=} spacing
* Specifies the spacing for if the command should prettified before getting sent back to Kinship.
* (the default for this is 4 [spaces], and it should remain this way so users can use `onSuccess` or `onFail` to monitor their commands.)
* If `0` or `undefined` is passed in, then newlines are replaced with regular spaces.
*/
/**
* Create a reduction function for usage with your serialization of the WHERE clause.
* @param {any[]} __argsReference
* Reference to an array that will contain all of the arguments to be passed into the Engine upon completion of this function.
* @param {WhereClauseReduceTools} tools
* Various tools that allow you to change the behavior of the serialization of the WHERE clause at a given moment.
*/
function createReductionFunction(
__argsReference=[],
tools={}
) {
const {
chains,
operators,
sanitize = (n) => '?',
spacing = 4
} = tools;
/**
* @param {string} command
* @param {any} condition
*/
const reduce = (command, condition, depth=1) => {
const padding = (spacing ?? 0) * 2;
const numberOfIndents = (depth * (spacing ?? 0)) + padding;
const indentation = Array.from(Array(numberOfIndents).keys()).map(_ => " ").join('');
const prettify = `${spacing ? "\n" : " "}${indentation}`;
if(Array.isArray(condition)) {
const chain = condition[0].chain;
condition[0].chain = "";
const reduced = condition.reduce((command, condition) => reduce(command, condition, depth + 1), `${chain} (`);
return `${command}${reduced})${prettify}`;
}
let {
chain,
operator,
property,
table,
value
} = condition;
if(Array.isArray(value)) {
value = value.map((v,n) => {
__argsReference.push(v);
return sanitize(__argsReference.length + n);
});
} else {
__argsReference.push(value);
}
chain = chains?.[chain] ?? chain;
if(operators?.[operator]) {
const values = /** @type {string[]} */ (Array.isArray(value) ? value : [value]);
return `${command}${chain} ${escape(table, true)}.${escape(property)} ${operators[operator](...values)} ${prettify}`;
}
return `${command}${chain} ${escape(table, true)}.${escape(property)} ${operator} ${sanitize(__argsReference.length)}${prettify}`;
}
return reduce;
}
Example of usage (MSSQL):
let args = [];
const reduce = createReduce(args, {
spacing: 4,
operators: {
[WhereOperator.BETWEEN]: (x,y) => `BETWEEN ${x} AND ${y}`,
[WhereOperator.IN]: (...values) => `IN (${values.join(',')})`
}
});
if(where) {
const cmd = where.reduce((cmd, cond) => reduce(cmd, cond));
}
console.log(cmd);
// would print something like this for `.where(m => m.FirstName.equals("John").and(m => m.LastName.equals("Doe")))`
/**
* SELECT [FirstName] AS [FirstName]
* [LastName] AS [LastName]
* FROM [MyTable] AS [MyTable]
* WHERE [FirstName] = ?
* AND [LastName] = ?
*/
Executing
Data Types
Column
FromClauseProperty
GroupByClauseProperty
MainTableFromClauseProperty
SortByClauseProperty
WhereClausePropertyArray
Testing your Custom Adapter
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
4 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
5 months ago
8 months ago
8 months ago