{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://gmr.github.io/pglifecycle/schemata/procedure.json",
  "title": "Procedure",
  "description": "Defines a procedure (CREATE PROCEDURE), which CALL invokes and which returns no value",
  "type": "object",
  "properties": {
    "schema": {
      "title": "Schema",
      "description": "The schema the procedure is created in",
      "type": "string"
    },
    "name": {
      "title": "Name",
      "description": "The procedure name",
      "type": "string"
    },
    "owner": {
      "title": "Owner",
      "description": "The role that owns the procedure",
      "type": "string"
    },
    "sql": {
      "title": "SQL Statement",
      "description": "User-provided raw SQL snippet",
      "type": "string"
    },
    "parameters": {
      "title": "Function Parameters",
      "description": "An array of IN, OUT, BOTH, VARADIC, and TABLE args",
      "type": "array",
      "items": {
        "title": "Parameter",
        "type": "object",
        "properties": {
          "mode": {
            "title": "Parameter Mode",
            "type": "string",
            "enum": [
              "IN",
              "OUT",
              "INOUT",
              "VARIADIC",
              "TABLE"
            ]
          },
          "name": {
            "title": "Parameter Name",
            "type": "string"
          },
          "data_type": {
            "title": "Parameter Data Type",
            "type": "string"
          },
          "default": {
            "title": "Default value for Paramter",
            "oneOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              },
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ]
          }
        },
        "additionalProperties": false,
        "required": [
          "mode",
          "data_type"
        ]
      }
    },
    "language": {
      "title": "Language",
      "description": "The name of the language that the procedure is implemented in. It can be\nsql, c, internal, or the name of a user-defined procedural language,\ne.g. plpgsql.\n",
      "type": "string"
    },
    "transform_types": {
      "title": "Transform Types",
      "description": "Lists which transforms a call to the procedure should apply.",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "security": {
      "title": "Security",
      "description": "INVOKER indicates that the procedure is to be executed with the privileges of the user that calls it. That is the default. DEFINER specifies that the function is to be executed with the privileges of the user that owns it.\n",
      "enum": [
        "INVOKER",
        "DEFINER"
      ]
    },
    "configuration": {
      "title": "Configuration Parameters",
      "description": "Configuration parameters to be set to the specified value when the procedure is entered, and then restored to its prior value when the procedure exits. A value is a string, a number or a boolean. A setting that PostgreSQL keeps as a list of names, such as search_path, is a list of strings, one name for each item. For such a setting, one string with a comma is an error, because PostgreSQL reads it as one name. A list has at least one item.\n",
      "type": "object",
      "propertyNames": {
        "pattern": "^[A-Za-z_][A-Za-z0-9_\\.]*$"
      },
      "additionalProperties": {
        "oneOf": [
          {
            "type": [
              "string",
              "number",
              "boolean"
            ]
          },
          {
            "type": "array",
            "minItems": 1,
            "items": {
              "type": "string"
            }
          }
        ]
      }
    },
    "definition": {
      "title": "Function Definition",
      "description": "A string constant defining the procedure; the meaning depends on the language. It can be an internal procedure name, the path to an object file, an SQL command, or text in a procedural language.\n",
      "type": "string"
    },
    "sql_body": {
      "title": "SQL-Standard Body",
      "description": "A body written in SQL-standard form, `BEGIN ATOMIC ... END`, in place of `definition`; the statements are parsed when the procedure is created.\n",
      "type": "string"
    },
    "object_file": {
      "title": "Object File",
      "description": "Used for dynamically loadable C language functions when the procedure name in the C language source code is not the same as the name of the SQL function.\n",
      "type": "string"
    },
    "link_symbol": {
      "title": "Link Symbol",
      "description": "The string link_symbol is the procedure's link symbol when used in conjunction with object_file, that is, the name of the procedure in the C language source code. If the link symbol is omitted, it is assumed to be the same as the name of the SQL function being defined. The C names of all functions must be different, so you must give overloaded C functions different C names (for example, use the argument types as part of the C names).\n",
      "type": "string"
    },
    "comment": {
      "title": "Comment",
      "description": "An optional comment about the procedure",
      "type": "string"
    },
    "security_labels": {
      "title": "Security Labels",
      "description": "The security labels of an object (`SECURITY LABEL FOR provider ON ... IS 'label'`), as the label of each provider: the key is the name of the label provider, and the value is the label. A label applies only when its provider is loaded in the server, for example with `shared_preload_libraries`.\nWith no `security_labels`, the project does not manage the labels of the object, and deploy leaves them as the database has them. With the field, the object has exactly the labels that it lists, thus an empty map removes all of them.\n",
      "type": "object",
      "additionalProperties": {
        "type": "string"
      }
    },
    "dependencies": {
      "title": "Dependencies",
      "description": "Objects this object depends on, for the cases the dependency graph cannot infer: an ordering the topological sort would otherwise get wrong, such as a table that a view reads, or a function that a SQL-standard function body calls. A foreign key needs no entry: the build adds each foreign key after all tables.\nEach entry names an object as `schema.name`, or unqualified for a schemaless type. A function or aggregate carries the argument types of one overload (`test.f(integer)`, or `test.agg(*)` for an aggregate with no arguments), and an operator its left and right argument types (`test.=~=(integer, integer)`), since overloads share a name, and a cast its types (`(int4 AS timestamp)`). The argument types compare as PostgreSQL resolves them. A bare function, aggregate or operator name is correct only when one overload has it.\n",
      "type": "object",
      "properties": {
        "aggregates": {
          "description": "The aggregates this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "collations": {
          "description": "The collations this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "domains": {
          "description": "The domains this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "event_triggers": {
          "description": "The event triggers this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "extensions": {
          "description": "The extensions this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "foreign_data_wrappers": {
          "description": "The foreign data wrappers this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "functions": {
          "description": "The functions this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "languages": {
          "description": "The languages this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "materialized_views": {
          "description": "The materialized views this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "operators": {
          "description": "The operators this object depends on, each with its left and right argument types (`test.=~=(integer, integer)`, or `test.!!!(NONE, integer)` for a prefix operator).\n",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "publications": {
          "description": "The publications this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "sequences": {
          "description": "The sequences this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "servers": {
          "description": "The servers this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "subscriptions": {
          "description": "The subscriptions this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "tables": {
          "description": "The tables this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "types": {
          "description": "The types this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "user_mappings": {
          "description": "The user mappings this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "users": {
          "description": "The users this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "views": {
          "description": "The views this object depends on.",
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "additionalProperties": false
    }
  },
  "additionalProperties": false,
  "required": [
    "schema",
    "name"
  ],
  "oneOf": [
    {
      "required": [
        "language",
        "definition"
      ],
      "not": {
        "anyOf": [
          {
            "required": [
              "sql"
            ]
          },
          {
            "required": [
              "sql_body"
            ]
          },
          {
            "required": [
              "object_file"
            ]
          }
        ]
      }
    },
    {
      "required": [
        "language",
        "sql_body"
      ],
      "not": {
        "anyOf": [
          {
            "required": [
              "sql"
            ]
          },
          {
            "required": [
              "definition"
            ]
          },
          {
            "required": [
              "object_file"
            ]
          }
        ]
      }
    },
    {
      "required": [
        "language",
        "object_file"
      ],
      "not": {
        "anyOf": [
          {
            "required": [
              "sql"
            ]
          },
          {
            "required": [
              "definition"
            ]
          },
          {
            "required": [
              "sql_body"
            ]
          }
        ]
      }
    },
    {
      "required": [
        "sql"
      ],
      "not": {
        "anyOf": [
          {
            "required": [
              "language"
            ]
          },
          {
            "required": [
              "definition"
            ]
          },
          {
            "required": [
              "sql_body"
            ]
          }
        ]
      }
    }
  ]
}