"use strict";
exports.__esModule = true;
exports.dialect = exports.toProtoScalar = exports.toSchemaScalar = exports.joiBase = void 0;
var Joi = require("joi");
var cnst = require(".././const");
// defintions based on psql 12 datatypes
// https://www.postgresql.org/docs/12/datatype.html
var geoPrefixes = [
    "geometry(Point",
    "geometry(Line",
    "geometry(MultiLineString",
    "geometry(Lseg",
    "geometry(Box",
    "geometry(Path",
    "geometry(Polygon",
    "geometry(MultiPolygon",
    "geometry(Circle",
];
var hasGeoPrefix = function (type) {
    return !!geoPrefixes.filter(function (geoPrefix) { return type.startsWith(geoPrefix); }).length;
};
/**
 * @description The idea is to assign joi validators with geo types based on db type prefix. Not yet implemented.
 * @param {string} type
 * @returns
 */
var joiGeoTypeByPrefix = function (type) {
    var _a, _b, _c, _d, _e, _f, _g;
    if (type.startsWith("geometry(Point")) {
        return (_a = Joi.string()).invalid.apply(_a, cnst.SYMBOLS_GEO_POINT);
    }
    else if (type.startsWith("geometry(Line") ||
        type.startsWith("geometry(MultiLineString")) {
        return (_b = Joi.string()).invalid.apply(_b, cnst.SYMBOLS_GEO_LINE);
    }
    else if (type.startsWith("geometry(Lseg")) {
        return (_c = Joi.string()).invalid.apply(_c, cnst.SYMBOLS_GEO_LSEG);
    }
    else if (type.startsWith("geometry(Box")) {
        return (_d = Joi.string()).invalid.apply(_d, cnst.SYMBOLS_GEO_BOX);
    }
    else if (type.startsWith("geometry(Path")) {
        return (_e = Joi.string()).invalid.apply(_e, cnst.SYMBOLS_GEO_PATH);
    }
    else if (type.startsWith("geometry(Polygon") ||
        type.startsWith("geometry(MultiPolygon")) {
        return (_f = Joi.string()).invalid.apply(_f, cnst.SYMBOLS_GEO_POLYGON);
    }
    else if (type.startsWith("geometry(Circle")) {
        return (_g = Joi.string()).invalid.apply(_g, cnst.SYMBOLS_GEO_CIRCLE);
    }
    return null;
};
exports.joiBase = function (type) {
    var _a, _b, _c, _d, _e, _f, _g;
    switch (type) {
        // 8.1. Numeric Types":
        case "smallint":
        case "integer":
            return Joi.number().integer();
        case "bigint":
        case "decimal":
        case "numeric":
        case "real":
        case "double precision":
            return Joi.string(); // string because of arbitrary presision that cannot be jsonified -- have special values (Infinity, -Infinity, NaN)
        case "smallserial":
        case "serial":
            return Joi.number().integer();
        case "bigserial":
            return Joi.string(); // string because of arbitrary presision
        case "int2":
        case "int4":
        case "int8":
            return Joi.number().integer();
        // 8.2. Monetary Types":
        case "money": // bigint in js
            return Joi.string(); // string as it is arbitrary length
        // 8.3. Character Types":
        // case "character varying(n)": // ignore. default will be string
        // case "varchar(n)": // ignore. default will be string
        // case "character(n)": // ignore. default will be string
        // case "char(n)": // ignore. default will be string
        case "character varying":
        case "text":
        case '"char"':
        case "name":
            return Joi.string();
        // 8.4. Binary Data Types":
        case "bytea":
            return Joi.string();
        // 8.5. Date/Time Types":
        // case "timestamp": tz optional // ignore. default will be string
        // case "timestamp": wtz // ignore. default will be string
        case "timestamp without time zone":
        case "date":
        // case "time": tz optional // ignore. default will be string
        // case "time": wtz // ignore. default will be string
        case "interval":
            return Joi.string();
        // 8.6. Boolean Type":
        case "boolean":
            return Joi.boolean();
        // 8.7. Enumerated Types":
        // ignore. default will be string
        // 8.8. Geometric Types":
        case "point":
        case "geometry(Point)":
            return (_a = Joi.string()).invalid.apply(_a, cnst.SYMBOLS_GEO_POINT);
        case "line":
        case "geometry(Line)":
        case "geometry(MultiLineString)":
            return (_b = Joi.string()).invalid.apply(_b, cnst.SYMBOLS_GEO_LINE);
        case "lseg":
        case "geometry(Lseg)":
            return (_c = Joi.string()).invalid.apply(_c, cnst.SYMBOLS_GEO_LSEG);
        case "box":
        case "geometry(Box)":
            return (_d = Joi.string()).invalid.apply(_d, cnst.SYMBOLS_GEO_BOX);
        case "path":
        case "geometry(Path)":
            return (_e = Joi.string()).invalid.apply(_e, cnst.SYMBOLS_GEO_PATH);
        case "polygon":
        case "geometry":
        case "geometry(Polygon)":
        case "geometry(MultiPolygon)":
            return (_f = Joi.string()).invalid.apply(_f, cnst.SYMBOLS_GEO_POLYGON);
        case "circle":
        case "geometry(Circle)":
            return (_g = Joi.string()).invalid.apply(_g, cnst.SYMBOLS_GEO_CIRCLE);
        // 8.9. Network Address Types":
        case "cidr":
        case "inet":
        case "macaddr":
            return Joi.string();
        // 8.10. Bit String Types":
        // case "bit(n)": // ignore. default will be string
        // case "bit varying(n)": // ignore. default will be string
        // 8.11. Text Search Types":
        // 8.11.1. tsvector":
        // 8.11.2. tsquery":
        // 8.12. UUID Type":
        case "uuid":
            return Joi.string();
        // 8.13. XML Type":
        case "xml":
            return Joi.string();
        // 8.14. JSON Types":
        case "json":
        case "jsonb":
        case "jsonpath":
            return Joi.string().invalid(cnst.SYMBOL_JSON); // will want to use JSONB on output
        // 8.15. Arrays":
        // ignore. default will be string
        // in the future -- breaking change will type
        // 8.16. Composite Types":
        // ignore. default will be string
        // 8.17. Range Types":
        case "int4range":
        case "int8range":
            return Joi.string();
        case "numrange":
        case "* float":
            return Joi.number();
        case "tsrange":
        case "tstzrange":
        case "daterange":
            return Joi.string();
        // 8.18. Domain Types": // ignore. let default catch it
        // 8.19. Object Identifier Types":
        case "oid":
            return Joi.number().integer();
        case "regproc":
        case "regprocedure":
        case "regoper":
        case "regoperator":
        case "regclass":
        case "regtype":
        case "regrole":
        case "regnamespace":
        case "regconfig":
        case "regdictionary":
            return Joi.string();
        // 8.20. pg_lsn Type":
        case "pg_lsn":
            return Joi.string();
        default:
            var match = type.match(cnst.REGEX_CHAR);
            if (match) {
                return Joi.string().max(Number(match.groups.len));
            }
            var geoType = joiGeoTypeByPrefix(type);
            if (geoType) {
                return geoType;
            }
            return Joi.string(); // string to support custom data types in the db & ignored char/text fields
    }
};
exports.toSchemaScalar = function (type) {
    switch (type) {
        // 8.1. Numeric Types":
        case "smallint":
        case "integer":
        case "bigint":
            return "Float";
        case "decimal":
        case "numeric":
        case "real":
        case "double precision":
            return "String"; // String because of arbitrary precision that cannot be jsonifieds
        case "smallserial":
        case "serial":
            return "Float";
        case "bigserial":
            return "String";
        case "int2":
        case "int4":
        case "int8":
            return "Float";
        // 8.2. Monetary Types":
        case "money || bigint in js":
            return "String"; // string as it is arbitrary length
        // 8.3. Character Types":
        // case "character varying(n)": // ignore. default will be string
        // case "varchar(n)": // ignore. default will be string
        // case "character(n)": // ignore. default will be string
        // case "char(n)": // ignore. default will be string
        case "character varying":
        case "text":
        case '"char"':
        case "name":
            return "String";
        // 8.4. Binary Data Types":
        case "bytea":
            return "String";
        // 8.5. Date/Time Types":
        // case "timestamp": tz optional // ignore. default will be string
        // case "timestamp": wtz // ignore. default will be string
        case "timestamp without time zone":
        case "date":
        // case "time": tz optional // ignore. default will be string
        // case "time": wtz // ignore. default will be string
        case "interval":
            return "String";
        // 8.6. Boolean Type":
        case "boolean":
            return "Boolean";
        // 8.7. Enumerated Types":
        // ignore. default will be string
        // 8.8. Geometric Types":
        case "point":
        case "geometry(Point)":
        case "line":
        case "geometry(Line)":
        case "geometry(MultiLineString)":
        case "lseg":
        case "geometry(Lseg)":
        case "box":
        case "geometry(Box)":
        case "path":
        case "geometry(Path)":
        case "polygon":
        case "geometry":
        case "geometry(Polygon)":
        case "geometry(MultiPolygon)":
        case "circle":
        case "geometry(Circle)":
            return "JSONB";
        // 8.9. Network Address Types":
        case "cidr":
        case "inet":
        case "macaddr":
            return "String";
        // 8.10. Bit String Types":
        // case "bit(n)": // ignore. default will be string
        // case "bit varying(n)": // ignore. default will be string
        //    return 'String';
        // 8.11. Text Search Types":
        // 8.11.1. tsvector":
        // 8.11.2. tsquery":
        // 8.12. UUID Type":
        case "uuid":
        case "string":
            return "String";
        // 8.13. XML Type":
        case "xml":
            return "String";
        // 8.14. JSON Types":
        case "json":
        case "jsonb":
        case "jsonpath":
            return "String"; // will want to use JSONB on output
        // 8.15. Arrays":
        // ignore. default will be string
        // in the future -- breaking change will type
        // 8.16. Composite Types":
        // ignore. default will be string
        // 8.17. Range Types":
        case "int4range":
        case "int8range":
            return "Float";
        case "numrange":
        case "* float":
            return "Float";
        case "tsrange":
        case "tstzrange":
        case "daterange":
            return "String";
        // 8.18. Domain Types": // ignore. let default catch it
        // 8.19. Object Identifier Types":
        case "oid":
            return "Float";
        case "regproc":
        case "regprocedure":
        case "regoper":
        case "regoperator":
        case "regclass":
        case "regtype":
        case "regrole":
        case "regnamespace":
        case "regconfig":
        case "regdictionary":
            return "String";
        // 8.20. pg_lsn Type":
        case "pg_lsn":
            return "String";
        default:
            if (hasGeoPrefix(type))
                return "JSONB";
            return "String";
    }
};
exports.toProtoScalar = function (type) {
    switch (type) {
        // 8.1. Numeric Types":
        case "smallint":
        case "integer":
            return "uint32";
        case "bigint":
        case "decimal":
        case "numeric":
        case "real":
        case "double precision":
            return "string"; // String because of arbitrary precision that cannot be jsonifieds
        case "smallserial":
        case "serial":
            return "uint32";
        case "bigserial":
            return "uint64";
        case "int2":
        case "int4":
        case "int8":
            return "sint32";
        // 8.2. Monetary Types":
        case "money": // bigint in js
            return "string"; // string as it is arbitrary length
        // 8.3. Character Types":
        // case "character varying(n)": // ignore. default will be string
        // case "varchar(n)": // ignore. default will be string
        // case "character(n)": // ignore. default will be string
        // case "char(n)": // ignore. default will be string
        case "character varying":
        case "text":
        case '"char"':
        case "name":
            return "string";
        // 8.4. Binary Data Types":
        case "bytea":
            return "string";
        // 8.5. Date/Time Types":
        // case "timestamp": tz optional // ignore. default will be string
        // case "timestamp": wtz // ignore. default will be string
        case "timestamp without time zone":
        case "date":
        // case "time": tz optional // ignore. default will be string
        // case "time": wtz // ignore. default will be string
        case "interval":
            return "string";
        // 8.6. Boolean Type":
        case "boolean":
            return "bool";
        // 8.7. Enumerated Types":
        // ignore. default will be string
        // 8.8. Geometric Types":
        case "point":
        case "geometry(Point)":
        case "line":
        case "geometry(Line)":
        case "geometry(MultiLineString)":
        case "lseg":
        case "geometry(Lseg)":
        case "box":
        case "geometry(Box)":
        case "path":
        case "geometry(Path)":
        case "polygon":
        case "geometry":
        case "geometry(Polygon)":
        case "geometry(MultiPolygon)":
        case "circle":
        case "geometry(Circle)":
            return "google.protobuf.Struct";
        // 8.9. Network Address Types":
        case "cidr":
        case "inet":
        case "macaddr":
            return "string";
        // 8.10. Bit String Types":
        // case "bit(n)": // ignore. default will be string
        // case "bit varying(n)": // ignore. default will be string
        //    return 'String';
        // 8.11. Text Search Types":
        // 8.11.1. tsvector":
        // 8.11.2. tsquery":
        // 8.12. UUID Type":
        case "uuid":
            return "string";
        // 8.13. XML Type":
        case "xml":
            return "string";
        // 8.14. JSON Types":
        case "json":
        case "jsonb":
        case "jsonpath":
            return "google.protobuf.Struct"; // will want to use JSONB on output
        // 8.15. Arrays":
        // ignore. default will be string
        // in the future -- breaking change will type
        // 8.16. Composite Types":
        // ignore. default will be string
        // 8.17. Range Types":
        case "int4range":
        case "int8range":
            return "string";
        case "numrange":
        case "* float":
            return "double";
        case "tsrange":
        case "tstzrange":
        case "daterange":
            return "string";
        // 8.18. Domain Types": // ignore. let default catch it
        // 8.19. Object Identifier Types":
        case "oid":
            return "uint32";
        case "regproc":
        case "regprocedure":
        case "regoper":
        case "regoperator":
        case "regclass":
        case "regtype":
        case "regrole":
        case "regnamespace":
        case "regconfig":
        case "regdictionary":
            return "string";
        // 8.20. pg_lsn Type":
        case "pg_lsn":
            return "string";
        default:
            if (hasGeoPrefix(type))
                return "google.protobuf.Struct";
            return "string";
    }
};
exports.dialect = function (_a) {
    var migrationTable = _a.migrationTable;
    var dbSurveyQuery = "\n      select distinct\n        resource_schema,\n        resource_type,\n        resource_name,\n        resource_column_id,\n        resource_column_name,\n        \"notnull\",\n        \"type\",\n        case\n          when primarykey >0 then true\n          else false\n        end as primarykey,\n        case\n          when uniquekey >0 then true\n          else false\n        end as uniquekey\n      from\n        (\n        select\n          \"oid\",\n          resource_schema,\n          resource_type,\n          resource_name,\n          resource_column_id,\n          resource_column_name,\n          \"notnull\",\n          \"type\",\n          max(primarykey) primarykey,\n          max(uniquekey) uniquekey\n        from\n          (\n            select\n              c.oid oid,\n              s.nspname resource_schema,\n              case\n                when c.relkind = 'r' then 'table'\n                when c.relkind = 'p' then 'partition'\n                when c.relkind = 'v' then 'view'\n                when c.relkind = 'm' then 'materialized view'\n                else 'unknown'\n              end as resource_type,\n              c.relname as resource_name,\n              a.attnum as resource_column_id,\n              a.attname as resource_column_name,\n              a.attnotnull as notnull,\n              pg_catalog.format_type(a.atttypid, a.atttypmod) as type,\n              case\n                when p.contype = 'p' then 1\n                else 0\n              end as primarykey,\n              case\n                when p.contype = 'u' then 1\n                else 0\n              end as uniquekey\n            from\n              pg_attribute a\n            join pg_class c on\n              c.oid = a.attrelid\n            join pg_namespace s on\n              c.relnamespace = s.oid\n            left join pg_attrdef d on\n              d.adrelid = c.oid\n              and d.adnum = a.attnum\n            left join pg_namespace n on\n              n.oid = c.relnamespace\n            left join pg_constraint p on\n              p.conrelid = c.oid\n              and a.attnum = any (p.conkey)\n            where\n              c.relkind in ('r', 'p', 'v', 'm') -- tables, views, materialized views\n              and a.attnum > 0\n              and not a.attisdropped\n              and s.nspname not in ('information_schema', 'pg_catalog')\n              and c.relname not in ('knex_migrations', 'knex_migrations_lock')\n              and c.relname not in ('" + migrationTable + "', '" + migrationTable + "_lock')\n            ) main\n        group by\n          \"oid\",\n          resource_schema,\n          resource_type,\n          resource_name,\n          resource_column_id,\n          resource_column_name,\n          \"notnull\",\n          \"type\"\n          ) base\n      order by\n        resource_schema,\n        resource_name,\n        resource_column_name;\n    ";
    var dbGeometryColumns = "\n    select\n      f_table_schema resource_schema,\n      f_table_name resource_name,\n      f_geometry_column resource_column_name,\n      srid,\n      \"type\"\n    FROM geometry_columns;\n  ";
    var versionQuery = "select version() as db_version;";
    return {
        dbSurveyQuery: dbSurveyQuery,
        versionQuery: versionQuery,
        joiBase: exports.joiBase,
        toSchemaScalar: exports.toSchemaScalar,
        toProtoScalar: exports.toProtoScalar,
        dbGeometryColumns: dbGeometryColumns
    };
};
//# sourceMappingURL=postgres.js.map