{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://gmr.github.io/pglifecycle/schemata/foreign_key.json",
  "title": "Foreign Key",
  "description": "Defines a foreign key on a table",
  "type": "object",
  "properties": {
    "name": {
      "title": "Name",
      "description": "The foreign key name",
      "type": "string"
    },
    "sql": {
      "title": "SQL Statement",
      "description": "User-provided raw SQL snippet",
      "type": "string"
    },
    "columns": {
      "title": "Columns",
      "description": "The columns in the table that the foreign key enforces the value of",
      "type": "array",
      "items": {
        "title": "Column Name",
        "type": "string"
      },
      "minItems": 1
    },
    "references": {
      "title": "Referenced Table",
      "description": "Defines the information about the foreign key table and columns",
      "type": "object",
      "properties": {
        "name": {
          "title": "Name",
          "description": "The name of the foreign key table",
          "type": "string"
        },
        "columns": {
          "title": "Columns",
          "description": "The columns in the table in the foreign key table",
          "type": "array",
          "items": {
            "title": "Column Name",
            "type": "string"
          },
          "minItems": 1
        },
        "period": {
          "title": "Period Column",
          "description": "The range column named after PERIOD in a temporal foreign key (PostgreSQL 18+), on the referenced side.\n",
          "type": "string"
        }
      },
      "additionalProperties": false,
      "required": [
        "name",
        "columns"
      ]
    },
    "match_type": {
      "title": "Match Type",
      "description": "A value inserted into the referencing column(s) is matched against the values of the referenced table and referenced columns using the given match type. There are three match types: FULL, PARTIAL, and SIMPLE (which is the default). FULL will not allow one column of a multicolumn foreign key to be null unless all foreign key columns are null; if they are all null, the row is not required to have a match in the referenced table. SIMPLE allows any of the foreign key columns to be null; if any of them are null, the row is not required to have a match in the referenced table. PARTIAL is not yet implemented.\n",
      "enum": [
        "FULL",
        "PARTIAL",
        "SIMPLE"
      ]
    },
    "on_delete": {
      "title": "On Delete",
      "description": "Action to take on delete of the column value in the referenced table",
      "enum": [
        "NO ACTION",
        "RESTRICT",
        "CASCADE",
        "SET NULL",
        "SET DEFAULT"
      ]
    },
    "on_update": {
      "title": "On Update",
      "description": "Action to take on update of the column value in the referenced table",
      "enum": [
        "NO ACTION",
        "RESTRICT",
        "CASCADE",
        "SET NULL",
        "SET DEFAULT"
      ]
    },
    "deferrable": {
      "title": "Deferrable",
      "description": "This controls whether the constraint can be deferred. A constraint that is not deferrable will be checked immediately after every command.\n",
      "type": "boolean"
    },
    "initially_deferred": {
      "title": "Initial Constraint Check Behavior",
      "type": "boolean"
    },
    "period": {
      "title": "Period Column",
      "description": "The range column named after PERIOD in a temporal foreign key (PostgreSQL 18+), on the referencing side. Both sides must name one.\n",
      "type": "string"
    },
    "enforced": {
      "title": "Enforced",
      "description": "false renders NOT ENFORCED (PostgreSQL 18+), which stops the constraint being checked. PostgreSQL records a not-enforced constraint as not validated as well. Absent means enforced, the default.\n",
      "type": "boolean"
    },
    "not_valid": {
      "title": "Not Valid",
      "description": "true renders NOT VALID: rows already in the table were never checked, only new ones are. The state holds only when the constraint is added with ALTER TABLE, so the build writes it that way. Absent means valid, the default.\n",
      "type": "boolean"
    }
  },
  "additionalProperties": false,
  "dependentSchemas": {
    "period": {
      "required": [
        "references"
      ],
      "properties": {
        "references": {
          "required": [
            "period"
          ]
        }
      }
    }
  },
  "if": {
    "required": [
      "references"
    ],
    "properties": {
      "references": {
        "required": [
          "period"
        ]
      }
    }
  },
  "then": {
    "required": [
      "period"
    ]
  },
  "oneOf": [
    {
      "required": [
        "sql"
      ],
      "not": {
        "required": [
          "columns",
          "references",
          "on_delete",
          "on_update",
          "deferrable",
          "initially_deferred"
        ]
      }
    },
    {
      "required": [
        "columns"
      ],
      "not": {
        "required": [
          "sql"
        ]
      }
    }
  ]
}