"use strict";
var __spreadArrays = (this && this.__spreadArrays) || function () {
    for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
    for (var r = Array(s), k = 0, i = 0; i < il; i++)
        for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
            r[k] = a[j];
    return r;
};
exports.__esModule = true;
exports.grpcSchema = exports.grpcTypes = exports.searchMessage = void 0;
var const_1 = require("../const");
var utils_1 = require("../utils");
exports.searchMessage = function (ResourceName) { return [
    "repeated " + ResourceName + " data",
    "optional int32 count",
]; };
exports.grpcTypes = function (_a) {
    var dbResources = _a.dbResources, toProtoScalar = _a.toProtoScalar, Resources = _a.Resources, supportsReturn = _a.supportsReturn, permissions = _a.permissions;
    var resources = Object.fromEntries(Resources);
    var messages = {};
    var services = [];
    for (var _i = 0, _b = Object.keys(dbResources); _i < _b.length; _i++) {
        var name = _b[_i];
        var allow = utils_1.permitted(permissions);
        var permit = {
            create: allow(name, "create"),
            read: allow(name, "read"),
            update: allow(name, "update"),
            "delete": allow(name, "delete"),
            any: true
        };
        permit.any = permit.create || permit.read || permit.update || permit["delete"];
        var report = resources[name].report;
        var hasGeoQueryType = report.search &&
            !!Object.values(report.search).filter(function (_a) {
                var geoqueryType = _a.geoqueryType;
                return !!geoqueryType;
            }).length;
        var ResourceName = utils_1.transformNameforResolver(name);
        messages["resSearch" + ResourceName] = exports.searchMessage(ResourceName);
        messages["resCreate" + ResourceName] = [exports.searchMessage(ResourceName)[0]]; // omit the count
        messages["" + ResourceName] = [];
        messages["keys" + ResourceName] = [];
        messages["in" + ResourceName] = [];
        messages["in_arr_" + ResourceName] = [];
        messages["in_range" + ResourceName] = [];
        if (hasGeoQueryType) {
            messages["st_" + ResourceName] = [];
        }
        messages["input" + ResourceName] = [];
        for (var _c = 0, _d = Object.entries(dbResources[name]); _c < _d.length; _c++) {
            var _e = _d[_c], field = _e[0], record = _e[1];
            var notnull = record.notnull, type = record.type, primarykey = record.primarykey;
            var schemaScalar = toProtoScalar(type);
            // the check for the search -> field is needed because of config `redactedFields`
            var geoType = !!(report.search[field] && report.search[field].geoqueryType);
            messages["in" + ResourceName].push("optional " + schemaScalar + " " + field);
            messages["in_arr_" + ResourceName].push("repeated " + schemaScalar + " " + field);
            if (schemaScalar !== "Boolean") {
                messages["in_range" + ResourceName].push("repeated " + (schemaScalar === "string" ? "string" : "float") + " " + field);
            }
            if (hasGeoQueryType && geoType) {
                messages["st_" + ResourceName] = __spreadArrays(messages["st_" + ResourceName], [
                    "optional st_radius radius_" + field,
                    "optional st_bbox bbox_" + field,
                    "optional string polygon_" + field,
                ]);
            }
            messages["" + ResourceName].push((notnull ? "required" : "optional") + " " + schemaScalar + " " + field);
            // json as input should be a sting to get validated and stored correctly
            messages["input" + ResourceName].push("optional " + (schemaScalar === "google.protobuf.Struct" ? "string" : schemaScalar) + " " + field);
            if (primarykey) {
                messages["keys" + ResourceName].push("required " + schemaScalar + " " + field);
            }
        }
        var spatialType = function (st) { return function (str) {
            return st || !str.endsWith("geo");
        }; };
        var searchInterfaces = [
            "optional in" + ResourceName + " equal",
            "optional in" + ResourceName + " gt",
            "optional in" + ResourceName + " gte",
            "optional in" + ResourceName + " lt",
            "optional in" + ResourceName + " lte",
            "optional in" + ResourceName + " not",
            "optional in" + ResourceName + " like",
            "optional in" + ResourceName + " null",
            "optional in" + ResourceName + " not_null",
            // accept multiple values
            "optional in_arr_" + ResourceName + " in",
            "optional in_arr_" + ResourceName + " not_in",
            // accept DEFINED multiple values {object keys}
            "optional in_range" + ResourceName + " range",
            "optional in_range" + ResourceName + " not_range",
            // accept DEFINED multiple values of DEFINED type
            "optional st_" + ResourceName + " geo",
        ].filter(spatialType(hasGeoQueryType));
        messages["search" + ResourceName] = searchInterfaces;
        if (permit.read) {
            messages["args_search_" + ResourceName] = [
                "optional search" + ResourceName + " payload",
                "optional inputContext context",
                "optional serviceInputOptions options",
            ];
            var subResourceName = ResourceName.includes(const_1.COMPLEX_RESOLVER_SEPERATOR)
                ? ResourceName.split(const_1.COMPLEX_RESOLVER_SEPERATOR)[1]
                : undefined;
            if (subResourceName) {
                messages["args_search_" + ResourceName].push("optional search" + subResourceName + " subquery");
            }
            services.push("rpc Search" + ResourceName + "(args_search_" + ResourceName + ") returns (resSearch" + ResourceName + ")");
        }
        if (permit.create) {
            // TODO: can also skip defining the response since it wont be used
            var createResponse = !supportsReturn
                ? "NonReturningSuccessResponse"
                : "resCreate" + ResourceName;
            services.push("rpc Create" + ResourceName + "(args_create_" + ResourceName + ") returns (" + createResponse + ")");
            messages["args_create_" + ResourceName] = [
                "repeated input" + ResourceName + " payload",
            ];
        }
        var keys = Object.values(dbResources[name]).filter(function (item) { return item.primarykey; });
        // these types if resource is keyed. else delete related defined types
        if (keys.length) {
            if (permit.read) {
                services.push("rpc Read" + ResourceName + "(keys" + ResourceName + ") returns (" + ResourceName + ")");
            }
            if (permit.update) {
                // TODO: can also skip defining the response since it wont be used
                var updateResponse = !supportsReturn
                    ? "NonReturningSuccessResponse"
                    : "" + ResourceName;
                messages["args_update_" + ResourceName] = [
                    "required keys" + ResourceName + " keys",
                    "required input" + ResourceName + " payload",
                ];
                services.push("rpc Update" + ResourceName + "(args_update_" + ResourceName + ") returns (" + updateResponse + ")");
            }
            if (permit["delete"]) {
                services.push("rpc Delete" + ResourceName + "(keys" + ResourceName + ") returns (res_float)");
            }
        }
        else {
            delete messages["keys" + ResourceName];
            delete messages["type resRead" + ResourceName];
            delete messages["type resUpdate" + ResourceName];
        }
    }
    return {
        messages: messages,
        services: services
    };
};
exports.grpcSchema = function (_a) {
    var dbResources = _a.dbResources, Resources = _a.Resources, toProtoScalar = _a.toProtoScalar, metadata = _a.metadata, supportsReturn = _a.supportsReturn, permissions = _a.permissions, AppShortName = _a.AppShortName;
    // append the complexQueries to the dbResources -- may need to move upstream. or maybe not as its just for the graphql
    Resources.forEach(function (_a) {
        var name = _a[0], Resource = _a[1];
        if (Resource.hasSubquery) {
            // append a record to `dbResources`
            dbResources[name] = dbResources[utils_1.getFirstIfSeperated(name)];
        }
    });
    var _b = exports.grpcTypes({
        dbResources: dbResources,
        toProtoScalar: toProtoScalar,
        Resources: Resources,
        supportsReturn: supportsReturn,
        permissions: permissions
    }), messages = _b.messages, services = _b.services;
    var items = Object.entries(messages).map(function (_a) {
        var name = _a[0], definition = _a[1];
        return "\n      message " + name + " {\n          " + (Array.isArray(definition)
            ? definition.map(utils_1.appendIndex).map(utils_1.appendSemicolon).join(const_1.NEW_LINE)
            : utils_1.appendSemicolon(definition)) + "\n      }\n    ";
    });
    // count
    messages.serviceInputOptions = ["required bool count"];
    // `optional serviceInputOptions options`,
    messages.servicePointGeometry = [
        "required string type",
        "required string coordinates",
    ];
    services.push("rpc service_healthz(no_args) returns (serviceAppHealthz)");
    var protoString = "\n\n      syntax = \"proto3\";\n\n      package service;\n\n      import \"google/protobuf/struct.proto\";\n\n      service " + AppShortName + " {\n        " + services.map(utils_1.appendSemicolon).join(const_1.NEW_LINE) + "\n      }\n\n      message no_args {\n\n      }\n\n      message res_float {\n        required float number = 1;\n      }\n\n\n      message serviceAppMetadata {\n        string appShortName = 1;\n        string title = 2;\n        string description = 3;\n        string termsOfService = 4;\n        string name = 5;\n        string email = 6;\n        string url = 7;\n        repeated string servers = 8;\n        string appName = 9;\n        string routerPrefix = 10;\n      }\n\n      message serviceAppDataBaseInfo {\n        string dialect = 1;\n        string version = 2;\n      }\n\n\n      message NonReturningSuccessResponse {\n        required bool success = 1;\n      }\n\n      message serviceAppHealthz {\n        required string serviceVersion = 1;\n        required float timestamp = 2;\n        required serviceAppMetadata metadata = 3;\n        required serviceAppDataBaseInfo db_info = 4;\n      }\n\n\n\n\n\n      message in_range_string {\n        required string min = 1;\n        required string max = 2;\n      }\n\n      message in_range_float {\n        required float min = 1;\n        required float max = 2;\n      }\n\n      message st_radius {\n        required float long = 1;\n        required float lat = 2;\n        required float meters = 3;\n      }\n\n      message st_bbox {\n        required float xMin = 1;\n        required float yMin = 2;\n        required float xMax = 3;\n        required float yMax = 4;\n      }\n\n      message inputContext {\n        optional string seperator = 1;\n        optional bool notWhere = 2;\n        optional string statementContext = 3;\n        optional string orderBy = 4;\n        optional float page = 5;\n        optional float limit = 6;\n        optional string fields = 7;\n        optional bool distinct = 8;\n      }\n\n\n      message serviceInputOptions {\n        optional bool count = 1;\n      }\n\n      message servicePointGeometry {\n        required string type = 1;\n        required string coordinates = 2;\n      }\n\n      " + items.join(const_1.NEW_LINE) + "\n\n    ";
    return {
        protoString: protoString
    };
};
//# sourceMappingURL=proto.js.map