UNPKG

@cheetah.js/orm

Version:
189 lines (188 loc) 7.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SqlConditionBuilder = void 0; const value_object_1 = require("../common/value-object"); const utils_1 = require("../utils"); class SqlConditionBuilder { constructor(entityStorage, applyJoinCallback, statements) { this.entityStorage = entityStorage; this.applyJoinCallback = applyJoinCallback; this.statements = statements; this.OPERATORS = ['$eq', '$ne', '$in', '$nin', '$like', '$gt', '$gte', '$lt', '$lte', '$and', '$or']; this.lastKeyNotOperator = ''; } build(condition, alias, model) { const sqlParts = this.processConditions(condition, alias, model); if (sqlParts.length === 0) { return ''; } return this.wrapWithLogicalOperator(sqlParts, 'AND'); } processConditions(condition, alias, model) { const sqlParts = []; for (let [key, value] of Object.entries(condition)) { const extractedValue = this.extractValueFromValueObject(value); const conditionSql = this.processEntry(key, extractedValue, alias, model); if (conditionSql) { sqlParts.push(conditionSql); } } return sqlParts; } processEntry(key, value, alias, model) { this.trackLastNonOperatorKey(key, model); const relationship = this.findRelationship(key, model); if (relationship) { return this.handleRelationship(relationship, value, alias); } if (this.isScalarValue(value)) { return this.handleScalarValue(key, value, alias, model); } if (this.isArrayValue(key, value)) { return this.buildInCondition(key, value, alias, model); } return this.handleObjectValue(key, value, alias, model); } handleRelationship(relationship, value, alias) { const sql = this.applyJoinCallback(relationship, value, alias); if (this.statements.strategy === 'joined') { return sql; } return ''; } handleScalarValue(key, value, alias, model) { if (key === '$eq') { return this.buildSimpleCondition(this.lastKeyNotOperator, value, alias, '=', model); } return this.buildSimpleCondition(key, value, alias, '=', model); } handleObjectValue(key, value, alias, model) { if (this.isLogicalOperator(key)) { return this.buildLogicalOperatorCondition(key, value, alias, model); } return this.buildOperatorConditions(key, value, alias, model); } buildLogicalOperatorCondition(key, value, alias, model) { const conditions = value.map((cond) => this.build(cond, alias, model)); const operator = this.extractLogicalOperator(key); return this.wrapWithLogicalOperator(conditions, operator); } buildOperatorConditions(key, value, alias, model) { const parts = []; for (const operator of this.OPERATORS) { if (operator in value) { const condition = this.buildOperatorCondition(key, operator, value[operator], alias, model); parts.push(condition); } } return parts.join(' AND '); } buildOperatorCondition(key, operator, value, alias, model) { switch (operator) { case '$eq': return this.buildSimpleCondition(key, value, alias, '=', model); case '$ne': return this.buildSimpleCondition(key, value, alias, '!=', model); case '$in': return this.buildInCondition(key, value, alias, model); case '$nin': return this.buildNotInCondition(key, value, alias, model); case '$like': return this.buildLikeCondition(key, value, alias, model); case '$gt': return this.buildComparisonCondition(key, value, alias, '>', model); case '$gte': return this.buildComparisonCondition(key, value, alias, '>=', model); case '$lt': return this.buildComparisonCondition(key, value, alias, '<', model); case '$lte': return this.buildComparisonCondition(key, value, alias, '<=', model); case '$and': case '$or': return this.buildNestedLogicalCondition(operator, value, alias, model); default: return ''; } } buildSimpleCondition(key, value, alias, operator, model) { const column = this.resolveColumnName(key, model); const formattedValue = this.formatValue(value); return `${alias}.${column} ${operator} ${formattedValue}`; } buildInCondition(key, values, alias, model) { const column = this.resolveColumnName(key, model); const formattedValues = values.map(val => this.formatValue(val)).join(', '); return `${alias}.${column} IN (${formattedValues})`; } buildNotInCondition(key, values, alias, model) { const column = this.resolveColumnName(key, model); const formattedValues = values.map(val => this.formatValue(val)).join(', '); return `${alias}.${column} NOT IN (${formattedValues})`; } buildLikeCondition(key, value, alias, model) { const column = this.resolveColumnName(key, model); return `${alias}.${column} LIKE '${value}'`; } buildComparisonCondition(key, value, alias, operator, model) { const column = this.resolveColumnName(key, model); return `${alias}.${column} ${operator} ${value}`; } buildNestedLogicalCondition(operator, value, alias, model) { const conditions = value.map((cond) => this.build(cond, alias, model)); const logicalOp = this.extractLogicalOperator(operator); return this.wrapWithLogicalOperator(conditions, logicalOp); } wrapWithLogicalOperator(conditions, operator) { return `(${conditions.join(` ${operator} `)})`; } extractValueFromValueObject(value) { if ((0, utils_1.extendsFrom)(value_object_1.ValueObject, value?.constructor?.prototype)) { return value.getValue(); } return value; } formatValue(value) { return (typeof value === 'string') ? `'${value}'` : value; } findRelationship(key, model) { const entity = this.entityStorage.get(model); return entity?.relations?.find(rel => rel.propertyKey === key); } isScalarValue(value) { return typeof value !== 'object' || value === null; } isArrayValue(key, value) { return !this.OPERATORS.includes(key) && Array.isArray(value); } isLogicalOperator(key) { return ['$or', '$and'].includes(key); } extractLogicalOperator(key) { return key.toUpperCase().replace('$', ''); } trackLastNonOperatorKey(key, model) { if (!this.OPERATORS.includes(key)) { this.lastKeyNotOperator = key; } } resolveColumnName(property, model) { if (property.startsWith('$')) { return property; } const entity = this.entityStorage.get(model); if (!entity) { return property; } const column = entity.properties?.[property]?.options.columnName; if (column) { return column; } return this.resolveRelationColumn(property, entity) ?? property; } resolveRelationColumn(property, entity) { const relation = entity.relations?.find(rel => rel.propertyKey === property); const column = relation?.columnName; return typeof column === 'string' ? column : undefined; } } exports.SqlConditionBuilder = SqlConditionBuilder;