UNPKG

objection

Version:
148 lines (116 loc) 3.73 kB
'use strict'; const { isObject, isFunction } = require('../utils/objectUtils'); const { defineNonEnumerableProperty } = require('./modelUtils'); const { isKnexRaw, isKnexQueryBuilder } = require('../utils/knexUtils'); const QUERY_PROPS_PROPERTY = '$$queryProps'; // Removes query properties from `json` and stores them into a hidden property // inside `model` so that they can be later merged back to `json`. function splitQueryProps(model, json) { const keys = Object.keys(json); if (hasQueryProps(json, keys)) { const queryProps = {}; const modelProps = {}; for (let i = 0, l = keys.length; i < l; ++i) { const key = keys[i]; const value = json[key]; if (isQueryProp(value)) { queryProps[key] = value; } else { modelProps[key] = value; } } defineNonEnumerableProperty(model, QUERY_PROPS_PROPERTY, queryProps); return modelProps; } else { return json; } } function hasQueryProps(json, keys) { for (let i = 0, l = keys.length; i < l; ++i) { if (isQueryProp(json[keys[i]])) { return true; } } return false; } function isQueryProp(value) { if (!isObject(value)) { return false; } return ( isKnexQueryBuilder(value) || isKnexRaw(value) || isKnexRawConvertable(value) || value.isObjectionQueryBuilderBase ); } // Merges and converts `model`'s query properties into `json`. function mergeQueryProps(model, json, omitProps, builder) { json = convertExistingQueryProps(json, builder); json = convertAndMergeHiddenQueryProps(model, json, omitProps, builder); return json; } // Converts the query properties in `json` to knex raw instances. // `json` may have query properties even though we removed them. // For example they may have been added in lifecycle hooks. function convertExistingQueryProps(json, builder) { const keys = Object.keys(json); for (let i = 0, l = keys.length; i < l; ++i) { const key = keys[i]; const value = json[key]; if (isQueryProp(value)) { json[key] = queryPropToKnexRaw(value, builder); } } return json; } // Converts and merges the query props that were split from the model // and stored into QUERY_PROPS_PROPERTY. function convertAndMergeHiddenQueryProps(model, json, omitProps, builder) { const queryProps = model[QUERY_PROPS_PROPERTY]; if (!queryProps) { // The model has no query properties. return json; } const modelClass = model.constructor; const keys = Object.keys(queryProps); for (let i = 0, l = keys.length; i < l; ++i) { const key = keys[i]; if (!omitProps || !omitProps.includes(key)) { const queryProp = queryPropToKnexRaw(queryProps[key], builder); json[modelClass.propertyNameToColumnName(key)] = queryProp; } } return json; } // Converts a query property into a knex `raw` instance. function queryPropToKnexRaw(queryProp, builder) { if (!queryProp) { return queryProp; } if (queryProp.isObjectionQueryBuilderBase) { return buildObjectionQueryBuilder(queryProp, builder); } else if (isKnexRawConvertable(queryProp)) { return buildKnexRawConvertable(queryProp, builder); } else { return queryProp; } } function buildObjectionQueryBuilder(builder, parentBuilder) { return builder.subqueryOf(parentBuilder).toKnexQuery(); } function buildKnexRawConvertable(convertable, builder) { if (!builder) { throw new Error( 'toDatabaseJson called without a query builder instance for a model with query properties', ); } return convertable.toKnexRaw(builder); } function isKnexRawConvertable(queryProp) { return isFunction(queryProp.toKnexRaw); } module.exports = { splitQueryProps, mergeQueryProps, };