"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.deleteField = exports.updateField = exports.createField = exports.readOne = exports.readAll = exports.fieldsInCollection = void 0;
const database_1 = __importStar(require("../database"));
const lodash_1 = require("lodash");
const ItemsService = __importStar(require("../services/items"));
const get_local_type_1 = __importDefault(require("../utils/get-local-type"));
const exceptions_1 = require("../exceptions");
exports.fieldsInCollection = (collection) => __awaiter(void 0, void 0, void 0, function* () {
    const [fields, columns] = yield Promise.all([
        database_1.default.select('field').from('directus_fields').where({ collection }),
        database_1.schemaInspector.columns(collection),
    ]);
    return lodash_1.uniq([...fields.map(({ field }) => field), ...columns.map(({ column }) => column)]);
});
/**
 * @TODO
 * update read to use ItemsService instead of direct to db
 */
exports.readAll = (collection) => __awaiter(void 0, void 0, void 0, function* () {
    const fieldsQuery = database_1.default.select('*').from('directus_fields');
    if (collection) {
        fieldsQuery.where({ collection });
    }
    const [columns, fields] = yield Promise.all([
        database_1.schemaInspector.columnInfo(collection),
        fieldsQuery,
    ]);
    return columns.map((column) => {
        const field = fields.find((field) => field.field === column.name && field.collection === column.table);
        const data = {
            collection: column.table,
            field: column.name,
            type: column ? get_local_type_1.default(column.type) : 'alias',
            database: column,
            system: field || null,
        };
        return data;
    });
});
/** @todo add accountability */
exports.readOne = (collection, field, accountability) => __awaiter(void 0, void 0, void 0, function* () {
    let column;
    const fieldInfo = yield database_1.default
        .select('*')
        .from('directus_fields')
        .where({ collection, field })
        .first();
    try {
        column = yield database_1.schemaInspector.columnInfo(collection, field);
    }
    catch (_a) { }
    const data = {
        collection,
        field,
        type: column ? get_local_type_1.default(column.type) : 'alias',
        database: column || null,
        system: fieldInfo || null,
    };
    return data;
});
exports.createField = (collection, field, accountability) => __awaiter(void 0, void 0, void 0, function* () {
    /**
     * @todo
     * Check if table / directus_fields row already exists
     */
    if (field.database) {
        yield database_1.default.schema.alterTable(collection, (table) => {
            let column;
            if (!field.database)
                return;
            if (field.type === 'string') {
                column = table.string(field.field, field.database.max_length !== null ? field.database.max_length : undefined);
            }
            else if (['float', 'decimal'].includes(field.type)) {
                const type = field.type;
                /** @todo add precision and scale support */
                column = table[type](field.field /* precision, scale */);
            }
            else {
                column = table[field.type](field.field);
            }
            if (field.database.default_value) {
                column.defaultTo(field.database.default_value);
            }
            if (field.database.is_nullable && field.database.is_nullable === true) {
                column.nullable();
            }
            else {
                column.notNullable();
            }
        });
    }
    if (field.system) {
        yield ItemsService.createItem('directus_fields', Object.assign(Object.assign({}, field.system), { collection: collection, field: field.field }), accountability);
    }
});
exports.updateField = (collection, field, accountability) => __awaiter(void 0, void 0, void 0, function* () {
    if (field.database) {
        yield database_1.default.schema.alterTable(collection, (table) => {
            let column;
            if (!field.database)
                return;
            if (field.type === 'string') {
                column = table.string(field.field, field.database.max_length !== null ? field.database.max_length : undefined);
            }
            else if (['float', 'decimal'].includes(field.type)) {
                const type = field.type;
                /** @todo add precision and scale support */
                column = table[type](field.field /* precision, scale */);
            }
            else {
                column = table[field.type](field.field);
            }
            if (field.database.default_value) {
                column.defaultTo(field.database.default_value);
            }
            if (field.database.is_nullable && field.database.is_nullable === true) {
                column.nullable();
            }
            else {
                column.notNullable();
            }
            column.alter();
        });
    }
    if (field.system) {
        const record = yield database_1.default
            .select('id')
            .from('directus_fields')
            .where({ collection, field: field.field })
            .first();
        if (!record)
            throw new exceptions_1.FieldNotFoundException(collection, field.field);
        yield database_1.default('directus_fields')
            .update(field.system)
            .where({ collection, field: field.field });
    }
    return field.field;
});
/** @todo save accountability */
exports.deleteField = (collection, field, accountability) => __awaiter(void 0, void 0, void 0, function* () {
    yield database_1.default('directus_fields').delete().where({ collection, field });
    yield database_1.default.schema.table(collection, (table) => {
        table.dropColumn(field);
    });
});
