"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SolidBaseRepository = void 0;
const lodash_1 = require("lodash");
const common_1 = require("@nestjs/common");
const model_metadata_entity_1 = require("../entities/model-metadata.entity");
const typeorm_1 = require("typeorm");
class SolidBaseRepository extends typeorm_1.Repository {
    constructor(entity, dataSource, requestContextService, securityRuleRepository) {
        super(entity, dataSource.createEntityManager());
        this.requestContextService = requestContextService;
        this.securityRuleRepository = securityRuleRepository;
        this.logger = new common_1.Logger(this.constructor.name);
    }
    modelSingularName() {
        return (0, lodash_1.camelCase)(this.metadata.name);
    }
    async findOneByUserKey(userKeyValue) {
        const modelSingularName = this.modelSingularName();
        const modelMetaRepo = this.manager.getRepository(model_metadata_entity_1.ModelMetadata);
        const modelMeta = await modelMetaRepo.findOne({
            where: { singularName: modelSingularName },
            relations: { userKeyField: true },
        });
        if (!modelMeta?.userKeyField?.name) {
            throw new Error(`User key field not found for model ${modelSingularName}`);
        }
        return this.findOneBy({ [modelMeta.userKeyField.name]: userKeyValue });
    }
    createQueryBuilder(alias, queryRunner) {
        throw new Error('createQueryBuilder() is disabled. Use createSecurityRuleAwareQueryBuilder instead');
    }
    async createSecurityRuleAwareQueryBuilder(alias, queryRunner) {
        const qb = super.createQueryBuilder(alias, queryRunner);
        if (!this.securityRuleRepository)
            return qb;
        if (!this.requestContextService)
            return qb;
        const activeUserOrUndefined = this.requestContextService.getActiveUser();
        if (!activeUserOrUndefined)
            return qb;
        return await this.securityRuleRepository.applySecurityRules(qb, this.modelSingularName(), activeUserOrUndefined);
    }
    async findOne(options) {
        const alias = this.modelSingularName();
        const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
        if (options) {
            if (options)
                qb.setFindOptions(options);
        }
        return qb.getOne();
    }
    async findOneBy(where) {
        return this.findOne({ where });
    }
    async findOneOrFail(options) {
        const entity = await this.findOne(options);
        if (!entity) {
            throw new typeorm_1.EntityNotFoundError(this.metadata.target, options?.where ?? {});
        }
        return entity;
    }
    async find(options) {
        const alias = this.modelSingularName();
        const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
        if (options) {
            qb.setFindOptions(options);
        }
        return qb.getMany();
    }
    async findAndCount(options) {
        const alias = this.modelSingularName();
        const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
        if (options) {
            qb.setFindOptions(options);
        }
        return qb.getManyAndCount();
    }
    async count(options) {
        const alias = this.modelSingularName();
        const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
        if (options) {
            qb.setFindOptions(options);
        }
        return qb.getCount();
    }
    async countBy(where) {
        return this.count({ where });
    }
    async average(columnName, where) {
        const alias = this.modelSingularName();
        const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
        if (where) {
            qb.setFindOptions({ where });
        }
        const result = await qb
            .select(`AVG(CAST(${alias}.${String(columnName)} AS FLOAT))`, 'avg')
            .getRawOne();
        if (result?.avg === null || result?.avg === undefined) {
            return null;
        }
        return typeof result.avg === 'number'
            ? result.avg
            : parseFloat(result.avg);
    }
    async sum(columnName, where) {
        const alias = this.modelSingularName();
        const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
        if (where) {
            qb.setFindOptions({ where });
        }
        const result = await qb
            .select(`SUM(CAST(${alias}.${String(columnName)} AS FLOAT))`, 'sum')
            .getRawOne();
        if (result?.sum === null || result?.sum === undefined) {
            return null;
        }
        return typeof result.sum === 'number'
            ? result.sum
            : parseFloat(result.sum);
    }
    async minimum(columnName, where) {
        const alias = this.modelSingularName();
        const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
        if (where) {
            qb.setFindOptions({ where });
        }
        const result = await qb
            .select(`MIN(CAST(${alias}.${String(columnName)} AS FLOAT))`, 'min')
            .getRawOne();
        if (result?.min === null || result?.min === undefined) {
            return null;
        }
        return typeof result.min === 'number'
            ? result.min
            : parseFloat(result.min);
    }
    async maximum(columnName, where) {
        const alias = this.modelSingularName();
        const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
        if (where) {
            qb.setFindOptions({ where });
        }
        const result = await qb
            .select(`MAX(CAST(${alias}.${String(columnName)} AS FLOAT))`, 'max')
            .getRawOne();
        if (result?.max === null || result?.max === undefined) {
            return null;
        }
        return typeof result.max === 'number'
            ? result.max
            : parseFloat(result.max);
    }
    async increment(where, propertyPath, value) {
        const alias = this.modelSingularName();
        const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
        qb.setFindOptions({ where });
        const rows = await qb.select(`${alias}.id`).getMany();
        const ids = rows.map((r) => r.id);
        if (ids.length === 0) {
            return { raw: [], affected: 0, generatedMaps: [] };
        }
        return this.manager
            .createQueryBuilder()
            .update(this.metadata.target)
            .set({ [propertyPath]: () => `${propertyPath} + :value` })
            .whereInIds(ids)
            .setParameter('value', value)
            .execute();
    }
    async decrement(where, propertyPath, value) {
        const alias = this.modelSingularName();
        const qb = await this.createSecurityRuleAwareQueryBuilder(alias);
        qb.setFindOptions({ where });
        const rows = await qb.select(`${alias}.id`).getMany();
        const ids = rows.map((r) => r.id);
        if (ids.length === 0) {
            return { raw: [], affected: 0, generatedMaps: [] };
        }
        return this.manager
            .createQueryBuilder()
            .update(this.metadata.target)
            .set({ [propertyPath]: () => `${propertyPath} - :value` })
            .whereInIds(ids)
            .setParameter('value', value)
            .execute();
    }
}
exports.SolidBaseRepository = SolidBaseRepository;
//# sourceMappingURL=solid-base.repository.js.map