"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SqlTestingHelper = void 0;
const tslib_1 = require("tslib");
const _a = tslib_1.__importStar(require("@zyno-io/ts-server-foundation/type-metadata-runtime"));
const node_test_1 = require("node:test");
const node_util_1 = require("node:util");
const database_1 = require("../database/database");
const entity_1 = require("../database/entity");
const metadata_1 = require("../database/metadata");
const __tsf_metadata_type = _a.createCompactMetadataRegistryV1("[1,[{\"kind\":2,\"typeName\":\"ClassType\",\"typeArguments\":[{\"kind\":2,\"typeName\":\"T\"}]},{\"kind\":12,\"types\":[{\"kind\":14,\"type\":{\"kind\":18,\"typeName\":\"Partial\",\"utilityType\":\"Partial\",\"typeArguments\":[{\"kind\":18,\"typeName\":\"EntityFields\",\"types\":[]}],\"utilityKeys\":[],\"types\":[]}},{\"kind\":18,\"typeName\":\"Partial\",\"utilityType\":\"Partial\",\"typeArguments\":[{\"kind\":18,\"typeName\":\"EntityFields\",\"types\":[]}],\"utilityKeys\":[],\"types\":[]}]},{\"kind\":3},{\"kind\":2,\"typeName\":\"ClassType\"},{\"kind\":8},{\"kind\":2,\"typeName\":\"EntityClass\",\"typeArguments\":[{\"kind\":2,\"typeName\":\"T\"}]},{\"kind\":18,\"typeName\":\"Record\",\"utilityType\":\"Record\",\"typeArguments\":[{\"kind\":6},{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":18,\"types\":[{\"kind\":20,\"name\":\"$in\",\"type\":{\"kind\":12,\"types\":[{\"kind\":14,\"type\":{\"kind\":2}},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$nin\",\"type\":{\"kind\":12,\"types\":[{\"kind\":14,\"type\":{\"kind\":2}},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$ne\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$gt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$gte\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$lt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$lte\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$like\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$notLike\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true}]}],\"typeName\":\"FilterValue\"}],\"index\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":18,\"types\":[{\"kind\":20,\"name\":\"$in\",\"type\":{\"kind\":12,\"types\":[{\"kind\":14,\"type\":{\"kind\":2}},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$nin\",\"type\":{\"kind\":12,\"types\":[{\"kind\":14,\"type\":{\"kind\":2}},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$ne\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$gt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$gte\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$lt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$lte\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$like\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$notLike\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true}]}],\"typeName\":\"FilterValue\"},\"types\":[],\"typeName\":\"FilterRecord\"},{\"kind\":12,\"types\":[{\"kind\":2,\"typeName\":\"keyof T\"},{\"kind\":6}]},{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":18,\"types\":[{\"kind\":20,\"name\":\"$in\",\"type\":{\"kind\":12,\"types\":[{\"kind\":14,\"type\":{\"kind\":2}},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$nin\",\"type\":{\"kind\":12,\"types\":[{\"kind\":14,\"type\":{\"kind\":2}},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$ne\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$gt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$gte\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$lt\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$lte\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$like\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true},{\"kind\":20,\"name\":\"$notLike\",\"type\":{\"kind\":12,\"types\":[{\"kind\":2},{\"kind\":4}]},\"optional\":true}]}],\"typeName\":\"FilterValue\"},{\"kind\":14,\"type\":{\"kind\":6}},{\"kind\":6},{\"kind\":12,\"types\":[{\"kind\":10,\"literal\":\"asc\"},{\"kind\":10,\"literal\":\"desc\"},{\"kind\":10,\"literal\":\"ASC\"},{\"kind\":10,\"literal\":\"DESC\"},{\"kind\":10,\"literal\":1},{\"kind\":10,\"literal\":-1}]},{\"kind\":12,\"types\":[{\"kind\":6},{\"kind\":18,\"typeName\":\"Record\",\"utilityType\":\"Record\",\"typeArguments\":[{\"kind\":6},{\"kind\":12,\"types\":[{\"kind\":10,\"literal\":\"asc\"},{\"kind\":10,\"literal\":\"desc\"},{\"kind\":10,\"literal\":\"ASC\"},{\"kind\":10,\"literal\":\"DESC\"},{\"kind\":10,\"literal\":1},{\"kind\":10,\"literal\":-1}]}],\"index\":{\"kind\":12,\"types\":[{\"kind\":10,\"literal\":\"asc\"},{\"kind\":10,\"literal\":\"desc\"},{\"kind\":10,\"literal\":\"ASC\"},{\"kind\":10,\"literal\":\"DESC\"},{\"kind\":10,\"literal\":1},{\"kind\":10,\"literal\":-1}]},\"types\":[]}]},{\"kind\":7},{\"kind\":22,\"type\":{\"kind\":14,\"type\":{\"kind\":2,\"typeName\":\"T\"}}},{\"kind\":2,\"typeName\":\"K\"},{\"kind\":22,\"type\":{\"kind\":14,\"type\":{\"kind\":2,\"typeName\":\"T[K]\"}}},{\"kind\":22,\"type\":{\"kind\":12,\"types\":[{\"kind\":2,\"typeName\":\"T[K]\"},{\"kind\":4}]}},{\"kind\":22,\"type\":{\"kind\":2,\"typeName\":\"T[K]\"}},{\"kind\":22,\"type\":{\"kind\":12,\"types\":[{\"kind\":2,\"typeName\":\"T\"},{\"kind\":4}]}},{\"kind\":22,\"type\":{\"kind\":2,\"typeName\":\"T\"}},{\"kind\":22,\"type\":{\"kind\":8}},{\"kind\":22,\"type\":{\"kind\":7}},{\"kind\":18,\"typeName\":\"PatchRecord\\u003cT\\u003e\",\"index\":{\"kind\":1},\"types\":[]},{\"kind\":22,\"type\":{\"kind\":18,\"typeName\":\"QueryMutationResult\",\"types\":[{\"kind\":20,\"name\":\"affectedRows\",\"type\":{\"kind\":7},\"optional\":false},{\"kind\":20,\"name\":\"modified\",\"type\":{\"kind\":7},\"optional\":false},{\"kind\":20,\"name\":\"primaryKeys\",\"type\":{\"kind\":14,\"type\":{\"kind\":18,\"typeName\":\"Record\",\"utilityType\":\"Record\",\"typeArguments\":[{\"kind\":6},{\"kind\":2}],\"index\":{\"kind\":2},\"types\":[]}},\"optional\":false}]}},{\"kind\":14,\"type\":{\"kind\":18,\"typeName\":\"Record\",\"utilityType\":\"Record\",\"typeArguments\":[{\"kind\":6},{\"kind\":2}],\"index\":{\"kind\":2},\"types\":[]}},{\"kind\":2},{\"kind\":22,\"type\":{\"kind\":3}},{\"kind\":22,\"type\":{\"kind\":18,\"typeName\":\"DriverConnection\",\"types\":[]}}]]", []);
const helpers = [];
let sqlMockDatabase;
let _SqlTestingHelperMetadata_1;
class SqlTestingHelper {
    rows = new Map();
    mockEntity(entityClass, data) {
        const rows = this.rows.get(entityClass) ?? [];
        rows.push(...cloneRows(entityClass, Array.isArray(data) ? data : [data]));
        this.rows.set(entityClass, rows);
        (0, entity_1.bindEntityDatabase)(entityClass, getSqlMockDatabase());
        activateHelper(this);
        installMocks();
    }
    clearMocks() {
        this.rows.clear();
    }
    hasMock(entityClass) {
        return this.rows.has(entityClass);
    }
    createQuery(entityClass) {
        return new InMemoryQueryBuilder(entityClass, this.rows.get(entityClass) ?? []);
    }
    static __tsfType = _SqlTestingHelperMetadata_1 = _a.decodeCompactMetadataV1("[1,{\"kind\":16,\"name\":\"SqlTestingHelper\",\"typeName\":\"SqlTestingHelper\",\"classType\":{\"$tsf\":0},\"properties\":[],\"methods\":[{\"name\":\"mockEntity\",\"parameters\":[{\"name\":\"entityClass\",\"type\":{\"$tsfType\":0},\"optional\":false,\"default\":false},{\"name\":\"data\",\"type\":{\"$tsfType\":1},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":2}},{\"name\":\"clearMocks\",\"parameters\":[],\"returnType\":{\"$tsfType\":2}},{\"name\":\"hasMock\",\"parameters\":[{\"name\":\"entityClass\",\"type\":{\"$tsfType\":3},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":4}},{\"name\":\"createQuery\",\"parameters\":[{\"name\":\"entityClass\",\"type\":{\"$tsfType\":5},\"optional\":false,\"default\":false}],\"returnType\":{\"kind\":16,\"typeName\":\"InMemoryQueryBuilder\",\"classType\":{\"$tsf\":1},\"typeArguments\":[{\"kind\":2,\"typeName\":\"T\"}]}}],\"hasConstructor\":false,\"constructorParameters\":[]}]", [() => SqlTestingHelper, () => (typeof InMemoryQueryBuilder !== "undefined" ? InMemoryQueryBuilder : (typeof exports !== "undefined" ? exports.InMemoryQueryBuilder : undefined))], __tsf_metadata_type);
}
exports.SqlTestingHelper = SqlTestingHelper;
_SqlTestingHelperMetadata_1.classType = SqlTestingHelper;
SqlTestingHelper.__tsfType = _SqlTestingHelperMetadata_1;
let _InMemoryQueryBuilderMetadata_1;
class InMemoryQueryBuilder {
    entityClass;
    rows;
    filters = {};
    selected;
    order = [];
    limitValue;
    offsetValue;
    constructor(entityClass, rows) {
        this.entityClass = entityClass;
        this.rows = rows;
    }
    filter(filter) {
        Object.assign(this.filters, filter);
        return this;
    }
    filterField(field, value) {
        return this.filter({ [String(field)]: value });
    }
    select(...fields) {
        this.selected = fields;
        return this;
    }
    orderBy(field, direction = 'asc') {
        this.order.push({ field, direction: normalizeDirection(direction) });
        return this;
    }
    sort(field, direction = 'asc') {
        if (typeof field === 'string')
            return this.orderBy(field, direction);
        for (const [name, value] of Object.entries(field))
            this.orderBy(name, value);
        return this;
    }
    limit(limit) {
        this.limitValue = limit;
        return this;
    }
    offset(offset) {
        this.offsetValue = offset;
        return this;
    }
    skip(offset) {
        return this.offset(offset);
    }
    async find() {
        return this.applyQuery().map(row => this.hydrate(row));
    }
    async findField(field) {
        return this.applyQuery().map(row => row[String(field)]);
    }
    async findOneFieldOrUndefined(field) {
        return this.limit(1)
            .findField(field)
            .then(rows => rows[0]);
    }
    async findOneField(field) {
        const value = await this.findOneFieldOrUndefined(field);
        if (value === undefined)
            throw new Error('Item not found');
        return value;
    }
    async findOneOrUndefined() {
        return (await this.limit(1).find())[0];
    }
    async findOne() {
        const entity = await this.findOneOrUndefined();
        if (!entity)
            throw new Error('Item not found');
        return entity;
    }
    async has() {
        return this.applyQuery().length > 0;
    }
    async count() {
        return this.applyQuery().length;
    }
    async patchMany(patch) {
        const matches = this.applyQuery();
        for (const row of matches)
            this.applyPatch(row, patch);
        return createMutationResult(matches.length);
    }
    async patchOne(patch) {
        const primaryKey = this.requirePrimaryKeyFilter('patchOne');
        const match = this.rows.find(row => matchesFilter(row, this.filters));
        if (!match)
            return createMutationResult(0);
        this.applyPatch(match, patch);
        return createMutationResult(1, [primaryKey]);
    }
    async deleteMany() {
        const matches = this.applyQuery();
        for (const row of matches)
            this.rows.splice(this.rows.indexOf(row), 1);
        return createMutationResult(matches.length);
    }
    async deleteOne() {
        const primaryKey = this.requirePrimaryKeyFilter('deleteOne');
        const index = this.rows.findIndex(row => matchesFilter(row, this.filters));
        if (index === -1)
            return createMutationResult(0);
        this.rows.splice(index, 1);
        return createMutationResult(1, [primaryKey]);
    }
    applyPatch(row, patch) {
        for (const [key, value] of Object.entries(patch)) {
            if (key === '$inc' || value === undefined)
                continue;
            row[key] = value;
        }
        if (isRecord(patch.$inc)) {
            for (const [key, value] of Object.entries(patch.$inc)) {
                row[key] = Number(row[key] ?? 0) + Number(value);
            }
        }
    }
    requirePrimaryKeyFilter(operation) {
        const metadata = (0, metadata_1.getEntityMetadata)(this.entityClass);
        const result = {};
        for (const primaryKey of metadata.primaryKeys) {
            const filterKey = Object.hasOwn(this.filters, primaryKey.propertyName)
                ? primaryKey.propertyName
                : Object.hasOwn(this.filters, primaryKey.columnName)
                    ? primaryKey.columnName
                    : undefined;
            const value = filterKey === undefined ? undefined : this.filters[filterKey];
            if (filterKey === undefined || value === null || value === undefined || isOperatorRecord(value)) {
                throw new Error(`${operation} requires an exact filter for primary key ${metadata.classType.name}.${primaryKey.propertyName}`);
            }
            result[primaryKey.propertyName] = value;
        }
        return result;
    }
    applyQuery() {
        let result = this.rows.filter(row => matchesFilter(row, this.filters));
        if (this.order.length) {
            result = [...result].sort((a, b) => {
                for (const item of this.order) {
                    const compared = compareValues(a[item.field], b[item.field]);
                    if (compared)
                        return item.direction === 'desc' ? -compared : compared;
                }
                return 0;
            });
        }
        if (this.offsetValue !== undefined)
            result = result.slice(this.offsetValue);
        if (this.limitValue !== undefined)
            result = result.slice(0, this.limitValue);
        return result;
    }
    hydrate(row) {
        const source = this.selected?.length ? Object.fromEntries(this.selected.map(field => [field, row[field]])) : row;
        const entity = (0, entity_1.createEntity)(this.entityClass, cloneRecord(source));
        (0, entity_1.markEntityClean)(entity);
        return entity;
    }
    static __tsfType = _InMemoryQueryBuilderMetadata_1 = _a.decodeCompactMetadataV1("[1,{\"kind\":16,\"name\":\"InMemoryQueryBuilder\",\"typeName\":\"InMemoryQueryBuilder\",\"classType\":{\"$tsf\":0},\"properties\":[],\"methods\":[{\"name\":\"filter\",\"parameters\":[{\"name\":\"filter\",\"type\":{\"$tsfType\":6},\"optional\":false,\"default\":false}],\"returnType\":{\"kind\":16,\"typeName\":\"this\",\"classType\":{\"$tsf\":1}}},{\"name\":\"filterField\",\"parameters\":[{\"name\":\"field\",\"type\":{\"$tsfType\":7},\"optional\":false,\"default\":false},{\"name\":\"value\",\"type\":{\"$tsfType\":8},\"optional\":false,\"default\":false}],\"returnType\":{\"kind\":16,\"typeName\":\"this\",\"classType\":{\"$tsf\":1}}},{\"name\":\"select\",\"parameters\":[{\"name\":\"fields\",\"type\":{\"$tsfType\":9},\"optional\":false,\"default\":false}],\"returnType\":{\"kind\":16,\"typeName\":\"this\",\"classType\":{\"$tsf\":1}}},{\"name\":\"orderBy\",\"parameters\":[{\"name\":\"field\",\"type\":{\"$tsfType\":10},\"optional\":false,\"default\":false},{\"name\":\"direction\",\"type\":{\"$tsfType\":11},\"optional\":true,\"default\":true}],\"returnType\":{\"kind\":16,\"typeName\":\"this\",\"classType\":{\"$tsf\":1}}},{\"name\":\"sort\",\"parameters\":[{\"name\":\"field\",\"type\":{\"$tsfType\":12},\"optional\":false,\"default\":false},{\"name\":\"direction\",\"type\":{\"$tsfType\":11},\"optional\":true,\"default\":true}],\"returnType\":{\"kind\":16,\"typeName\":\"this\",\"classType\":{\"$tsf\":1}}},{\"name\":\"limit\",\"parameters\":[{\"name\":\"limit\",\"type\":{\"$tsfType\":13},\"optional\":false,\"default\":false}],\"returnType\":{\"kind\":16,\"typeName\":\"this\",\"classType\":{\"$tsf\":1}}},{\"name\":\"offset\",\"parameters\":[{\"name\":\"offset\",\"type\":{\"$tsfType\":13},\"optional\":false,\"default\":false}],\"returnType\":{\"kind\":16,\"typeName\":\"this\",\"classType\":{\"$tsf\":1}}},{\"name\":\"skip\",\"parameters\":[{\"name\":\"offset\",\"type\":{\"$tsfType\":13},\"optional\":false,\"default\":false}],\"returnType\":{\"kind\":16,\"typeName\":\"this\",\"classType\":{\"$tsf\":1}}},{\"name\":\"find\",\"parameters\":[],\"returnType\":{\"$tsfType\":14}},{\"name\":\"findField\",\"parameters\":[{\"name\":\"field\",\"type\":{\"$tsfType\":15},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":16}},{\"name\":\"findOneFieldOrUndefined\",\"parameters\":[{\"name\":\"field\",\"type\":{\"$tsfType\":15},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":17}},{\"name\":\"findOneField\",\"parameters\":[{\"name\":\"field\",\"type\":{\"$tsfType\":15},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":18}},{\"name\":\"findOneOrUndefined\",\"parameters\":[],\"returnType\":{\"$tsfType\":19}},{\"name\":\"findOne\",\"parameters\":[],\"returnType\":{\"$tsfType\":20}},{\"name\":\"has\",\"parameters\":[],\"returnType\":{\"$tsfType\":21}},{\"name\":\"count\",\"parameters\":[],\"returnType\":{\"$tsfType\":22}},{\"name\":\"patchMany\",\"parameters\":[{\"name\":\"patch\",\"type\":{\"$tsfType\":23},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":24}},{\"name\":\"patchOne\",\"parameters\":[{\"name\":\"patch\",\"type\":{\"$tsfType\":23},\"optional\":false,\"default\":false}],\"returnType\":{\"$tsfType\":24}},{\"name\":\"deleteMany\",\"parameters\":[],\"returnType\":{\"$tsfType\":24}},{\"name\":\"deleteOne\",\"parameters\":[],\"returnType\":{\"$tsfType\":24}}],\"hasConstructor\":true,\"constructorParameters\":[{\"name\":\"entityClass\",\"type\":{\"$tsfType\":5},\"optional\":false,\"default\":false},{\"name\":\"rows\",\"type\":{\"$tsfType\":25},\"optional\":false,\"default\":false}]}]", [() => InMemoryQueryBuilder, () => (typeof this !== "undefined" ? this : (typeof exports !== "undefined" ? exports.this : undefined))], __tsf_metadata_type);
}
_InMemoryQueryBuilderMetadata_1.classType = InMemoryQueryBuilder;
InMemoryQueryBuilder.__tsfType = _InMemoryQueryBuilderMetadata_1;
let _SqlTestingDriverMetadata_1;
class SqlTestingDriver {
    dialect = 'mysql';
    async connect() { }
    async close() { }
    async acquire() {
        throw new Error('SQL test mocks are not configured for this entity');
    }
    static __tsfType = _SqlTestingDriverMetadata_1 = _a.decodeCompactMetadataV1("[1,{\"kind\":16,\"name\":\"SqlTestingDriver\",\"typeName\":\"SqlTestingDriver\",\"classType\":{\"$tsf\":0},\"properties\":[{\"name\":\"dialect\",\"type\":{\"$tsfType\":26},\"optional\":false}],\"methods\":[{\"name\":\"connect\",\"parameters\":[],\"returnType\":{\"$tsfType\":27}},{\"name\":\"close\",\"parameters\":[],\"returnType\":{\"$tsfType\":27}},{\"name\":\"acquire\",\"parameters\":[],\"returnType\":{\"$tsfType\":28}}],\"hasConstructor\":false,\"constructorParameters\":[]}]", [() => SqlTestingDriver], __tsf_metadata_type);
}
_SqlTestingDriverMetadata_1.classType = SqlTestingDriver;
SqlTestingDriver.__tsfType = _SqlTestingDriverMetadata_1;
function getSqlMockDatabase() {
    return (sqlMockDatabase ??= new database_1.BaseDatabase(new SqlTestingDriver()));
}
function installMocks() {
    const descriptor = Object.getOwnPropertyDescriptor(database_1.BaseDatabase.prototype, 'query');
    if (descriptor && typeof descriptor.value === 'function' && 'mock' in descriptor.value)
        return;
    const originalQuery = database_1.BaseDatabase.prototype.query;
    node_test_1.mock.method(database_1.BaseDatabase.prototype, 'query', function (Entity, session) {
        for (let index = helpers.length - 1; index >= 0; index--) {
            const helper = helpers[index];
            if (helper.hasMock(Entity))
                return helper.createQuery(Entity);
        }
        return originalQuery.call(this, Entity, session);
    });
}
function activateHelper(helper) {
    const index = helpers.indexOf(helper);
    if (index !== -1)
        helpers.splice(index, 1);
    helpers.push(helper);
}
function matchesFilter(row, filter) {
    for (const [field, expected] of Object.entries(filter)) {
        if (!matchesValue(row[field], expected))
            return false;
    }
    return true;
}
function matchesValue(actual, expected) {
    if (isOperatorRecord(expected)) {
        const inValues = Array.isArray(expected.$in) ? expected.$in : undefined;
        const notInValues = Array.isArray(expected.$nin) ? expected.$nin : undefined;
        if ('$in' in expected && !inValues?.some(item => (0, node_util_1.isDeepStrictEqual)(actual, item)))
            return false;
        if ('$nin' in expected && notInValues?.some(item => (0, node_util_1.isDeepStrictEqual)(actual, item)))
            return false;
        if ('$ne' in expected && (0, node_util_1.isDeepStrictEqual)(actual, expected.$ne))
            return false;
        if ('$gt' in expected && compareValues(actual, expected.$gt) <= 0)
            return false;
        if ('$gte' in expected && compareValues(actual, expected.$gte) < 0)
            return false;
        if ('$lt' in expected && compareValues(actual, expected.$lt) >= 0)
            return false;
        if ('$lte' in expected && compareValues(actual, expected.$lte) > 0)
            return false;
        if ('$like' in expected && !like(String(actual ?? ''), String(expected.$like)))
            return false;
        if ('$notLike' in expected && like(String(actual ?? ''), String(expected.$notLike)))
            return false;
        return true;
    }
    return (0, node_util_1.isDeepStrictEqual)(actual, expected);
}
function isOperatorRecord(value) {
    return (!!value &&
        typeof value === 'object' &&
        !Array.isArray(value) &&
        Object.keys(value).some(key => key.startsWith('$')));
}
function isRecord(value) {
    return !!value && typeof value === 'object' && !Array.isArray(value);
}
function like(actual, pattern) {
    const expression = pattern.split('%').map(escapeRegExp).join('.*').replace(/_/g, '.');
    return new RegExp(`^${expression}$`, 'i').test(actual);
}
function compareValues(a, b) {
    if (a === b)
        return 0;
    if (a === undefined || a === null)
        return 1;
    if (b === undefined || b === null)
        return -1;
    return a > b ? 1 : -1;
}
function normalizeDirection(direction) {
    if (direction === -1)
        return 'desc';
    if (direction === 1)
        return 'asc';
    return direction.toLowerCase() === 'desc' ? 'desc' : 'asc';
}
function createMutationResult(affectedRows, primaryKeys = []) {
    const result = { affectedRows, primaryKeys };
    Object.defineProperty(result, 'modified', {
        enumerable: false,
        value: affectedRows
    });
    return result;
}
function cloneRows(entityClass, rows) {
    return rows.map(row => (0, entity_1.getEntityFields)((0, entity_1.createEntity)(entityClass, row)));
}
function cloneRecord(row) {
    return { ...row };
}
function escapeRegExp(value) {
    return value.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
}
//# sourceMappingURL=sql.js.map