"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NamedTable = void 0;
const core_1 = require("@midwayjs/core");
const utils_1 = require("../../../utils");
const BoundSql_1 = require("../BoundSql");
const model_1 = require("../model");
const Where_1 = require("./Where");
class NamedTable {
    constructor({ tableName, sqlModule, namedTableInterceptors, }) {
        this._columns = {};
        this.fields = [];
        this.groups = [];
        this.orders = [];
        this.excludeColumns = new Set();
        this.useLogic = false;
        this._withBlank = false;
        this._where = new Where_1.Where(this);
        this.tableName = tableName;
        this.sqlModule = sqlModule;
        // this.rowMapColumnMapper = rowMapColumnMapper;
        this.namedTableInterceptors = namedTableInterceptors;
        this.logicDeleteColumn = sqlModule.logicDeleteColumn;
        this.logicDeleteValue = sqlModule.logicDeleteValue;
    }
    /**
     * 克隆
     */
    clone() {
        const namedTable = new NamedTable({
            tableName: this.tableName,
            sqlModule: this.sqlModule,
            namedTableInterceptors: this.namedTableInterceptors,
        });
        namedTable.primary = this.primary;
        namedTable.logicDeleteValue = this.logicDeleteValue;
        namedTable.logicDeleteColumn = this.logicDeleteColumn;
        namedTable._columns = { ...this._columns };
        namedTable.fields = [...this.fields];
        namedTable.groups = [...this.groups];
        namedTable.orders = [...this.orders];
        namedTable.excludeColumns = new Set(...this.excludeColumns);
        // namedTable.rowMapColumnMapper = this.rowMapColumnMapper;
        namedTable.defaultPrimaryValue = this.defaultPrimaryValue;
        namedTable.useLogic = this.useLogic;
        namedTable.withBlank = this.withBlank;
        namedTable._where = this._where == null ? null : this._where.clone();
        // namedTable.properties = this.properties;
        return namedTable;
    }
    /**
     * 使用逻辑删除
     */
    logic() {
        this.useLogic = true;
        return this;
    }
    /**
     * 更新空值
     */
    withBlank() {
        this._withBlank = true;
        return this;
    }
    /**
     * 设置主键名，update时使用
     * 设置主键名，并设置默认主键值(主要用于insert)
     * @param primary 主键列
     * @param defaultPrimaryValue 默认值
     */
    primary(primary, defaultPrimaryValue) {
        // this.primary = rowMapColumnMapper.apply(primary);
        this._primary = primary;
        if (defaultPrimaryValue != null) {
            // if (typeof defaultPrimaryValue === 'function') {
            //   this.defaultPrimaryValue = defaultPrimaryValue();
            // } else {
            // }
            this.defaultPrimaryValue = defaultPrimaryValue;
        }
        return this;
    }
    /**
     * 拼接where
     */
    where() {
        return this._where;
    }
    /**
     * 设置单列的值
     * @param property
     * @param value
     */
    column(property, value) {
        // this.columns.put(rowMapColumnMapper.apply(property), value);
        if (arguments.length === 1) {
            if ((0, utils_1.isNotBlank)(property)) {
                this.fields.push(property);
            }
        }
        else {
            this._columns[property] = value;
        }
        return this;
    }
    /**
     * 设置查询的列，如`columns('a','b','c')`
     * @param properties 各项列
     */
    columns(...properties) {
        if (properties != null) {
            for (const property of properties) {
                this.column(property);
            }
        }
        return this;
    }
    /**
     * 设置要排除的列
     * @param property
     */
    exclude(property) {
        if ((0, utils_1.isNotBlank)(property)) {
            // excludeColumns.add(rowMapColumnMapper.apply(property));
            this.excludeColumns.add(property);
        }
        return this;
    }
    /**
     * 设置查询的列，如`columns('a','b','c')`
     * @param properties 各项列
     */
    excludes(...properties) {
        if (properties != null) {
            for (const property of properties) {
                this.exclude(property);
            }
        }
        return this;
    }
    /**
     * 拼接`order by xxx asc/desc`
     * @param property 要排序的列
     * @param sort `asc`或`desc`
     */
    orderBy(property, sort = 'asc') {
        // this.orders.add(rowMapColumnMapper.apply(property) + ' ' + sort);
        this.orders.push(property + ' ' + sort);
        return this;
    }
    /**
     * 拼接`order by xxx desc`
     * @param property 要排序的列
     */
    orderByDesc(property) {
        return this.orderBy(property, 'desc');
    }
    /**
     * 拼接`group by`
     * @param properties 要分组的列
     */
    groupBy(...properties) {
        // this.groups.addAll(Arrays.stream(properties).map(rowMapColumnMapper).collect(Collectors.toList()));
        this.groups.push(...properties);
        return this;
    }
    /**
     * 执行插入,返回主键
     * @param data 各项列和值
     */
    async insert(data) {
        if (data != null) {
            const keys = Object.keys(data);
            for (const key of keys) {
                this._columns[key] = data[key];
            }
        }
        if (this.defaultPrimaryValue != null &&
            (0, utils_1.isBlank)((this._columns[this._primary] || '').toString())) {
            if (typeof this.defaultPrimaryValue === 'function') {
                this._columns[this._primary] = this.defaultPrimaryValue();
            }
            else {
                this._columns[this._primary] = this.defaultPrimaryValue;
            }
        }
        this.preHandle(model_1.SqlMode.INSERT);
        const entries = this.filterNotBlanks();
        if (entries.length === 0) {
            throw new core_1.MidwayCommonError('参数不能为空');
        }
        const builder = new utils_1.StringBuilder();
        builder.append('insert into ');
        builder.append(this.tableName);
        builder.append('(');
        builder.append(entries.map(v => v.key).join(','));
        // builder.append(StringUtils.join(entries.stream().map(Map.Entry::getKey).toArray(), ","));
        builder.append(') values (');
        builder.append(Array.from({ length: entries.length })
            .map(() => '?')
            .join(','));
        // builder.append(StringUtils.join(Collections.nCopies(entries.size(), "?"), ","));
        builder.append(')');
        // const value =this. sqlModule.insert(new BoundSql(runtimeContext, builder.toString(), entries.stream().map(Map.Entry::getValue).collect(Collectors.toList()), sqlModule), this.primary);
        const value = await this.sqlModule._insert(new BoundSql_1.BoundSql({
            sqlOrXml: builder.toString(),
            parameters: entries.map(v => v.value),
            sqlModule: this.sqlModule,
        }));
        if ((0, utils_1.isNotBlank)(this._primary)) {
            return this._columns[this._primary];
        }
        return value;
    }
    /**
     * 执行delete语句
     */
    async delete() {
        this.preHandle(model_1.SqlMode.DELETE);
        if (this.useLogic) {
            const dataMap = {
                [this.logicDeleteColumn]: this.logicDeleteValue,
            };
            return await this.update(dataMap);
        }
        if (this._where.isEmpty()) {
            throw new core_1.MidwayCommonError('delete语句不能没有条件');
        }
        const builder = new utils_1.StringBuilder();
        builder.append('delete from ');
        builder.append(this.tableName);
        builder.append(this._where.getSql());
        return await this.sqlModule._update(new BoundSql_1.BoundSql({
            sqlOrXml: builder.toString(),
            parameters: this._where.params,
            sqlModule: this.sqlModule,
        }));
    }
    /**
     * 保存到表中，当主键有值时则修改，否则插入
     * @param data 各项列和值
     * @param beforeQuery 是否根据id查询有没有数据
     */
    async save(data, beforeQuery) {
        if (arguments.length === 0) {
            data = null;
            beforeQuery = false;
        }
        else if (arguments.length === 1) {
            if (typeof data === 'boolean') {
                beforeQuery = data;
                data = null;
            }
            else {
                beforeQuery = false;
            }
        }
        if ((0, utils_1.isBlank)(this._primary)) {
            throw new core_1.MidwayCommonError('请设置主键');
        }
        if (data != null) {
            Object.keys(data).forEach(key => {
                this._columns[key] = data[key];
            });
        }
        let primaryValue = this._columns[this._primary] || '';
        if ((0, utils_1.isBlank)(primaryValue) && data != null) {
            primaryValue = data[this._primary] || '';
        }
        if (beforeQuery) {
            if ((0, utils_1.isNotBlank)(primaryValue)) {
                const params = [];
                params.push(primaryValue);
                // const count = this.sqlModule.selectInt(new BoundSql(runtimeContext, "select count(*) count from " + this.tableName + " where " + this.primary + " = ?", params, sqlModule));
                const count = await this.sqlModule._selectInt(new BoundSql_1.BoundSql({
                    sqlOrXml: 'select count(*) count from ' +
                        this.tableName +
                        ' where ' +
                        this.primary +
                        ' = ?',
                    parameters: params,
                    sqlModule: this.sqlModule,
                }));
                if (count == 0) {
                    return await this.insert(data);
                }
                return await this.update(data);
            }
            else {
                return await this.insert(data);
            }
        }
        if ((0, utils_1.isNotBlank)(primaryValue)) {
            return await this.update(data);
        }
        return await this.insert(data);
    }
    /**
     * 执行分页查询，分页条件手动传入
     * @param limit 限制条数
     * @param offset 跳过条数
     */
    async page(limit, offset) {
        this.preHandle(model_1.SqlMode.PAGE);
        return await this.sqlModule._page(this.buildSelect(), new model_1.Page(limit, offset));
    }
    /**
     * 执行update语句
     * @param data 各项列和值
     * @param isUpdateBlank 是否更新空值字段
     */
    async update(data, isUpdateBlank) {
        if (null != data) {
            Object.keys(data).forEach(key => {
                this._columns[key] = data[key];
            });
        }
        this.preHandle(model_1.SqlMode.UPDATE);
        let primaryValue = null;
        if ((0, utils_1.isNotBlank)(this._primary)) {
            primaryValue = this._columns[this._primary];
            delete this._columns[this._primary];
        }
        if (isUpdateBlank != null) {
            this._withBlank = isUpdateBlank;
        }
        const entries = this.filterNotBlanks();
        if (entries.length === 0) {
            throw new core_1.MidwayCommonError('要修改的列不能为空');
        }
        const builder = new utils_1.StringBuilder();
        builder.append('update ');
        builder.append(this.tableName);
        builder.append(' set ');
        const params = [];
        for (let i = 0, size = entries.length; i < size; i++) {
            const entry = entries[i];
            builder.append(entry.key).append(' = ?');
            params.push(entry.value);
            if (i + 1 < size) {
                builder.append(',');
            }
        }
        if (!this._where.isEmpty()) {
            builder.append(this._where.getSql());
            params.push(...this._where.params);
        }
        else if (primaryValue != null) {
            builder.append(' where ').append(this._primary).append(' = ?');
            params.push(primaryValue);
        }
        else {
            throw new core_1.MidwayCommonError('主键值不能为空');
        }
        return await this.sqlModule._update(new BoundSql_1.BoundSql({
            sqlOrXml: builder.toString(),
            parameters: params,
            sqlModule: this.sqlModule,
        }));
    }
    /**
     * 查询条数
     */
    async count() {
        this.preHandle(model_1.SqlMode.COUNT);
        const builder = new utils_1.StringBuilder();
        builder.append('select count(1) from ').append(this.tableName);
        const params = this.buildWhere(builder);
        return await this.sqlModule._selectInt(new BoundSql_1.BoundSql({
            sqlOrXml: builder.toString(),
            parameters: params,
            sqlModule: this.sqlModule,
        }));
    }
    /**
     * 判断是否存在
     */
    async exists() {
        return (await this.count()) > 0;
    }
    /**
     * 查询List，并传入变量信息
     */
    async select() {
        this.preHandle(model_1.SqlMode.SELECT);
        return await this.sqlModule._select(this.buildSelect());
    }
    /**
     * 执行`selectOne`查询
     */
    async selectOne() {
        this.preHandle(model_1.SqlMode.SELECT_ONE);
        return await this.sqlModule._selectOne(this.buildSelect());
    }
    /**
     * 批量插入
     * @param collection 对象数据
     * @param batchSize 批量
     */
    async batchInsert(collection, batchSize = 100) {
        const _keys = [];
        collection.map(it => Object.keys(it)).forEach(it => _keys.push(...it));
        // Set<String> keys = collection.stream().flatMap(it -> it.keySet().stream()).collect(Collectors.toSet());
        const keys = [...new Set(_keys)];
        if (keys.length === 0) {
            throw new core_1.MidwayCommonError('要插入的列不能为空');
        }
        const builder = new utils_1.StringBuilder();
        builder.append('insert into ');
        builder.append(this.tableName);
        builder.append('(');
        // builder.append(StringUtils.join(keys.stream().map(rowMapColumnMapper).collect(Collectors.toList()), ","));
        builder.append(keys.join(','));
        builder.append(') values (');
        builder.append(Array.from({ length: keys.length })
            .map(() => '?')
            .join(','));
        // builder.append(StringUtils.join(Collections.nCopies(keys.size(), "?"), ","));
        builder.append(')');
        // return this.sqlModule.batchUpdate(builder.toString(), batchSize, collection.stream()
        //   .map(it -> keys.stream().map(it::get).toArray())
        //   .collect(Collectors.toList()));
        return await this.sqlModule.batchUpdate(builder.toString(), collection.map(it => Object.values(it)), batchSize);
    }
    buildSelect() {
        const builder = new utils_1.StringBuilder();
        builder.append('select ');
        const fields = this.fields.filter(it => !this.excludeColumns.has(it));
        if (fields.length === 0) {
            builder.append('*');
        }
        else {
            builder.append(fields.join(','));
        }
        builder.append(' from ').append(this.tableName);
        const params = this.buildWhere(builder);
        if (this.groups.length > 0) {
            builder.append(' group by ');
            builder.append(this.groups.join(','));
        }
        if (this.orders.length > 0) {
            builder.append(' order by ');
            builder.append(this.orders.join(','));
        }
        const boundSql = new BoundSql_1.BoundSql({
            sqlOrXml: builder.toString(),
            parameters: params,
            sqlModule: this.sqlModule,
        });
        // BoundSql boundSql = new BoundSql(runtimeContext, builder.toString(), params, sqlModule);
        boundSql.excludeColumns = this.excludeColumns;
        return boundSql;
    }
    buildWhere(builder) {
        const params = [];
        if (!this._where.isEmpty()) {
            this._where.and();
            this._where.ne(this.useLogic, this.logicDeleteColumn, this.logicDeleteValue);
            builder.append(this._where.getSql());
            params.push(...this._where.params);
        }
        else if (this.useLogic) {
            this._where.ne(this.logicDeleteColumn, this.logicDeleteValue);
            builder.append(this._where.getSql());
            params.push(...this._where.params);
        }
        return params;
    }
    filterNotBlanks() {
        if (this._withBlank) {
            return Object.keys(this._columns)
                .filter(key => !this.excludeColumns.has(key))
                .map(key => ({
                key,
                value: this._columns[key],
            }));
        }
        return Object.keys(this._columns)
            .filter(key => (0, utils_1.isNotBlank)(this._columns[key] ? this._columns[key].toString() : ''))
            .filter(key => !this.excludeColumns.has(key))
            .map(key => ({
            key,
            value: this._columns[key],
        }));
    }
    preHandle(sqlMode) {
        if (this.namedTableInterceptors != null) {
            this.namedTableInterceptors.forEach(interceptor => interceptor.preHandle(sqlMode, this, this.sqlModule.ctx));
        }
    }
}
exports.NamedTable = NamedTable;
//# sourceMappingURL=NamedTable.js.map