Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 57bbe11013 | |||
| 386b7ad012 | |||
| a91460b390 | |||
| 0017c598e1 |
35
GEMINI.md
35
GEMINI.md
@ -37,12 +37,12 @@ These functions operate on the global `GLOBAL_JSPG` engine instance and provide
|
|||||||
JSPG augments standard JSON Schema 2020-12 to provide an opinionated, strict, and highly ergonomic Object-Oriented paradigm. Developers defining Punc Data Models should follow these conventions.
|
JSPG augments standard JSON Schema 2020-12 to provide an opinionated, strict, and highly ergonomic Object-Oriented paradigm. Developers defining Punc Data Models should follow these conventions.
|
||||||
|
|
||||||
### Types of Types
|
### Types of Types
|
||||||
* **Table-Backed (Entity Types)**: Primarily defined in root type schemas. These represent physical Postgres tables.
|
* **Table-Backed (Entity Types)**: Primarily defined in root `types` schemas. These represent physical Postgres tables.
|
||||||
* They absolutely **require** an `$id`.
|
* They are implicitly registered in the Global Registry using their precise key name mapped from the database compilation phase.
|
||||||
* The schema conceptually requires a `type` discriminator at runtime so the engine knows what physical variation to interact with.
|
* The schema conceptually requires a `type` discriminator at runtime so the engine knows what physical variation to interact with.
|
||||||
* Can inherit other entity types to build lineage (e.g. `person` -> `organization` -> `entity`).
|
* Can inherit other entity types to build lineage (e.g. `person` -> `organization` -> `entity`) natively using the `type` property.
|
||||||
* **Field-Backed (JSONB Bubbles)**: These are shapes that live entirely inside a Postgres JSONB column without being tied to a top-level table constraint.
|
* **Field-Backed (JSONB Bubbles)**: These are shapes that live entirely inside a Postgres JSONB column without being tied to a top-level table constraint.
|
||||||
* **Global `$id` Promotion**: Utilizing explicit `$id` declarations promotes the schema to the Global Registry. This effectively creates strictly-typed code-generator universes (e.g., generating an `InvoiceNotificationMetadata` Dart class) operating cleanly inside unstructured Postgres JSONB columns.
|
* **Global Schema Registration**: Roots must be attached to the top-level keys mapped from the `types`, `enums`, or `puncs` database tables.
|
||||||
* They can re-use the standard `type` discriminator locally for `oneOf` polymorphism without conflicting with global Postgres Table constraints.
|
* They can re-use the standard `type` discriminator locally for `oneOf` polymorphism without conflicting with global Postgres Table constraints.
|
||||||
|
|
||||||
### Discriminators & The Dot Convention (A.B)
|
### Discriminators & The Dot Convention (A.B)
|
||||||
@ -50,30 +50,28 @@ In Punc, polymorphic targets like explicit tagged unions or STI (Single Table In
|
|||||||
|
|
||||||
**The 2-Tier Paradigm**: The system inherently prevents "God Tables" by restricting routing to exactly two dimensions, guaranteeing absolute $O(1)$ lookups without ambiguity:
|
**The 2-Tier Paradigm**: The system inherently prevents "God Tables" by restricting routing to exactly two dimensions, guaranteeing absolute $O(1)$ lookups without ambiguity:
|
||||||
1. **Vertical Routing (`type`)**: Identifies the specific Postgres Table lineage (e.g. `person` vs `organization`).
|
1. **Vertical Routing (`type`)**: Identifies the specific Postgres Table lineage (e.g. `person` vs `organization`).
|
||||||
2. **Horizontal Routing (`kind.type`)**: Natively evaluates Single Table Inheritance. The runtime dynamically concatenates `$kind.$type` to yield the namespace-protected schema `$id` (e.g. `light.person`), maintaining collision-free schema registration.
|
2. **Horizontal Routing (`kind.type`)**: Natively evaluates Single Table Inheritance. The runtime dynamically concatenates `$kind.$type` to yield the namespace-protected schema key (e.g. `light.person`), maintaining collision-free schema registration.
|
||||||
|
|
||||||
Therefore, any schema that participates in polymorphic discrimination MUST explicitly define its discriminator properties natively inside its `properties` block. However, to stay DRY and maintain flexible APIs, you **DO NOT** need to hardcode `const` values, nor should you add them to your `required` array. The Punc engine treats `type` and `kind` as **magic properties**.
|
Therefore, any schema that participates in polymorphic discrimination MUST explicitly define its discriminator properties natively inside its `properties` block. However, to stay DRY and maintain flexible APIs, you **DO NOT** need to hardcode `const` values, nor should you add them to your `required` array. The Punc engine treats `type` and `kind` as **magic properties**.
|
||||||
|
|
||||||
**Magic Validation Constraints**:
|
**Magic Validation Constraints**:
|
||||||
* **Dynamically Required**: The system inherently drives the need for their requirement. The Validator dynamically expects the discriminators and structurally bubbles `MISSING_TYPE` ultimata ONLY when a polymorphic router (`$family` / `oneOf`) dynamically requires them to resolve a path. You never manually put them in the JSON schema `required` block.
|
* **Dynamically Required**: The system inherently drives the need for their requirement. The Validator dynamically expects the discriminators and structurally bubbles `MISSING_TYPE` ultimata ONLY when a polymorphic router (`$family` / `oneOf`) dynamically requires them to resolve a path. You never manually put them in the JSON schema `required` block.
|
||||||
* **Implicit Resolution**: When wrapped in `$family` or `oneOf`, the polymorphic router can mathematically parse the schema `$id` (e.g. `light.person`) and natively validate that `type` equals `"person"` and `kind` equals `"light"`, bubbling `CONST_VIOLATED` if they mismatch, all without you ever hardcoding `const` limitations.
|
* **Implicit Resolution**: When wrapped in `$family` or `oneOf`, the polymorphic router can mathematically parse the schema key (e.g. `light.person`) and natively validate that `type` equals `"person"` and `kind` equals `"light"`, bubbling `CONST_VIOLATED` if they mismatch, all without you ever hardcoding `const` limitations.
|
||||||
* **Generator Explicitness**: Because Postgres is the Single Source of Truth, forcing the explicit definition in `properties` initially guarantees the downstream Dart/Go code generators observe the fields and can cleanly serialize them dynamically back to the server.
|
* **Generator Explicitness**: Because Postgres is the Single Source of Truth, forcing the explicit definition in `properties` initially guarantees the downstream Dart/Go code generators observe the fields and can cleanly serialize them dynamically back to the server.
|
||||||
|
|
||||||
For example, a schema representing `$id: "light.person"` must natively define its own structural boundaries:
|
For example, a schema registered under the exact key `"light.person"` inside the database registry must natively define its own structural boundaries:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"$id": "light.person",
|
|
||||||
"type": "person",
|
"type": "person",
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": { "type": "string" },
|
"type": { "type": "string" },
|
||||||
"kind": { "type": "string" }
|
"kind": { "type": "string" }
|
||||||
},
|
}
|
||||||
"required": ["type", "kind"]
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
* **The Object Contract (Presence)**: The Object enforces its own structural integrity mechanically. Standard JSON Validation natively ensures `type` and `kind` are present, bubbling `REQUIRED_FIELD_MISSING` organically if omitted.
|
* **The Object Contract (Presence)**: The Object enforces its own structural integrity mechanically. Standard JSON Validation natively ensures `type` and `kind` are dynamically present as expected.
|
||||||
* **The Dynamic Values (`db.types`)**: Because the `type` and `kind` properties technically exist, the Punc engine dynamically intercepts them during `validate_object`. It mathematically parses the schema `$id` (e.g. `light.person`) and natively validates that `type` equals `"person"` (or a valid descendant in `db.types`) and `kind` equals `"light"`, bubbling `CONST_VIOLATED` if they mismatch.
|
* **The Dynamic Values (`db.types`)**: Because the `type` and `kind` properties technically exist, the Punc engine dynamically intercepts them during `validate_object`. It mathematically parses the schema key (e.g. `light.person`) and natively validates that `type` equals `"person"` (or a valid descendant in `db.types`) and `kind` equals `"light"`, bubbling `CONST_VIOLATED` if they mismatch.
|
||||||
* **The Routing Contract**: When wrapped in `$family` or `oneOf`, the polymorphic router can execute Lightning Fast $O(1)$ fast-paths by reading the payload's `type`/`kind` identifiers, and gracefully fallback to standard structural failure if omitted.
|
* **The Routing Contract**: When wrapped in `$family` or `oneOf`, the polymorphic router can execute Lightning Fast $O(1)$ fast-paths by reading the payload's `type`/`kind` identifiers, and gracefully fallback to standard structural failure if omitted.
|
||||||
|
|
||||||
### Composition & Inheritance (The `type` keyword)
|
### Composition & Inheritance (The `type` keyword)
|
||||||
@ -97,7 +95,7 @@ Polymorphism is how an object boundary can dynamically take on entirely differen
|
|||||||
* *Options*: `person` -> `light.person`, `organization` -> `light.organization`. (If a projection like `light.bot` does not exist in `db.schemas`, it is safely ignored).
|
* *Options*: `person` -> `light.person`, `organization` -> `light.organization`. (If a projection like `light.bot` does not exist in `db.schemas`, it is safely ignored).
|
||||||
* **Scenario C: Single Table Inheritance (Horizontal Routing)**
|
* **Scenario C: Single Table Inheritance (Horizontal Routing)**
|
||||||
* *Setup*: `{ "$family": "widget" }` (Where `widget` is a table type but has no external variations).
|
* *Setup*: `{ "$family": "widget" }` (Where `widget` is a table type but has no external variations).
|
||||||
* *Execution*: The engine queries `db.types.get("widget").variations` and finds only `["widget"]`. Since it lacks table inheritance, it is treated as STI. The engine scans the specific, confined `schemas` array directly under `db.types.get("widget")` for any `$id` terminating in the base `.widget` (e.g., `stock.widget`). The `$family` automatically uses `kind` as the discriminator.
|
* *Execution*: The engine queries `db.types.get("widget").variations` and finds only `["widget"]`. Since it lacks table inheritance, it is treated as STI. The engine scans the specific, confined `schemas` array directly under `db.types.get("widget")` for any registered key terminating in the base `.widget` (e.g., `stock.widget`). The `$family` automatically uses `kind` as the discriminator.
|
||||||
* *Options*: `stock` -> `stock.widget`, `tasks` -> `tasks.widget`.
|
* *Options*: `stock` -> `stock.widget`, `tasks` -> `tasks.widget`.
|
||||||
|
|
||||||
* **`oneOf` (Strict Tagged Unions)**: A hardcoded list of candidate schemas. Unlike `$family` which relies on global DB metadata, `oneOf` forces pure mathematical structural evaluation of the provided candidates. It strictly bans typical JSON Schema "Union of Sets" fallback searches. Every candidate MUST possess a mathematically unique discriminator payload to allow $O(1)$ routing.
|
* **`oneOf` (Strict Tagged Unions)**: A hardcoded list of candidate schemas. Unlike `$family` which relies on global DB metadata, `oneOf` forces pure mathematical structural evaluation of the provided candidates. It strictly bans typical JSON Schema "Union of Sets" fallback searches. Every candidate MUST possess a mathematically unique discriminator payload to allow $O(1)$ routing.
|
||||||
@ -112,7 +110,6 @@ It evaluates as an **Independent Declarative Rules Engine**. Every `Case` block
|
|||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"$id": "save_external_account",
|
|
||||||
"cases": [
|
"cases": [
|
||||||
{
|
{
|
||||||
"when": {
|
"when": {
|
||||||
@ -171,10 +168,11 @@ When compiling nested object graphs or arrays, the JSPG engine must dynamically
|
|||||||
5. **Implicit Base Fallback (1:M)**: If no explicit prefix matches, and M:M deduction fails, the compiler filters for exactly one remaining relation with a `null` prefix (e.g. `fk_invoice_line_invoice` -> `prefix: null`). A `null` prefix mathematically denotes the core structural parent-child ownership edge and is used safely as a fallback.
|
5. **Implicit Base Fallback (1:M)**: If no explicit prefix matches, and M:M deduction fails, the compiler filters for exactly one remaining relation with a `null` prefix (e.g. `fk_invoice_line_invoice` -> `prefix: null`). A `null` prefix mathematically denotes the core structural parent-child ownership edge and is used safely as a fallback.
|
||||||
6. **Deterministic Abort**: If the engine exhausts all deduction pathways and the edge remains ambiguous, it explicitly aborts schema compilation (`returns None`) rather than silently generating unpredictable SQL.
|
6. **Deterministic Abort**: If the engine exhausts all deduction pathways and the edge remains ambiguous, it explicitly aborts schema compilation (`returns None`) rather than silently generating unpredictable SQL.
|
||||||
|
|
||||||
### Ad-Hoc Schema Promotion
|
### Subschema Promotion
|
||||||
To seamlessly support deeply nested, inline Object definitions that don't declare an explicit `$id`, JSPG aggressively promotes them to standalone topological entities during the database compilation phase.
|
To seamlessly support deeply nested Object and Array structures, JSPG aggressively promotes them to standalone topological entities during the database compilation phase.
|
||||||
* **Hash Generation:** While evaluating the unified graph, if the compiler enters an `Object` or `Array` structure completely lacking an `$id`, it dynamically calculates a localized hash alias representing exactly its structural constraints.
|
* **Path Generation:** While evaluating a unified graph originating from a base `types`, `enums`, or `puncs` key, the compiler tracks its exact path descent into nested objects and arrays. It dynamically calculates a localized alias string by appending a `/` pathing syntax (e.g., `base_schema_key/nested/path`) representing exactly its structural constraints.
|
||||||
* **Promotion:** This inline chunk is mathematically elevated to its own `$id` in the `db.schemas` cache registry. This guarantees that $O(1)$ WebSockets or isolated queries can natively target any arbitrary sub-object of a massive database topology directly without recursively re-parsing its parent's AST block every read.
|
* **Promotion:** This nested subschema chunk is mathematically elevated to its own independent key in the `db.schemas` cache registry using its full path. This guarantees that $O(1)$ WebSockets or isolated queries can natively target any arbitrary nested sub-object of a massive database topology directly without recursively re-parsing its parent's AST block every read. Note that you cannot use the `type` attribute to statically inherit from these automatically promoted subschemas.
|
||||||
|
* **Primitive Confinement:** Purely scalar or primitive branches (like `oneOf: [{type: "string"}, {type: "null"}]`) bypass global topological promotion. They are evaluated directly within the execution engine via isolated Tuple Indexes to explicitly protect the global DB Registry and Go Mixer from memory bloat.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -192,6 +190,7 @@ JSPG implements specific extensions to the Draft 2020-12 standard to support the
|
|||||||
* **Discriminator Fast Paths & Extraction**: When executing a polymorphic node (`oneOf` or `$family`), the engine statically analyzes the incoming JSON payload for the literal `type` and `kind` string coordinates. It routes the evaluation specifically to matching candidates in $O(1)$ while returning `MISSING_TYPE` ultimata directly.
|
* **Discriminator Fast Paths & Extraction**: When executing a polymorphic node (`oneOf` or `$family`), the engine statically analyzes the incoming JSON payload for the literal `type` and `kind` string coordinates. It routes the evaluation specifically to matching candidates in $O(1)$ while returning `MISSING_TYPE` ultimata directly.
|
||||||
* **Missing Type Ultimatum**: If an entity logically requires a discriminator and the JSON payload omits it, JSPG short-circuits branch execution entirely, bubbling a single, perfectly-pathed `MISSING_TYPE` error back to the UI natively to prevent confusing cascading failures.
|
* **Missing Type Ultimatum**: If an entity logically requires a discriminator and the JSON payload omits it, JSPG short-circuits branch execution entirely, bubbling a single, perfectly-pathed `MISSING_TYPE` error back to the UI natively to prevent confusing cascading failures.
|
||||||
* **Golden Match Context**: When exactly one structural candidate perfectly maps a discriminator, the Validator exclusively cascades that specific structural error context directly to the user, stripping away all noise generated by other parallel schemas.
|
* **Golden Match Context**: When exactly one structural candidate perfectly maps a discriminator, the Validator exclusively cascades that specific structural error context directly to the user, stripping away all noise generated by other parallel schemas.
|
||||||
|
* **Topological Array Pathing**: Instead of relying on explicit `$id` references or injected properties, array iteration paths are dynamically typed based on their compiler boundary constraints. If the array's `items` schema resolves to a topological table-backed entity (e.g., inheriting via a `$family` macro tracked in the global DB catalog), the array locks paths and derives element indexes from their actual UUID paths (`array/widget-1/name`), natively enforcing database continuity. If evaluating isolated ad-hoc JSONB elements, strict numeric indexing is enforced natively (`array/1/name`) preventing synthetic payload manipulation.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -2,9 +2,8 @@
|
|||||||
{
|
{
|
||||||
"description": "additionalProperties validates properties not matched by properties",
|
"description": "additionalProperties validates properties not matched by properties",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema1": {
|
||||||
"$id": "schema1",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {
|
"foo": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -17,7 +16,7 @@
|
|||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -62,8 +61,8 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true with additionalProperties still validates structure",
|
"description": "extensible: true with additionalProperties still validates structure",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"additionalProperties_1_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {
|
"foo": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -72,10 +71,9 @@
|
|||||||
"extensible": true,
|
"extensible": true,
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
|
||||||
"$id": "additionalProperties_1_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -108,9 +106,8 @@
|
|||||||
{
|
{
|
||||||
"description": "complex additionalProperties with object and array items",
|
"description": "complex additionalProperties with object and array items",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema3": {
|
||||||
"$id": "schema3",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -123,7 +120,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,11 +2,9 @@
|
|||||||
{
|
{
|
||||||
"description": "boolean schema 'true'",
|
"description": "boolean schema 'true'",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"booleanSchema_0_0": {}
|
||||||
"$id": "booleanSchema_0_0"
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -99,12 +97,11 @@
|
|||||||
{
|
{
|
||||||
"description": "boolean schema 'false'",
|
"description": "boolean schema 'false'",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"booleanSchema_1_0": {
|
||||||
"not": {},
|
"not": {}
|
||||||
"$id": "booleanSchema_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,87 +2,193 @@
|
|||||||
{
|
{
|
||||||
"description": "Multi-Paradigm Declarative Cases",
|
"description": "Multi-Paradigm Declarative Cases",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"parallel_rules": {
|
||||||
"$id": "parallel_rules",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"status": { "type": "string" },
|
"status": {
|
||||||
"kind": { "type": "string" }
|
"type": "string"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"cases": [
|
"cases": [
|
||||||
{
|
{
|
||||||
"when": { "properties": { "status": {"const": "unverified"} }, "required": ["status"] },
|
"when": {
|
||||||
|
"properties": {
|
||||||
|
"status": {
|
||||||
|
"const": "unverified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"status"
|
||||||
|
]
|
||||||
|
},
|
||||||
"then": {
|
"then": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"amount_1": {"type": "number"},
|
"amount_1": {
|
||||||
"amount_2": {"type": "number"}
|
"type": "number"
|
||||||
},
|
},
|
||||||
"required": ["amount_1", "amount_2"]
|
"amount_2": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"amount_1",
|
||||||
|
"amount_2"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"when": { "properties": { "kind": {"const": "credit"} }, "required": ["kind"] },
|
"when": {
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"const": "credit"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"kind"
|
||||||
|
]
|
||||||
|
},
|
||||||
"then": {
|
"then": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"cvv": {"type": "number"}
|
"cvv": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"required": ["cvv"]
|
"required": [
|
||||||
|
"cvv"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
"mutually_exclusive": {
|
||||||
"$id": "mutually_exclusive",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": { "type": "string" }
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"cases": [
|
"cases": [
|
||||||
{
|
{
|
||||||
"when": { "properties": { "type": {"const": "A"} }, "required": ["type"] },
|
"when": {
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "A"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
},
|
||||||
"then": {
|
"then": {
|
||||||
"properties": { "field_a": {"type": "number"} },
|
"properties": {
|
||||||
"required": ["field_a"]
|
"field_a": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"field_a"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"when": { "properties": { "type": {"const": "B"} }, "required": ["type"] },
|
"when": {
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"const": "B"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
},
|
||||||
"then": {
|
"then": {
|
||||||
"properties": { "field_b": {"type": "number"} },
|
"properties": {
|
||||||
"required": ["field_b"]
|
"field_b": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"field_b"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"else": {
|
"else": {
|
||||||
"properties": { "fallback_b": {"type": "number"} },
|
"properties": {
|
||||||
"required": ["fallback_b"]
|
"fallback_b": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"fallback_b"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
"nested_fallbacks": {
|
||||||
"$id": "nested_fallbacks",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"tier": { "type": "string" }
|
"tier": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"cases": [
|
"cases": [
|
||||||
{
|
{
|
||||||
"when": { "properties": { "tier": {"const": "1"} }, "required": ["tier"] },
|
"when": {
|
||||||
|
"properties": {
|
||||||
|
"tier": {
|
||||||
|
"const": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"tier"
|
||||||
|
]
|
||||||
|
},
|
||||||
"then": {
|
"then": {
|
||||||
"properties": { "basic": {"type": "number"} },
|
"properties": {
|
||||||
"required": ["basic"]
|
"basic": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"basic"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"else": {
|
"else": {
|
||||||
"cases": [
|
"cases": [
|
||||||
{
|
{
|
||||||
"when": { "properties": { "tier": {"const": "2"} }, "required": ["tier"] },
|
"when": {
|
||||||
|
"properties": {
|
||||||
|
"tier": {
|
||||||
|
"const": "2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"tier"
|
||||||
|
]
|
||||||
|
},
|
||||||
"then": {
|
"then": {
|
||||||
"properties": { "standard": {"type": "number"} },
|
"properties": {
|
||||||
"required": ["standard"]
|
"standard": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"standard"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"else": {
|
"else": {
|
||||||
"properties": { "premium": {"type": "number"} },
|
"properties": {
|
||||||
"required": ["premium"]
|
"premium": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"premium"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -90,91 +196,156 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
"missing_when": {
|
||||||
"$id": "missing_when",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"cases": [
|
"cases": [
|
||||||
{
|
{
|
||||||
"else": {
|
"else": {
|
||||||
"properties": { "unconditional": {"type": "number"} },
|
"properties": {
|
||||||
"required": ["unconditional"]
|
"unconditional": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"unconditional"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"description": "Fires only the first rule successfully",
|
"description": "Fires only the first rule successfully",
|
||||||
"data": { "status": "unverified", "amount_1": 1, "amount_2": 2 },
|
"data": {
|
||||||
|
"status": "unverified",
|
||||||
|
"amount_1": 1,
|
||||||
|
"amount_2": 2
|
||||||
|
},
|
||||||
"schema_id": "parallel_rules",
|
"schema_id": "parallel_rules",
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Fires both independent parallel rules flawlessly",
|
"description": "Fires both independent parallel rules flawlessly",
|
||||||
"data": { "status": "unverified", "kind": "credit", "amount_1": 1, "amount_2": 2, "cvv": 123 },
|
"data": {
|
||||||
|
"status": "unverified",
|
||||||
|
"kind": "credit",
|
||||||
|
"amount_1": 1,
|
||||||
|
"amount_2": 2,
|
||||||
|
"cvv": 123
|
||||||
|
},
|
||||||
"schema_id": "parallel_rules",
|
"schema_id": "parallel_rules",
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Catches errors triggered concurrently by multiple independent blocked rules",
|
"description": "Catches errors triggered concurrently by multiple independent blocked rules",
|
||||||
"data": { "status": "unverified", "kind": "credit" },
|
"data": {
|
||||||
|
"status": "unverified",
|
||||||
|
"kind": "credit"
|
||||||
|
},
|
||||||
"schema_id": "parallel_rules",
|
"schema_id": "parallel_rules",
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {
|
"expect": {
|
||||||
"success": false,
|
"success": false,
|
||||||
"errors": [
|
"errors": [
|
||||||
{ "code": "REQUIRED_FIELD_MISSING", "details": { "path": "amount_1" } },
|
{
|
||||||
{ "code": "REQUIRED_FIELD_MISSING", "details": { "path": "amount_2" } },
|
"code": "REQUIRED_FIELD_MISSING",
|
||||||
{ "code": "REQUIRED_FIELD_MISSING", "details": { "path": "cvv" } }
|
"details": {
|
||||||
|
"path": "amount_1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "REQUIRED_FIELD_MISSING",
|
||||||
|
"details": {
|
||||||
|
"path": "amount_2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "REQUIRED_FIELD_MISSING",
|
||||||
|
"details": {
|
||||||
|
"path": "cvv"
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "STRICT_PROPERTY_VIOLATION throws if an un-triggered then property is submitted",
|
"description": "STRICT_PROPERTY_VIOLATION throws if an un-triggered then property is submitted",
|
||||||
"data": { "status": "verified", "cvv": 123 },
|
"data": {
|
||||||
|
"status": "verified",
|
||||||
|
"cvv": 123
|
||||||
|
},
|
||||||
"schema_id": "parallel_rules",
|
"schema_id": "parallel_rules",
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {
|
"expect": {
|
||||||
"success": false,
|
"success": false,
|
||||||
"errors": [
|
"errors": [
|
||||||
{ "code": "STRICT_PROPERTY_VIOLATION", "details": { "path": "cvv" } }
|
{
|
||||||
|
"code": "STRICT_PROPERTY_VIOLATION",
|
||||||
|
"details": {
|
||||||
|
"path": "cvv"
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Successfully routes mutually exclusive properties seamlessly",
|
"description": "Successfully routes mutually exclusive properties seamlessly",
|
||||||
"data": { "type": "A", "field_a": 1, "fallback_b": 2 },
|
"data": {
|
||||||
|
"type": "A",
|
||||||
|
"field_a": 1,
|
||||||
|
"fallback_b": 2
|
||||||
|
},
|
||||||
"schema_id": "mutually_exclusive",
|
"schema_id": "mutually_exclusive",
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Nested fallbacks execute seamlessly",
|
"description": "Nested fallbacks execute seamlessly",
|
||||||
"data": { "tier": "3", "premium": 1 },
|
"data": {
|
||||||
|
"tier": "3",
|
||||||
|
"premium": 1
|
||||||
|
},
|
||||||
"schema_id": "nested_fallbacks",
|
"schema_id": "nested_fallbacks",
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "A case without a when executes its else indiscriminately",
|
"description": "A case without a when executes its else indiscriminately",
|
||||||
"data": { "unconditional": 1 },
|
"data": {
|
||||||
|
"unconditional": 1
|
||||||
|
},
|
||||||
"schema_id": "missing_when",
|
"schema_id": "missing_when",
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "A case without a when throws if else unconditionally requires field",
|
"description": "A case without a when throws if else unconditionally requires field",
|
||||||
"data": { },
|
"data": {},
|
||||||
"schema_id": "missing_when",
|
"schema_id": "missing_when",
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {
|
"expect": {
|
||||||
"success": false,
|
"success": false,
|
||||||
"errors": [
|
"errors": [
|
||||||
{ "code": "REQUIRED_FIELD_MISSING", "details": { "path": "unconditional" } }
|
{
|
||||||
|
"code": "REQUIRED_FIELD_MISSING",
|
||||||
|
"details": {
|
||||||
|
"path": "unconditional"
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
{
|
{
|
||||||
"description": "const validation",
|
"description": "const validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_0_0": {
|
||||||
"const": 2,
|
"const": 2
|
||||||
"$id": "const_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -42,8 +41,8 @@
|
|||||||
{
|
{
|
||||||
"description": "const with object",
|
"description": "const with object",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_1_0": {
|
||||||
"const": {
|
"const": {
|
||||||
"foo": "bar",
|
"foo": "bar",
|
||||||
"baz": "bax"
|
"baz": "bax"
|
||||||
@ -51,10 +50,9 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"foo": {},
|
"foo": {},
|
||||||
"baz": {}
|
"baz": {}
|
||||||
},
|
|
||||||
"$id": "const_1_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -109,16 +107,15 @@
|
|||||||
{
|
{
|
||||||
"description": "const with array",
|
"description": "const with array",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_2_0": {
|
||||||
"const": [
|
"const": [
|
||||||
{
|
{
|
||||||
"foo": "bar"
|
"foo": "bar"
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"$id": "const_2_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -163,12 +160,11 @@
|
|||||||
{
|
{
|
||||||
"description": "const with null",
|
"description": "const with null",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_3_0": {
|
||||||
"const": null,
|
"const": null
|
||||||
"$id": "const_3_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -194,12 +190,11 @@
|
|||||||
{
|
{
|
||||||
"description": "const with false does not match 0",
|
"description": "const with false does not match 0",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_4_0": {
|
||||||
"const": false,
|
"const": false
|
||||||
"$id": "const_4_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -234,12 +229,11 @@
|
|||||||
{
|
{
|
||||||
"description": "const with true does not match 1",
|
"description": "const with true does not match 1",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_5_0": {
|
||||||
"const": true,
|
"const": true
|
||||||
"$id": "const_5_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -274,14 +268,13 @@
|
|||||||
{
|
{
|
||||||
"description": "const with [false] does not match [0]",
|
"description": "const with [false] does not match [0]",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_6_0": {
|
||||||
"const": [
|
"const": [
|
||||||
false
|
false
|
||||||
],
|
|
||||||
"$id": "const_6_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -322,14 +315,13 @@
|
|||||||
{
|
{
|
||||||
"description": "const with [true] does not match [1]",
|
"description": "const with [true] does not match [1]",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_7_0": {
|
||||||
"const": [
|
"const": [
|
||||||
true
|
true
|
||||||
],
|
|
||||||
"$id": "const_7_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -370,14 +362,13 @@
|
|||||||
{
|
{
|
||||||
"description": "const with {\"a\": false} does not match {\"a\": 0}",
|
"description": "const with {\"a\": false} does not match {\"a\": 0}",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_8_0": {
|
||||||
"const": {
|
"const": {
|
||||||
"a": false
|
"a": false
|
||||||
},
|
|
||||||
"$id": "const_8_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -418,14 +409,13 @@
|
|||||||
{
|
{
|
||||||
"description": "const with {\"a\": true} does not match {\"a\": 1}",
|
"description": "const with {\"a\": true} does not match {\"a\": 1}",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_9_0": {
|
||||||
"const": {
|
"const": {
|
||||||
"a": true
|
"a": true
|
||||||
},
|
|
||||||
"$id": "const_9_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -466,12 +456,11 @@
|
|||||||
{
|
{
|
||||||
"description": "const with 0 does not match other zero-like types",
|
"description": "const with 0 does not match other zero-like types",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_10_0": {
|
||||||
"const": 0,
|
"const": 0
|
||||||
"$id": "const_10_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -533,12 +522,11 @@
|
|||||||
{
|
{
|
||||||
"description": "const with 1 does not match true",
|
"description": "const with 1 does not match true",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_11_0": {
|
||||||
"const": 1,
|
"const": 1
|
||||||
"$id": "const_11_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -573,12 +561,11 @@
|
|||||||
{
|
{
|
||||||
"description": "const with -2.0 matches integer and float types",
|
"description": "const with -2.0 matches integer and float types",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_12_0": {
|
||||||
"const": -2,
|
"const": -2
|
||||||
"$id": "const_12_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -631,12 +618,11 @@
|
|||||||
{
|
{
|
||||||
"description": "float and integers are equal up to 64-bit representation limits",
|
"description": "float and integers are equal up to 64-bit representation limits",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_13_0": {
|
||||||
"const": 9007199254740992,
|
"const": 9007199254740992
|
||||||
"$id": "const_13_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -680,12 +666,11 @@
|
|||||||
{
|
{
|
||||||
"description": "nul characters in strings",
|
"description": "nul characters in strings",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_14_0": {
|
||||||
"const": "hello\u0000there",
|
"const": "hello\u0000there"
|
||||||
"$id": "const_14_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -711,13 +696,12 @@
|
|||||||
{
|
{
|
||||||
"description": "characters with the same visual representation but different codepoint",
|
"description": "characters with the same visual representation but different codepoint",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_15_0": {
|
||||||
"const": "μ",
|
"const": "μ",
|
||||||
"$comment": "U+03BC",
|
"$comment": "U+03BC"
|
||||||
"$id": "const_15_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -745,13 +729,12 @@
|
|||||||
{
|
{
|
||||||
"description": "characters with the same visual representation, but different number of codepoints",
|
"description": "characters with the same visual representation, but different number of codepoints",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_16_0": {
|
||||||
"const": "ä",
|
"const": "ä",
|
||||||
"$comment": "U+00E4",
|
"$comment": "U+00E4"
|
||||||
"$id": "const_16_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -779,15 +762,14 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in const object match",
|
"description": "extensible: true allows extra properties in const object match",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"const_17_0": {
|
||||||
"const": {
|
"const": {
|
||||||
"a": 1
|
"a": 1
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "const_17_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,15 +2,14 @@
|
|||||||
{
|
{
|
||||||
"description": "contains keyword validation",
|
"description": "contains keyword validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"contains_0_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"minimum": 5
|
"minimum": 5
|
||||||
},
|
},
|
||||||
"items": true,
|
"items": true
|
||||||
"$id": "contains_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -89,15 +88,14 @@
|
|||||||
{
|
{
|
||||||
"description": "contains keyword with const keyword",
|
"description": "contains keyword with const keyword",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"contains_1_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 5
|
"const": 5
|
||||||
},
|
},
|
||||||
"items": true,
|
"items": true
|
||||||
"$id": "contains_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -146,12 +144,11 @@
|
|||||||
{
|
{
|
||||||
"description": "contains keyword with boolean schema true",
|
"description": "contains keyword with boolean schema true",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"contains_2_0": {
|
||||||
"contains": true,
|
"contains": true
|
||||||
"$id": "contains_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -179,12 +176,11 @@
|
|||||||
{
|
{
|
||||||
"description": "contains keyword with boolean schema false",
|
"description": "contains keyword with boolean schema false",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"contains_3_0": {
|
||||||
"contains": false,
|
"contains": false
|
||||||
"$id": "contains_3_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -221,17 +217,16 @@
|
|||||||
{
|
{
|
||||||
"description": "items + contains",
|
"description": "items + contains",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"contains_4_0": {
|
||||||
"items": {
|
"items": {
|
||||||
"multipleOf": 2
|
"multipleOf": 2
|
||||||
},
|
},
|
||||||
"contains": {
|
"contains": {
|
||||||
"multipleOf": 3
|
"multipleOf": 3
|
||||||
},
|
|
||||||
"$id": "contains_4_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -289,15 +284,14 @@
|
|||||||
{
|
{
|
||||||
"description": "contains with false if subschema",
|
"description": "contains with false if subschema",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"contains_5_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"if": false,
|
"if": false,
|
||||||
"else": true
|
"else": true
|
||||||
},
|
|
||||||
"$id": "contains_5_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -325,14 +319,13 @@
|
|||||||
{
|
{
|
||||||
"description": "contains with null instance elements",
|
"description": "contains with null instance elements",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"contains_6_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"type": "null"
|
"type": "null"
|
||||||
},
|
|
||||||
"$id": "contains_6_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -351,15 +344,14 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows non-matching items in contains",
|
"description": "extensible: true allows non-matching items in contains",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"contains_7_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "contains_7_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -379,14 +371,13 @@
|
|||||||
{
|
{
|
||||||
"description": "strict by default: non-matching items in contains are invalid",
|
"description": "strict by default: non-matching items in contains are invalid",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"contains_8_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
|
||||||
"$id": "contains_8_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of string-encoded content based on media type",
|
"description": "validation of string-encoded content based on media type",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"content_0_0": {
|
||||||
"contentMediaType": "application/json",
|
"contentMediaType": "application/json"
|
||||||
"$id": "content_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -42,12 +41,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of binary string-encoding",
|
"description": "validation of binary string-encoding",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"content_1_0": {
|
||||||
"contentEncoding": "base64",
|
"contentEncoding": "base64"
|
||||||
"$id": "content_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -82,13 +80,12 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of binary-encoded media type documents",
|
"description": "validation of binary-encoded media type documents",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"content_2_0": {
|
||||||
"contentMediaType": "application/json",
|
"contentMediaType": "application/json",
|
||||||
"contentEncoding": "base64",
|
"contentEncoding": "base64"
|
||||||
"$id": "content_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -132,8 +129,8 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of binary-encoded media type documents with schema",
|
"description": "validation of binary-encoded media type documents with schema",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"content_3_0": {
|
||||||
"contentMediaType": "application/json",
|
"contentMediaType": "application/json",
|
||||||
"contentEncoding": "base64",
|
"contentEncoding": "base64",
|
||||||
"contentSchema": {
|
"contentSchema": {
|
||||||
@ -149,10 +146,9 @@
|
|||||||
"type": "integer"
|
"type": "integer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "content_3_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -15,9 +15,8 @@
|
|||||||
"variations": [
|
"variations": [
|
||||||
"org"
|
"org"
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"full.org": {
|
||||||
"$id": "full.org",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"missing_users": {
|
"missing_users": {
|
||||||
@ -28,7 +27,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "22222222-2222-2222-2222-222222222222",
|
"id": "22222222-2222-2222-2222-222222222222",
|
||||||
@ -42,13 +41,12 @@
|
|||||||
"variations": [
|
"variations": [
|
||||||
"user"
|
"user"
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"full.user": {
|
||||||
"$id": "full.user",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {}
|
"properties": {}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"relations": []
|
"relations": []
|
||||||
@ -84,9 +82,8 @@
|
|||||||
"variations": [
|
"variations": [
|
||||||
"parent"
|
"parent"
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"full.parent": {
|
||||||
"$id": "full.parent",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"children": {
|
"children": {
|
||||||
@ -97,7 +94,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "22222222-2222-2222-2222-222222222222",
|
"id": "22222222-2222-2222-2222-222222222222",
|
||||||
@ -111,13 +108,12 @@
|
|||||||
"variations": [
|
"variations": [
|
||||||
"child"
|
"child"
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"full.child": {
|
||||||
"$id": "full.child",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {}
|
"properties": {}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"relations": [
|
"relations": [
|
||||||
@ -167,9 +163,8 @@
|
|||||||
"variations": [
|
"variations": [
|
||||||
"invoice"
|
"invoice"
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"full.invoice": {
|
||||||
"$id": "full.invoice",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"activities": {
|
"activities": {
|
||||||
@ -180,7 +175,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "22222222-2222-2222-2222-222222222222",
|
"id": "22222222-2222-2222-2222-222222222222",
|
||||||
@ -194,13 +189,12 @@
|
|||||||
"variations": [
|
"variations": [
|
||||||
"activity"
|
"activity"
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"full.activity": {
|
||||||
"$id": "full.activity",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {}
|
"properties": {}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"relations": [
|
"relations": [
|
||||||
@ -274,9 +268,8 @@
|
|||||||
"variations": [
|
"variations": [
|
||||||
"actor"
|
"actor"
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"full.actor": {
|
||||||
"$id": "full.actor",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"ambiguous_edge": {
|
"ambiguous_edge": {
|
||||||
@ -287,7 +280,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "22222222-2222-2222-2222-222222222222",
|
"id": "22222222-2222-2222-2222-222222222222",
|
||||||
@ -301,13 +294,12 @@
|
|||||||
"variations": [
|
"variations": [
|
||||||
"junction"
|
"junction"
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"empty.junction": {
|
||||||
"$id": "empty.junction",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {}
|
"properties": {}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"relations": [
|
"relations": [
|
||||||
|
|||||||
@ -2,10 +2,9 @@
|
|||||||
{
|
{
|
||||||
"description": "single dependency (required)",
|
"description": "single dependency (required)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema1": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "schema1",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bar": [
|
"bar": [
|
||||||
"foo"
|
"foo"
|
||||||
@ -13,7 +12,7 @@
|
|||||||
},
|
},
|
||||||
"extensible": true
|
"extensible": true
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -93,16 +92,15 @@
|
|||||||
{
|
{
|
||||||
"description": "empty dependents",
|
"description": "empty dependents",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema2": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "schema2",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bar": []
|
"bar": []
|
||||||
},
|
},
|
||||||
"extensible": true
|
"extensible": true
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -139,10 +137,9 @@
|
|||||||
{
|
{
|
||||||
"description": "multiple dependents required",
|
"description": "multiple dependents required",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema3": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "schema3",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"quux": [
|
"quux": [
|
||||||
"foo",
|
"foo",
|
||||||
@ -151,7 +148,7 @@
|
|||||||
},
|
},
|
||||||
"extensible": true
|
"extensible": true
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -228,10 +225,9 @@
|
|||||||
{
|
{
|
||||||
"description": "dependencies with escaped characters",
|
"description": "dependencies with escaped characters",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema4": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "schema4",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"foo\nbar": [
|
"foo\nbar": [
|
||||||
"foo\rbar"
|
"foo\rbar"
|
||||||
@ -242,7 +238,7 @@
|
|||||||
},
|
},
|
||||||
"extensible": true
|
"extensible": true
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -297,10 +293,9 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in dependentRequired",
|
"description": "extensible: true allows extra properties in dependentRequired",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema5": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "schema5",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bar": [
|
"bar": [
|
||||||
"foo"
|
"foo"
|
||||||
@ -308,7 +303,7 @@
|
|||||||
},
|
},
|
||||||
"extensible": true
|
"extensible": true
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -329,10 +324,9 @@
|
|||||||
{
|
{
|
||||||
"description": "single dependency (schemas, STRICT)",
|
"description": "single dependency (schemas, STRICT)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema_schema1": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "schema_schema1",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": true,
|
"foo": true,
|
||||||
"bar": true
|
"bar": true
|
||||||
@ -350,7 +344,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -451,10 +445,9 @@
|
|||||||
{
|
{
|
||||||
"description": "single dependency (schemas, EXTENSIBLE)",
|
"description": "single dependency (schemas, EXTENSIBLE)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema_schema2": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "schema_schema2",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": true,
|
"foo": true,
|
||||||
"bar": true
|
"bar": true
|
||||||
@ -473,7 +466,7 @@
|
|||||||
},
|
},
|
||||||
"extensible": true
|
"extensible": true
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -492,10 +485,9 @@
|
|||||||
{
|
{
|
||||||
"description": "boolean subschemas",
|
"description": "boolean subschemas",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema_schema3": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "schema_schema3",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": true,
|
"foo": true,
|
||||||
"bar": true
|
"bar": true
|
||||||
@ -505,7 +497,7 @@
|
|||||||
"bar": false
|
"bar": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -556,10 +548,9 @@
|
|||||||
{
|
{
|
||||||
"description": "dependencies with escaped characters",
|
"description": "dependencies with escaped characters",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema_schema4": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "schema_schema4",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo\tbar": true,
|
"foo\tbar": true,
|
||||||
"foo'bar": true,
|
"foo'bar": true,
|
||||||
@ -579,7 +570,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -637,10 +628,9 @@
|
|||||||
{
|
{
|
||||||
"description": "dependent subschema incompatible with root (STRICT)",
|
"description": "dependent subschema incompatible with root (STRICT)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema_schema5": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "schema_schema5",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {},
|
"foo": {},
|
||||||
"baz": true
|
"baz": true
|
||||||
@ -653,7 +643,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -711,10 +701,9 @@
|
|||||||
{
|
{
|
||||||
"description": "dependent subschema incompatible with root (EXTENSIBLE)",
|
"description": "dependent subschema incompatible with root (EXTENSIBLE)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"schema_schema6": {
|
||||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
"$id": "schema_schema6",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {},
|
"foo": {},
|
||||||
"baz": true
|
"baz": true
|
||||||
@ -729,7 +718,7 @@
|
|||||||
},
|
},
|
||||||
"extensible": true
|
"extensible": true
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
{
|
{
|
||||||
"description": "empty string is valid for all types (except const)",
|
"description": "empty string is valid for all types (except const)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"emptyString_0_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"obj": {
|
"obj": {
|
||||||
"type": "object"
|
"type": "object"
|
||||||
@ -36,10 +36,9 @@
|
|||||||
"con_empty": {
|
"con_empty": {
|
||||||
"const": ""
|
"const": ""
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "emptyString_0_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -142,7 +141,9 @@
|
|||||||
"errors": [
|
"errors": [
|
||||||
{
|
{
|
||||||
"code": "CONST_VIOLATED",
|
"code": "CONST_VIOLATED",
|
||||||
"details": { "path": "con" }
|
"details": {
|
||||||
|
"path": "con"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,16 +2,15 @@
|
|||||||
{
|
{
|
||||||
"description": "simple enum validation",
|
"description": "simple enum validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_0_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
1,
|
1,
|
||||||
2,
|
2,
|
||||||
3
|
3
|
||||||
],
|
|
||||||
"$id": "enum_0_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -37,8 +36,8 @@
|
|||||||
{
|
{
|
||||||
"description": "heterogeneous enum validation",
|
"description": "heterogeneous enum validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_1_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
6,
|
6,
|
||||||
"foo",
|
"foo",
|
||||||
@ -50,10 +49,9 @@
|
|||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {}
|
"foo": {}
|
||||||
},
|
|
||||||
"$id": "enum_1_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -113,15 +111,14 @@
|
|||||||
{
|
{
|
||||||
"description": "heterogeneous enum-with-null validation",
|
"description": "heterogeneous enum-with-null validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_2_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
6,
|
6,
|
||||||
null
|
null
|
||||||
],
|
|
||||||
"$id": "enum_2_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -156,8 +153,8 @@
|
|||||||
{
|
{
|
||||||
"description": "enums in properties",
|
"description": "enums in properties",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_3_0": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {
|
"foo": {
|
||||||
@ -173,10 +170,9 @@
|
|||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"bar"
|
"bar"
|
||||||
],
|
|
||||||
"$id": "enum_3_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -251,15 +247,14 @@
|
|||||||
{
|
{
|
||||||
"description": "enum with escaped characters",
|
"description": "enum with escaped characters",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_4_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
"foo\nbar",
|
"foo\nbar",
|
||||||
"foo\rbar"
|
"foo\rbar"
|
||||||
],
|
|
||||||
"$id": "enum_4_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -294,14 +289,13 @@
|
|||||||
{
|
{
|
||||||
"description": "enum with false does not match 0",
|
"description": "enum with false does not match 0",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_5_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
false
|
false
|
||||||
],
|
|
||||||
"$id": "enum_5_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -336,16 +330,15 @@
|
|||||||
{
|
{
|
||||||
"description": "enum with [false] does not match [0]",
|
"description": "enum with [false] does not match [0]",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_6_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
[
|
[
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
],
|
|
||||||
"$id": "enum_6_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -386,14 +379,13 @@
|
|||||||
{
|
{
|
||||||
"description": "enum with true does not match 1",
|
"description": "enum with true does not match 1",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_7_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
true
|
true
|
||||||
],
|
|
||||||
"$id": "enum_7_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -428,16 +420,15 @@
|
|||||||
{
|
{
|
||||||
"description": "enum with [true] does not match [1]",
|
"description": "enum with [true] does not match [1]",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_8_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
[
|
[
|
||||||
true
|
true
|
||||||
]
|
]
|
||||||
],
|
|
||||||
"$id": "enum_8_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -478,14 +469,13 @@
|
|||||||
{
|
{
|
||||||
"description": "enum with 0 does not match false",
|
"description": "enum with 0 does not match false",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_9_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
0
|
0
|
||||||
],
|
|
||||||
"$id": "enum_9_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -520,16 +510,15 @@
|
|||||||
{
|
{
|
||||||
"description": "enum with [0] does not match [false]",
|
"description": "enum with [0] does not match [false]",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_10_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
[
|
[
|
||||||
0
|
0
|
||||||
]
|
]
|
||||||
],
|
|
||||||
"$id": "enum_10_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -570,14 +559,13 @@
|
|||||||
{
|
{
|
||||||
"description": "enum with 1 does not match true",
|
"description": "enum with 1 does not match true",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_11_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
1
|
1
|
||||||
],
|
|
||||||
"$id": "enum_11_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -612,16 +600,15 @@
|
|||||||
{
|
{
|
||||||
"description": "enum with [1] does not match [true]",
|
"description": "enum with [1] does not match [true]",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_12_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
[
|
[
|
||||||
1
|
1
|
||||||
]
|
]
|
||||||
],
|
|
||||||
"$id": "enum_12_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -662,14 +649,13 @@
|
|||||||
{
|
{
|
||||||
"description": "nul characters in strings",
|
"description": "nul characters in strings",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_13_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
"hello\u0000there"
|
"hello\u0000there"
|
||||||
],
|
|
||||||
"$id": "enum_13_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -695,17 +681,16 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in enum object match",
|
"description": "extensible: true allows extra properties in enum object match",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"enum_14_0": {
|
||||||
"enum": [
|
"enum": [
|
||||||
{
|
{
|
||||||
"foo": 1
|
"foo": 1
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "enum_14_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
{
|
{
|
||||||
"description": "exclusiveMaximum validation",
|
"description": "exclusiveMaximum validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"exclusiveMaximum_0_0": {
|
||||||
"exclusiveMaximum": 3,
|
"exclusiveMaximum": 3
|
||||||
"$id": "exclusiveMaximum_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
{
|
{
|
||||||
"description": "exclusiveMinimum validation",
|
"description": "exclusiveMinimum validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"exclusiveMinimum_0_0": {
|
||||||
"exclusiveMinimum": 1.1,
|
"exclusiveMinimum": 1.1
|
||||||
"$id": "exclusiveMinimum_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of date-time strings",
|
"description": "validation of date-time strings",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_0_0": {
|
||||||
"format": "date-time",
|
"format": "date-time"
|
||||||
"$id": "format_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -249,12 +248,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of date strings",
|
"description": "validation of date strings",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_1_0": {
|
||||||
"format": "date",
|
"format": "date"
|
||||||
"$id": "format_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -694,12 +692,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of duration strings",
|
"description": "validation of duration strings",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_2_0": {
|
||||||
"format": "duration",
|
"format": "duration"
|
||||||
"$id": "format_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -941,12 +938,11 @@
|
|||||||
{
|
{
|
||||||
"description": "\\a is not an ECMA 262 control escape",
|
"description": "\\a is not an ECMA 262 control escape",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_3_0": {
|
||||||
"format": "regex",
|
"format": "regex"
|
||||||
"$id": "format_3_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -963,12 +959,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of e-mail addresses",
|
"description": "validation of e-mail addresses",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_4_0": {
|
||||||
"format": "email",
|
"format": "email"
|
||||||
"$id": "format_4_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1192,12 +1187,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of host names",
|
"description": "validation of host names",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_5_0": {
|
||||||
"format": "hostname",
|
"format": "hostname"
|
||||||
"$id": "format_5_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1422,12 +1416,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of A-label (punycode) host names",
|
"description": "validation of A-label (punycode) host names",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_6_0": {
|
||||||
"format": "hostname",
|
"format": "hostname"
|
||||||
"$id": "format_6_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1803,12 +1796,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of an internationalized e-mail addresses",
|
"description": "validation of an internationalized e-mail addresses",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_7_0": {
|
||||||
"format": "idn-email",
|
"format": "idn-email"
|
||||||
"$id": "format_7_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1906,12 +1898,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of internationalized host names",
|
"description": "validation of internationalized host names",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_8_0": {
|
||||||
"format": "idn-hostname",
|
"format": "idn-hostname"
|
||||||
"$id": "format_8_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -2479,12 +2470,11 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_9_0": {
|
||||||
"format": "idn-hostname",
|
"format": "idn-hostname"
|
||||||
"$id": "format_9_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -2672,12 +2662,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of IP addresses",
|
"description": "validation of IP addresses",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_10_0": {
|
||||||
"format": "ipv4",
|
"format": "ipv4"
|
||||||
"$id": "format_10_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -2830,12 +2819,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of IPv6 addresses",
|
"description": "validation of IPv6 addresses",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_11_0": {
|
||||||
"format": "ipv6",
|
"format": "ipv6"
|
||||||
"$id": "format_11_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -3203,12 +3191,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of IRI References",
|
"description": "validation of IRI References",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_12_0": {
|
||||||
"format": "iri-reference",
|
"format": "iri-reference"
|
||||||
"$id": "format_12_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -3333,12 +3320,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of IRIs",
|
"description": "validation of IRIs",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_13_0": {
|
||||||
"format": "iri",
|
"format": "iri"
|
||||||
"$id": "format_13_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -3481,12 +3467,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of JSON-pointers (JSON String Representation)",
|
"description": "validation of JSON-pointers (JSON String Representation)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_14_0": {
|
||||||
"format": "json-pointer",
|
"format": "json-pointer"
|
||||||
"$id": "format_14_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -3836,12 +3821,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of regular expressions",
|
"description": "validation of regular expressions",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_15_0": {
|
||||||
"format": "regex",
|
"format": "regex"
|
||||||
"$id": "format_15_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -3921,12 +3905,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of Relative JSON Pointers (RJP)",
|
"description": "validation of Relative JSON Pointers (RJP)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_16_0": {
|
||||||
"format": "relative-json-pointer",
|
"format": "relative-json-pointer"
|
||||||
"$id": "format_16_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -4096,12 +4079,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of time strings",
|
"description": "validation of time strings",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_17_0": {
|
||||||
"format": "time",
|
"format": "time"
|
||||||
"$id": "format_17_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -4523,12 +4505,11 @@
|
|||||||
{
|
{
|
||||||
"description": "unknown format",
|
"description": "unknown format",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_18_0": {
|
||||||
"format": "unknown",
|
"format": "unknown"
|
||||||
"$id": "format_18_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -4599,12 +4580,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of URI References",
|
"description": "validation of URI References",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_19_0": {
|
||||||
"format": "uri-reference",
|
"format": "uri-reference"
|
||||||
"$id": "format_19_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -4747,12 +4727,11 @@
|
|||||||
{
|
{
|
||||||
"description": "format: uri-template",
|
"description": "format: uri-template",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_20_0": {
|
||||||
"format": "uri-template",
|
"format": "uri-template"
|
||||||
"$id": "format_20_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -4850,12 +4829,11 @@
|
|||||||
{
|
{
|
||||||
"description": "validation of URIs",
|
"description": "validation of URIs",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_21_0": {
|
||||||
"format": "uri",
|
"format": "uri"
|
||||||
"$id": "format_21_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -5187,12 +5165,11 @@
|
|||||||
{
|
{
|
||||||
"description": "uuid format",
|
"description": "uuid format",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_22_0": {
|
||||||
"format": "uuid",
|
"format": "uuid"
|
||||||
"$id": "format_22_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -5398,12 +5375,11 @@
|
|||||||
{
|
{
|
||||||
"description": "period format",
|
"description": "period format",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"format_23_0": {
|
||||||
"format": "period",
|
"format": "period"
|
||||||
"$id": "format_23_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,16 +5,19 @@
|
|||||||
"puncs": [
|
"puncs": [
|
||||||
{
|
{
|
||||||
"name": "get_invoice",
|
"name": "get_invoice",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"get_invoice.response": {
|
||||||
"$id": "get_invoice.response",
|
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{ "type": "invoice" },
|
{
|
||||||
{ "type": "null" }
|
"type": "invoice"
|
||||||
]
|
},
|
||||||
|
{
|
||||||
|
"type": "null"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"enums": [],
|
"enums": [],
|
||||||
"relations": [
|
"relations": [
|
||||||
@ -23,32 +26,64 @@
|
|||||||
"type": "relation",
|
"type": "relation",
|
||||||
"constraint": "fk_attachment_attachable_entity",
|
"constraint": "fk_attachment_attachable_entity",
|
||||||
"source_type": "attachment",
|
"source_type": "attachment",
|
||||||
"source_columns": ["attachable_id", "attachable_type"],
|
"source_columns": [
|
||||||
|
"attachable_id",
|
||||||
|
"attachable_type"
|
||||||
|
],
|
||||||
"destination_type": "entity",
|
"destination_type": "entity",
|
||||||
"destination_columns": ["id", "type"],
|
"destination_columns": [
|
||||||
|
"id",
|
||||||
|
"type"
|
||||||
|
],
|
||||||
"prefix": null
|
"prefix": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"types": [
|
"types": [
|
||||||
{
|
{
|
||||||
"name": "entity",
|
"name": "entity",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"entity": {
|
||||||
"$id": "entity",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": { "type": "string", "format": "uuid" },
|
"id": {
|
||||||
"type": { "type": "string" },
|
"type": "string",
|
||||||
"archived": { "type": "boolean" },
|
"format": "uuid"
|
||||||
"created_at": { "type": "string", "format": "date-time" }
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"archived": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"created_at": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hierarchy": [
|
||||||
|
"entity"
|
||||||
|
],
|
||||||
|
"variations": [
|
||||||
|
"entity",
|
||||||
|
"activity",
|
||||||
|
"invoice",
|
||||||
|
"attachment"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
"id",
|
||||||
|
"type",
|
||||||
|
"archived",
|
||||||
|
"created_at"
|
||||||
],
|
],
|
||||||
"hierarchy": ["entity"],
|
|
||||||
"variations": ["entity", "activity", "invoice", "attachment"],
|
|
||||||
"fields": ["id", "type", "archived", "created_at"],
|
|
||||||
"grouped_fields": {
|
"grouped_fields": {
|
||||||
"entity": ["id", "type", "archived", "created_at"]
|
"entity": [
|
||||||
|
"id",
|
||||||
|
"type",
|
||||||
|
"archived",
|
||||||
|
"created_at"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"field_types": {
|
"field_types": {
|
||||||
"id": "uuid",
|
"id": "uuid",
|
||||||
@ -63,21 +98,42 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "activity",
|
"name": "activity",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"activity": {
|
||||||
"$id": "activity",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"start_date": { "type": "string", "format": "date-time" }
|
"start_date": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "date-time"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hierarchy": [
|
||||||
|
"activity",
|
||||||
|
"entity"
|
||||||
|
],
|
||||||
|
"variations": [
|
||||||
|
"activity",
|
||||||
|
"invoice"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
"id",
|
||||||
|
"type",
|
||||||
|
"archived",
|
||||||
|
"created_at",
|
||||||
|
"start_date"
|
||||||
],
|
],
|
||||||
"hierarchy": ["activity", "entity"],
|
|
||||||
"variations": ["activity", "invoice"],
|
|
||||||
"fields": ["id", "type", "archived", "created_at", "start_date"],
|
|
||||||
"grouped_fields": {
|
"grouped_fields": {
|
||||||
"entity": ["id", "type", "archived", "created_at"],
|
"entity": [
|
||||||
"activity": ["start_date"]
|
"id",
|
||||||
|
"type",
|
||||||
|
"archived",
|
||||||
|
"created_at"
|
||||||
|
],
|
||||||
|
"activity": [
|
||||||
|
"start_date"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"field_types": {
|
"field_types": {
|
||||||
"id": "uuid",
|
"id": "uuid",
|
||||||
@ -93,26 +149,51 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "invoice",
|
"name": "invoice",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"invoice": {
|
||||||
"$id": "invoice",
|
|
||||||
"type": "activity",
|
"type": "activity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"status": { "type": "string" },
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"attachments": {
|
"attachments": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": { "type": "attachment" }
|
"items": {
|
||||||
|
"type": "attachment"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hierarchy": [
|
||||||
|
"invoice",
|
||||||
|
"activity",
|
||||||
|
"entity"
|
||||||
|
],
|
||||||
|
"variations": [
|
||||||
|
"invoice"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
"id",
|
||||||
|
"type",
|
||||||
|
"archived",
|
||||||
|
"created_at",
|
||||||
|
"start_date",
|
||||||
|
"status"
|
||||||
],
|
],
|
||||||
"hierarchy": ["invoice", "activity", "entity"],
|
|
||||||
"variations": ["invoice"],
|
|
||||||
"fields": ["id", "type", "archived", "created_at", "start_date", "status"],
|
|
||||||
"grouped_fields": {
|
"grouped_fields": {
|
||||||
"entity": ["id", "type", "archived", "created_at"],
|
"entity": [
|
||||||
"activity": ["start_date"],
|
"id",
|
||||||
"invoice": ["status"]
|
"type",
|
||||||
|
"archived",
|
||||||
|
"created_at"
|
||||||
|
],
|
||||||
|
"activity": [
|
||||||
|
"start_date"
|
||||||
|
],
|
||||||
|
"invoice": [
|
||||||
|
"status"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"field_types": {
|
"field_types": {
|
||||||
"id": "uuid",
|
"id": "uuid",
|
||||||
@ -129,26 +210,66 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "attachment",
|
"name": "attachment",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"attachment": {
|
||||||
"$id": "attachment",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": { "type": "string" },
|
"name": {
|
||||||
"attachable_id": { "type": "string", "format": "uuid" },
|
"type": "string"
|
||||||
"attachable_type": { "type": "string" },
|
},
|
||||||
"kind": { "type": "string" },
|
"attachable_id": {
|
||||||
"file": { "type": "string" },
|
"type": "string",
|
||||||
"data": { "type": "object" }
|
"format": "uuid"
|
||||||
|
},
|
||||||
|
"attachable_type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"kind": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"type": "object"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hierarchy": [
|
||||||
|
"attachment",
|
||||||
|
"entity"
|
||||||
|
],
|
||||||
|
"variations": [
|
||||||
|
"attachment"
|
||||||
|
],
|
||||||
|
"fields": [
|
||||||
|
"id",
|
||||||
|
"type",
|
||||||
|
"archived",
|
||||||
|
"created_at",
|
||||||
|
"attachable_id",
|
||||||
|
"attachable_type",
|
||||||
|
"kind",
|
||||||
|
"file",
|
||||||
|
"data",
|
||||||
|
"name"
|
||||||
],
|
],
|
||||||
"hierarchy": ["attachment", "entity"],
|
|
||||||
"variations": ["attachment"],
|
|
||||||
"fields": ["id", "type", "archived", "created_at", "attachable_id", "attachable_type", "kind", "file", "data", "name"],
|
|
||||||
"grouped_fields": {
|
"grouped_fields": {
|
||||||
"entity": ["id", "type", "archived", "created_at"],
|
"entity": [
|
||||||
"attachment": ["attachable_id", "attachable_type", "kind", "file", "data", "name"]
|
"id",
|
||||||
|
"type",
|
||||||
|
"archived",
|
||||||
|
"created_at"
|
||||||
|
],
|
||||||
|
"attachment": [
|
||||||
|
"attachable_id",
|
||||||
|
"attachable_type",
|
||||||
|
"kind",
|
||||||
|
"file",
|
||||||
|
"data",
|
||||||
|
"name"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"field_types": {
|
"field_types": {
|
||||||
"id": "uuid",
|
"id": "uuid",
|
||||||
|
|||||||
@ -2,14 +2,13 @@
|
|||||||
{
|
{
|
||||||
"description": "a schema given for items",
|
"description": "a schema given for items",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_0_0": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
|
||||||
"$id": "items_0_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -65,12 +64,11 @@
|
|||||||
{
|
{
|
||||||
"description": "items with boolean schema (true)",
|
"description": "items with boolean schema (true)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_1_0": {
|
||||||
"items": true,
|
"items": true
|
||||||
"$id": "items_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -100,12 +98,11 @@
|
|||||||
{
|
{
|
||||||
"description": "items with boolean schema (false)",
|
"description": "items with boolean schema (false)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_2_0": {
|
||||||
"items": false,
|
"items": false
|
||||||
"$id": "items_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -135,8 +132,8 @@
|
|||||||
{
|
{
|
||||||
"description": "items and subitems",
|
"description": "items and subitems",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_3_0": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": false,
|
"items": false,
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
@ -149,11 +146,9 @@
|
|||||||
{
|
{
|
||||||
"type": "item"
|
"type": "item"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"$id": "items_3_0"
|
|
||||||
},
|
},
|
||||||
{
|
"item": {
|
||||||
"$id": "item",
|
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": false,
|
"items": false,
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
@ -165,14 +160,13 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
"sub-item": {
|
||||||
"$id": "sub-item",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
"foo"
|
"foo"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -374,8 +368,8 @@
|
|||||||
{
|
{
|
||||||
"description": "nested items",
|
"description": "nested items",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_4_0": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
@ -388,10 +382,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "items_4_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -507,17 +500,16 @@
|
|||||||
{
|
{
|
||||||
"description": "prefixItems with no additional items allowed",
|
"description": "prefixItems with no additional items allowed",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_5_0": {
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
{},
|
{},
|
||||||
{},
|
{},
|
||||||
{}
|
{}
|
||||||
],
|
],
|
||||||
"items": false,
|
"items": false
|
||||||
"$id": "items_5_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -584,8 +576,8 @@
|
|||||||
{
|
{
|
||||||
"description": "items does not look in applicators, valid case",
|
"description": "items does not look in applicators, valid case",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_6_0": {
|
||||||
"allOf": [
|
"allOf": [
|
||||||
{
|
{
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
@ -597,10 +589,9 @@
|
|||||||
],
|
],
|
||||||
"items": {
|
"items": {
|
||||||
"minimum": 5
|
"minimum": 5
|
||||||
},
|
|
||||||
"$id": "items_6_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -632,8 +623,8 @@
|
|||||||
{
|
{
|
||||||
"description": "prefixItems validation adjusts the starting index for items",
|
"description": "prefixItems validation adjusts the starting index for items",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_7_0": {
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -641,10 +632,9 @@
|
|||||||
],
|
],
|
||||||
"items": {
|
"items": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
|
||||||
"$id": "items_7_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -677,15 +667,14 @@
|
|||||||
{
|
{
|
||||||
"description": "items with heterogeneous array",
|
"description": "items with heterogeneous array",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_8_0": {
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
{}
|
{}
|
||||||
],
|
],
|
||||||
"items": false,
|
"items": false
|
||||||
"$id": "items_8_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -717,14 +706,13 @@
|
|||||||
{
|
{
|
||||||
"description": "items with null instance elements",
|
"description": "items with null instance elements",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_9_0": {
|
||||||
"items": {
|
"items": {
|
||||||
"type": "null"
|
"type": "null"
|
||||||
},
|
|
||||||
"$id": "items_9_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -743,13 +731,12 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra items (when items is false)",
|
"description": "extensible: true allows extra items (when items is false)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_10_0": {
|
||||||
"items": false,
|
"items": false,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "items_10_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -768,15 +755,14 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties for items",
|
"description": "extensible: true allows extra properties for items",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_11_0": {
|
||||||
"items": {
|
"items": {
|
||||||
"minimum": 5
|
"minimum": 5
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "items_11_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -807,13 +793,12 @@
|
|||||||
{
|
{
|
||||||
"description": "array: simple extensible array",
|
"description": "array: simple extensible array",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_12_0": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "items_12_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -842,13 +827,12 @@
|
|||||||
{
|
{
|
||||||
"description": "array: strict array",
|
"description": "array: strict array",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_13_0": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"extensible": false,
|
"extensible": false
|
||||||
"$id": "items_13_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -876,15 +860,14 @@
|
|||||||
{
|
{
|
||||||
"description": "array: items extensible",
|
"description": "array: items extensible",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_14_0": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"extensible": true
|
"extensible": true
|
||||||
},
|
|
||||||
"$id": "items_14_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -914,16 +897,15 @@
|
|||||||
{
|
{
|
||||||
"description": "array: items strict",
|
"description": "array: items strict",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"items_15_0": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"extensible": false
|
"extensible": false
|
||||||
},
|
|
||||||
"$id": "items_15_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,13 +2,12 @@
|
|||||||
{
|
{
|
||||||
"description": "maxContains without contains is ignored",
|
"description": "maxContains without contains is ignored",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxContains_0_0": {
|
||||||
"maxContains": 1,
|
"maxContains": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "maxContains_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -39,16 +38,15 @@
|
|||||||
{
|
{
|
||||||
"description": "maxContains with contains",
|
"description": "maxContains with contains",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxContains_1_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"maxContains": 1,
|
"maxContains": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "maxContains_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -113,16 +111,15 @@
|
|||||||
{
|
{
|
||||||
"description": "maxContains with contains, value with a decimal",
|
"description": "maxContains with contains, value with a decimal",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxContains_2_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"maxContains": 1,
|
"maxContains": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "maxContains_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -153,17 +150,16 @@
|
|||||||
{
|
{
|
||||||
"description": "minContains < maxContains",
|
"description": "minContains < maxContains",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxContains_3_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"minContains": 1,
|
"minContains": 1,
|
||||||
"maxContains": 3,
|
"maxContains": 3,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "maxContains_3_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -206,16 +202,15 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows non-matching items in maxContains",
|
"description": "extensible: true allows non-matching items in maxContains",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxContains_4_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"maxContains": 1,
|
"maxContains": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "maxContains_4_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,13 +2,12 @@
|
|||||||
{
|
{
|
||||||
"description": "maxItems validation",
|
"description": "maxItems validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxItems_0_0": {
|
||||||
"maxItems": 2,
|
"maxItems": 2,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "maxItems_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -61,13 +60,12 @@
|
|||||||
{
|
{
|
||||||
"description": "maxItems validation with a decimal",
|
"description": "maxItems validation with a decimal",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxItems_1_0": {
|
||||||
"maxItems": 2,
|
"maxItems": 2,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "maxItems_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -99,13 +97,12 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra items in maxItems (but counted)",
|
"description": "extensible: true allows extra items in maxItems (but counted)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxItems_2_0": {
|
||||||
"maxItems": 2,
|
"maxItems": 2,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "maxItems_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
{
|
{
|
||||||
"description": "maxLength validation",
|
"description": "maxLength validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxLength_0_0": {
|
||||||
"maxLength": 2,
|
"maxLength": 2
|
||||||
"$id": "maxLength_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -60,12 +59,11 @@
|
|||||||
{
|
{
|
||||||
"description": "maxLength validation with a decimal",
|
"description": "maxLength validation with a decimal",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxLength_1_0": {
|
||||||
"maxLength": 2,
|
"maxLength": 2
|
||||||
"$id": "maxLength_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,13 +2,12 @@
|
|||||||
{
|
{
|
||||||
"description": "maxProperties validation",
|
"description": "maxProperties validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxProperties_0_0": {
|
||||||
"maxProperties": 2,
|
"maxProperties": 2,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "maxProperties_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -83,13 +82,12 @@
|
|||||||
{
|
{
|
||||||
"description": "maxProperties validation with a decimal",
|
"description": "maxProperties validation with a decimal",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxProperties_1_0": {
|
||||||
"maxProperties": 2,
|
"maxProperties": 2,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "maxProperties_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -121,13 +119,12 @@
|
|||||||
{
|
{
|
||||||
"description": "maxProperties = 0 means the object is empty",
|
"description": "maxProperties = 0 means the object is empty",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxProperties_2_0": {
|
||||||
"maxProperties": 0,
|
"maxProperties": 0,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "maxProperties_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -155,13 +152,12 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in maxProperties (though maxProperties still counts them!)",
|
"description": "extensible: true allows extra properties in maxProperties (though maxProperties still counts them!)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maxProperties_3_0": {
|
||||||
"maxProperties": 2,
|
"maxProperties": 2,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "maxProperties_3_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
{
|
{
|
||||||
"description": "maximum validation",
|
"description": "maximum validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maximum_0_0": {
|
||||||
"maximum": 3,
|
"maximum": 3
|
||||||
"$id": "maximum_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -51,12 +50,11 @@
|
|||||||
{
|
{
|
||||||
"description": "maximum validation with unsigned integer",
|
"description": "maximum validation with unsigned integer",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"maximum_1_0": {
|
||||||
"maximum": 300,
|
"maximum": 300
|
||||||
"$id": "maximum_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,25 +2,23 @@
|
|||||||
{
|
{
|
||||||
"description": "merging: properties accumulate",
|
"description": "merging: properties accumulate",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"base_0": {
|
||||||
"$id": "base_0",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"base_prop": {
|
"base_prop": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"merge_0_0": {
|
||||||
"type": "base_0",
|
"type": "base_0",
|
||||||
"properties": {
|
"properties": {
|
||||||
"child_prop": {
|
"child_prop": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "merge_0_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -48,7 +46,9 @@
|
|||||||
"errors": [
|
"errors": [
|
||||||
{
|
{
|
||||||
"code": "INVALID_TYPE",
|
"code": "INVALID_TYPE",
|
||||||
"details": { "path": "base_prop" }
|
"details": {
|
||||||
|
"path": "base_prop"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -58,9 +58,8 @@
|
|||||||
{
|
{
|
||||||
"description": "merging: required fields accumulate",
|
"description": "merging: required fields accumulate",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"base_1": {
|
||||||
"$id": "base_1",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"a": {
|
"a": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -70,7 +69,7 @@
|
|||||||
"a"
|
"a"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
"merge_1_0": {
|
||||||
"type": "base_1",
|
"type": "base_1",
|
||||||
"properties": {
|
"properties": {
|
||||||
"b": {
|
"b": {
|
||||||
@ -79,10 +78,9 @@
|
|||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"b"
|
"b"
|
||||||
],
|
|
||||||
"$id": "merge_1_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -109,7 +107,9 @@
|
|||||||
"errors": [
|
"errors": [
|
||||||
{
|
{
|
||||||
"code": "REQUIRED_FIELD_MISSING",
|
"code": "REQUIRED_FIELD_MISSING",
|
||||||
"details": { "path": "a" }
|
"details": {
|
||||||
|
"path": "a"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -126,7 +126,9 @@
|
|||||||
"errors": [
|
"errors": [
|
||||||
{
|
{
|
||||||
"code": "REQUIRED_FIELD_MISSING",
|
"code": "REQUIRED_FIELD_MISSING",
|
||||||
"details": { "path": "b" }
|
"details": {
|
||||||
|
"path": "b"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -136,9 +138,8 @@
|
|||||||
{
|
{
|
||||||
"description": "merging: dependencies accumulate",
|
"description": "merging: dependencies accumulate",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"base_2": {
|
||||||
"$id": "base_2",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"trigger": {
|
"trigger": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -153,7 +154,7 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"merge_2_0": {
|
||||||
"type": "base_2",
|
"type": "base_2",
|
||||||
"properties": {
|
"properties": {
|
||||||
"child_dep": {
|
"child_dep": {
|
||||||
@ -164,10 +165,9 @@
|
|||||||
"trigger": [
|
"trigger": [
|
||||||
"child_dep"
|
"child_dep"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"$id": "merge_2_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -196,7 +196,9 @@
|
|||||||
"errors": [
|
"errors": [
|
||||||
{
|
{
|
||||||
"code": "DEPENDENCY_MISSING",
|
"code": "DEPENDENCY_MISSING",
|
||||||
"details": { "path": "" }
|
"details": {
|
||||||
|
"path": ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -214,7 +216,9 @@
|
|||||||
"errors": [
|
"errors": [
|
||||||
{
|
{
|
||||||
"code": "DEPENDENCY_MISSING",
|
"code": "DEPENDENCY_MISSING",
|
||||||
"details": { "path": "" }
|
"details": {
|
||||||
|
"path": ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -224,9 +228,8 @@
|
|||||||
{
|
{
|
||||||
"description": "merging: form and display do NOT merge",
|
"description": "merging: form and display do NOT merge",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"base_3": {
|
||||||
"$id": "base_3",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"a": {
|
"a": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -240,7 +243,7 @@
|
|||||||
"b"
|
"b"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
"merge_3_0": {
|
||||||
"type": "base_3",
|
"type": "base_3",
|
||||||
"properties": {
|
"properties": {
|
||||||
"c": {
|
"c": {
|
||||||
@ -249,10 +252,9 @@
|
|||||||
},
|
},
|
||||||
"form": [
|
"form": [
|
||||||
"c"
|
"c"
|
||||||
],
|
|
||||||
"$id": "merge_3_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -93,9 +93,8 @@
|
|||||||
"types": [
|
"types": [
|
||||||
{
|
{
|
||||||
"name": "entity",
|
"name": "entity",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"entity": {
|
||||||
"$id": "entity",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
@ -131,7 +130,7 @@
|
|||||||
"modified_at"
|
"modified_at"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"entity"
|
"entity"
|
||||||
],
|
],
|
||||||
@ -162,9 +161,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "organization",
|
"name": "organization",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"organization": {
|
||||||
"$id": "organization",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
@ -172,7 +170,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"organization",
|
"organization",
|
||||||
"entity"
|
"entity"
|
||||||
@ -210,13 +208,12 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "user",
|
"name": "user",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"user": {
|
||||||
"$id": "user",
|
|
||||||
"type": "organization",
|
"type": "organization",
|
||||||
"properties": {}
|
"properties": {}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"user",
|
"user",
|
||||||
"organization",
|
"organization",
|
||||||
@ -259,9 +256,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "person",
|
"name": "person",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"person": {
|
||||||
"$id": "person",
|
|
||||||
"type": "user",
|
"type": "user",
|
||||||
"properties": {
|
"properties": {
|
||||||
"first_name": {
|
"first_name": {
|
||||||
@ -310,7 +306,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"person",
|
"person",
|
||||||
"user",
|
"user",
|
||||||
@ -373,9 +369,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "order",
|
"name": "order",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"order": {
|
||||||
"$id": "order",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"total": {
|
"total": {
|
||||||
@ -395,7 +390,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"order",
|
"order",
|
||||||
"entity"
|
"entity"
|
||||||
@ -437,9 +432,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "order_line",
|
"name": "order_line",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"order_line": {
|
||||||
"$id": "order_line",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"order_id": {
|
"order_id": {
|
||||||
@ -453,7 +447,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"order_line",
|
"order_line",
|
||||||
"entity"
|
"entity"
|
||||||
@ -546,13 +540,12 @@
|
|||||||
"modified_at": "timestamptz",
|
"modified_at": "timestamptz",
|
||||||
"modified_by": "uuid"
|
"modified_by": "uuid"
|
||||||
},
|
},
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"relationship": {
|
||||||
"$id": "relationship",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {}
|
"properties": {}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"lookup_fields": [],
|
"lookup_fields": [],
|
||||||
"historical": true,
|
"historical": true,
|
||||||
"notify": true
|
"notify": true
|
||||||
@ -616,9 +609,8 @@
|
|||||||
"modified_at": "timestamptz",
|
"modified_at": "timestamptz",
|
||||||
"modified_by": "uuid"
|
"modified_by": "uuid"
|
||||||
},
|
},
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"contact": {
|
||||||
"$id": "contact",
|
|
||||||
"type": "relationship",
|
"type": "relationship",
|
||||||
"properties": {
|
"properties": {
|
||||||
"is_primary": {
|
"is_primary": {
|
||||||
@ -626,7 +618,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"lookup_fields": [],
|
"lookup_fields": [],
|
||||||
"historical": true,
|
"historical": true,
|
||||||
"notify": true
|
"notify": true
|
||||||
@ -674,9 +666,8 @@
|
|||||||
"modified_at": "timestamptz",
|
"modified_at": "timestamptz",
|
||||||
"modified_by": "uuid"
|
"modified_by": "uuid"
|
||||||
},
|
},
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"phone_number": {
|
||||||
"$id": "phone_number",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"number": {
|
"number": {
|
||||||
@ -684,7 +675,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"lookup_fields": [],
|
"lookup_fields": [],
|
||||||
"historical": true,
|
"historical": true,
|
||||||
"notify": true,
|
"notify": true,
|
||||||
@ -733,9 +724,8 @@
|
|||||||
"modified_at": "timestamptz",
|
"modified_at": "timestamptz",
|
||||||
"modified_by": "uuid"
|
"modified_by": "uuid"
|
||||||
},
|
},
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"email_address": {
|
||||||
"$id": "email_address",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"address": {
|
"address": {
|
||||||
@ -743,7 +733,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"lookup_fields": [],
|
"lookup_fields": [],
|
||||||
"historical": true,
|
"historical": true,
|
||||||
"notify": true,
|
"notify": true,
|
||||||
@ -751,9 +741,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "attachment",
|
"name": "attachment",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_metadata": {
|
||||||
"$id": "type_metadata",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
@ -761,8 +750,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"other_metadata": {
|
||||||
"$id": "other_metadata",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"other": {
|
"other": {
|
||||||
@ -770,8 +758,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"attachment": {
|
||||||
"$id": "attachment",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"flags": {
|
"flags": {
|
||||||
@ -788,7 +775,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"attachment",
|
"attachment",
|
||||||
"entity"
|
"entity"
|
||||||
|
|||||||
@ -2,13 +2,12 @@
|
|||||||
{
|
{
|
||||||
"description": "minContains without contains is ignored",
|
"description": "minContains without contains is ignored",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minContains_0_0": {
|
||||||
"minContains": 1,
|
"minContains": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minContains_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -36,16 +35,15 @@
|
|||||||
{
|
{
|
||||||
"description": "minContains=1 with contains",
|
"description": "minContains=1 with contains",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minContains_1_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"minContains": 1,
|
"minContains": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minContains_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -108,16 +106,15 @@
|
|||||||
{
|
{
|
||||||
"description": "minContains=2 with contains",
|
"description": "minContains=2 with contains",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minContains_2_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"minContains": 2,
|
"minContains": 2,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minContains_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -195,16 +192,15 @@
|
|||||||
{
|
{
|
||||||
"description": "minContains=2 with contains with a decimal value",
|
"description": "minContains=2 with contains with a decimal value",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minContains_3_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"minContains": 2,
|
"minContains": 2,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minContains_3_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -235,17 +231,16 @@
|
|||||||
{
|
{
|
||||||
"description": "maxContains = minContains",
|
"description": "maxContains = minContains",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minContains_4_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"maxContains": 2,
|
"maxContains": 2,
|
||||||
"minContains": 2,
|
"minContains": 2,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minContains_4_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -298,17 +293,16 @@
|
|||||||
{
|
{
|
||||||
"description": "maxContains < minContains",
|
"description": "maxContains < minContains",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minContains_5_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"maxContains": 1,
|
"maxContains": 1,
|
||||||
"minContains": 3,
|
"minContains": 3,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minContains_5_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -361,16 +355,15 @@
|
|||||||
{
|
{
|
||||||
"description": "minContains = 0",
|
"description": "minContains = 0",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minContains_6_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"minContains": 0,
|
"minContains": 0,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minContains_6_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -398,17 +391,16 @@
|
|||||||
{
|
{
|
||||||
"description": "minContains = 0 with maxContains",
|
"description": "minContains = 0 with maxContains",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minContains_7_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"minContains": 0,
|
"minContains": 0,
|
||||||
"maxContains": 1,
|
"maxContains": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minContains_7_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -448,16 +440,15 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows non-matching items in minContains",
|
"description": "extensible: true allows non-matching items in minContains",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minContains_8_0": {
|
||||||
"contains": {
|
"contains": {
|
||||||
"const": 1
|
"const": 1
|
||||||
},
|
},
|
||||||
"minContains": 1,
|
"minContains": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minContains_8_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,13 +2,12 @@
|
|||||||
{
|
{
|
||||||
"description": "minItems validation",
|
"description": "minItems validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minItems_0_0": {
|
||||||
"minItems": 1,
|
"minItems": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minItems_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -57,13 +56,12 @@
|
|||||||
{
|
{
|
||||||
"description": "minItems validation with a decimal",
|
"description": "minItems validation with a decimal",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minItems_1_0": {
|
||||||
"minItems": 1,
|
"minItems": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minItems_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -92,13 +90,12 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra items in minItems",
|
"description": "extensible: true allows extra items in minItems",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minItems_2_0": {
|
||||||
"minItems": 1,
|
"minItems": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minItems_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
{
|
{
|
||||||
"description": "minLength validation",
|
"description": "minLength validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minLength_0_0": {
|
||||||
"minLength": 2,
|
"minLength": 2
|
||||||
"$id": "minLength_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -60,12 +59,11 @@
|
|||||||
{
|
{
|
||||||
"description": "minLength validation with a decimal",
|
"description": "minLength validation with a decimal",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minLength_1_0": {
|
||||||
"minLength": 2,
|
"minLength": 2
|
||||||
"$id": "minLength_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,13 +2,12 @@
|
|||||||
{
|
{
|
||||||
"description": "minProperties validation",
|
"description": "minProperties validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minProperties_0_0": {
|
||||||
"minProperties": 1,
|
"minProperties": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minProperties_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -75,13 +74,12 @@
|
|||||||
{
|
{
|
||||||
"description": "minProperties validation with a decimal",
|
"description": "minProperties validation with a decimal",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minProperties_1_0": {
|
||||||
"minProperties": 1,
|
"minProperties": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minProperties_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -110,13 +108,12 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in minProperties",
|
"description": "extensible: true allows extra properties in minProperties",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minProperties_2_0": {
|
||||||
"minProperties": 1,
|
"minProperties": 1,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "minProperties_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
{
|
{
|
||||||
"description": "minimum validation",
|
"description": "minimum validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minimum_0_0": {
|
||||||
"minimum": 1.1,
|
"minimum": 1.1
|
||||||
"$id": "minimum_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -51,12 +50,11 @@
|
|||||||
{
|
{
|
||||||
"description": "minimum validation with signed integer",
|
"description": "minimum validation with signed integer",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"minimum_1_0": {
|
||||||
"minimum": -2,
|
"minimum": -2
|
||||||
"$id": "minimum_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
{
|
{
|
||||||
"description": "by int",
|
"description": "by int",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"multipleOf_0_0": {
|
||||||
"multipleOf": 2,
|
"multipleOf": 2
|
||||||
"$id": "multipleOf_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -42,12 +41,11 @@
|
|||||||
{
|
{
|
||||||
"description": "by number",
|
"description": "by number",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"multipleOf_1_0": {
|
||||||
"multipleOf": 1.5,
|
"multipleOf": 1.5
|
||||||
"$id": "multipleOf_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -82,12 +80,11 @@
|
|||||||
{
|
{
|
||||||
"description": "by small number",
|
"description": "by small number",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"multipleOf_2_0": {
|
||||||
"multipleOf": 0.0001,
|
"multipleOf": 0.0001
|
||||||
"$id": "multipleOf_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -113,13 +110,12 @@
|
|||||||
{
|
{
|
||||||
"description": "small multiple of large integer",
|
"description": "small multiple of large integer",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"multipleOf_3_0": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"multipleOf": 1e-8,
|
"multipleOf": 1e-08
|
||||||
"$id": "multipleOf_3_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,14 +2,13 @@
|
|||||||
{
|
{
|
||||||
"description": "not",
|
"description": "not",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"not_0_0": {
|
||||||
"not": {
|
"not": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
|
||||||
"$id": "not_0_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -35,17 +34,16 @@
|
|||||||
{
|
{
|
||||||
"description": "not multiple types",
|
"description": "not multiple types",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"not_1_0": {
|
||||||
"not": {
|
"not": {
|
||||||
"type": [
|
"type": [
|
||||||
"integer",
|
"integer",
|
||||||
"boolean"
|
"boolean"
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"$id": "not_1_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -80,8 +78,8 @@
|
|||||||
{
|
{
|
||||||
"description": "not more complex schema",
|
"description": "not more complex schema",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"not_2_0": {
|
||||||
"not": {
|
"not": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -90,10 +88,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "not_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -132,16 +129,15 @@
|
|||||||
{
|
{
|
||||||
"description": "forbidden property",
|
"description": "forbidden property",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"not_3_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {
|
"foo": {
|
||||||
"not": {}
|
"not": {}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "not_3_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -170,12 +166,11 @@
|
|||||||
{
|
{
|
||||||
"description": "forbid everything with empty schema",
|
"description": "forbid everything with empty schema",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"not_4_0": {
|
||||||
"not": {},
|
"not": {}
|
||||||
"$id": "not_4_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -268,12 +263,11 @@
|
|||||||
{
|
{
|
||||||
"description": "forbid everything with boolean schema true",
|
"description": "forbid everything with boolean schema true",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"not_5_0": {
|
||||||
"not": true,
|
"not": true
|
||||||
"$id": "not_5_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -366,13 +360,12 @@
|
|||||||
{
|
{
|
||||||
"description": "allow everything with boolean schema false",
|
"description": "allow everything with boolean schema false",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"not_6_0": {
|
||||||
"not": false,
|
"not": false,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "not_6_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -465,14 +458,13 @@
|
|||||||
{
|
{
|
||||||
"description": "double negation",
|
"description": "double negation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"not_7_0": {
|
||||||
"not": {
|
"not": {
|
||||||
"not": {}
|
"not": {}
|
||||||
},
|
|
||||||
"$id": "not_7_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -489,15 +481,14 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in not",
|
"description": "extensible: true allows extra properties in not",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"not_8_0": {
|
||||||
"not": {
|
"not": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "not_8_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -516,14 +507,13 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: false (default) forbids extra properties in not",
|
"description": "extensible: false (default) forbids extra properties in not",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"not_9_0": {
|
||||||
"not": {
|
"not": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
|
||||||
"$id": "not_9_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -542,8 +532,8 @@
|
|||||||
{
|
{
|
||||||
"description": "property next to not (extensible: true)",
|
"description": "property next to not (extensible: true)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"not_10_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"bar": {
|
"bar": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -552,10 +542,9 @@
|
|||||||
"not": {
|
"not": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "not_10_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -575,8 +564,8 @@
|
|||||||
{
|
{
|
||||||
"description": "property next to not (extensible: false)",
|
"description": "property next to not (extensible: false)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"not_11_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"bar": {
|
"bar": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
@ -584,10 +573,9 @@
|
|||||||
},
|
},
|
||||||
"not": {
|
"not": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
|
||||||
"$id": "not_11_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,165 +2,181 @@
|
|||||||
{
|
{
|
||||||
"description": "Strict Inheritance",
|
"description": "Strict Inheritance",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"parent_type": {
|
||||||
"$id": "parent_type",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {"a": {"type": "integer"}},
|
"properties": {
|
||||||
"required": ["a"]
|
"a": {
|
||||||
},
|
"type": "integer"
|
||||||
{
|
|
||||||
"$id": "child_type",
|
|
||||||
"type": "parent_type",
|
|
||||||
"properties": {"b": {"type": "integer"}}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"a"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"child_type": {
|
||||||
|
"type": "parent_type",
|
||||||
|
"properties": {
|
||||||
|
"b": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"description": "valid child inherits properties and strictness",
|
"description": "valid child inherits properties and strictness",
|
||||||
"schema_id": "child_type",
|
"schema_id": "child_type",
|
||||||
"data": {"a": 1, "b": 2},
|
"data": {
|
||||||
|
"a": 1,
|
||||||
|
"b": 2
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {"success": true}
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "missing inherited required property fails",
|
"description": "missing inherited required property fails",
|
||||||
"schema_id": "child_type",
|
"schema_id": "child_type",
|
||||||
"data": {"b": 2},
|
"data": {
|
||||||
|
"b": 2
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {"success": false}
|
"expect": {
|
||||||
|
"success": false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "additional properties fail due to inherited strictness",
|
"description": "additional properties fail due to inherited strictness",
|
||||||
"schema_id": "child_type",
|
"schema_id": "child_type",
|
||||||
"data": {"a": 1, "b": 2, "c": 3},
|
"data": {
|
||||||
|
"a": 1,
|
||||||
|
"b": 2,
|
||||||
|
"c": 3
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {"success": false}
|
"expect": {
|
||||||
|
"success": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Local Shadowing (Composition & Proxies)",
|
"description": "Local Shadowing (Composition & Proxies)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"budget": {
|
||||||
"$id": "budget",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"max": {"type": "integer", "maximum": 100}
|
"max": {
|
||||||
|
"type": "integer",
|
||||||
|
"maximum": 100
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"custom_budget": {
|
||||||
"$id": "custom_budget",
|
|
||||||
"type": "budget",
|
"type": "budget",
|
||||||
"properties": {
|
"properties": {
|
||||||
"max": {"type": "integer", "maximum": 50}
|
"max": {
|
||||||
|
"type": "integer",
|
||||||
|
"maximum": 50
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"description": "shadowing override applies (50 is locally allowed)",
|
"description": "shadowing override applies (50 is locally allowed)",
|
||||||
"schema_id": "custom_budget",
|
"schema_id": "custom_budget",
|
||||||
"data": {"max": 40},
|
"data": {
|
||||||
|
"max": 40
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {"success": true}
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "shadowing override applies natively, rejecting 60 even though parent allowed 100",
|
"description": "shadowing override applies natively, rejecting 60 even though parent allowed 100",
|
||||||
"schema_id": "custom_budget",
|
"schema_id": "custom_budget",
|
||||||
"data": {"max": 60},
|
|
||||||
"action": "validate",
|
|
||||||
"expect": {"success": false}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Inline id Resolution",
|
|
||||||
"database": {
|
|
||||||
"schemas": [
|
|
||||||
{
|
|
||||||
"$id": "api.request",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"inline_obj": {
|
|
||||||
"$id": "inline_nested",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {"foo": {"type": "string"}},
|
|
||||||
"required": ["foo"]
|
|
||||||
},
|
|
||||||
"proxy_obj": {
|
|
||||||
"type": "inline_nested"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "proxy resolves and validates to the inline component",
|
|
||||||
"schema_id": "api.request",
|
|
||||||
"data": {
|
"data": {
|
||||||
"inline_obj": {"foo": "bar"},
|
"max": 60
|
||||||
"proxy_obj": {"foo": "baz"}
|
|
||||||
},
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {"success": true}
|
"expect": {
|
||||||
},
|
"success": false
|
||||||
{
|
}
|
||||||
"description": "proxy resolves and catches violation targeting inline component constraints",
|
|
||||||
"schema_id": "api.request",
|
|
||||||
"data": {
|
|
||||||
"inline_obj": {"foo": "bar"},
|
|
||||||
"proxy_obj": {}
|
|
||||||
},
|
|
||||||
"action": "validate",
|
|
||||||
"expect": {"success": false}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Primitive Array Shorthand (Optionality)",
|
"description": "Primitive Array Shorthand (Optionality)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"invoice": {
|
||||||
"$id": "invoice",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {"amount": {"type": "integer"}},
|
|
||||||
"required": ["amount"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$id": "request",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"inv": {"type": ["invoice", "null"]}
|
"amount": {
|
||||||
}
|
"type": "integer"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"amount"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"request": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"inv": {
|
||||||
|
"type": [
|
||||||
|
"invoice",
|
||||||
|
"null"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"description": "valid object passes shorthand inheritance check",
|
"description": "valid object passes shorthand inheritance check",
|
||||||
"schema_id": "request",
|
"schema_id": "request",
|
||||||
"data": {"inv": {"amount": 5}},
|
"data": {
|
||||||
|
"inv": {
|
||||||
|
"amount": 5
|
||||||
|
}
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {"success": true}
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "null passes shorthand inheritance check",
|
"description": "null passes shorthand inheritance check",
|
||||||
"schema_id": "request",
|
"schema_id": "request",
|
||||||
"data": {"inv": null},
|
"data": {
|
||||||
|
"inv": null
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {"success": true}
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "invalid object fails inner constraints safely",
|
"description": "invalid object fails inner constraints safely",
|
||||||
"schema_id": "request",
|
"schema_id": "request",
|
||||||
"data": {"inv": {"amount": "string"}},
|
"data": {
|
||||||
|
"inv": {
|
||||||
|
"amount": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {"success": false}
|
"expect": {
|
||||||
|
"success": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,8 @@
|
|||||||
{
|
{
|
||||||
"description": "Hybrid Array Pathing",
|
"description": "Hybrid Array Pathing",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"hybrid_pathing": {
|
||||||
"$id": "hybrid_pathing",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"primitives": {
|
"primitives": {
|
||||||
@ -69,7 +68,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -123,7 +122,9 @@
|
|||||||
"errors": [
|
"errors": [
|
||||||
{
|
{
|
||||||
"code": "INVALID_TYPE",
|
"code": "INVALID_TYPE",
|
||||||
"details": { "path": "primitives/1" }
|
"details": {
|
||||||
|
"path": "primitives/1"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -147,11 +148,15 @@
|
|||||||
"errors": [
|
"errors": [
|
||||||
{
|
{
|
||||||
"code": "REQUIRED_FIELD_MISSING",
|
"code": "REQUIRED_FIELD_MISSING",
|
||||||
"details": { "path": "ad_hoc_objects/1/name" }
|
"details": {
|
||||||
|
"path": "ad_hoc_objects/1/name"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "STRICT_PROPERTY_VIOLATION",
|
"code": "STRICT_PROPERTY_VIOLATION",
|
||||||
"details": { "path": "ad_hoc_objects/1/age" }
|
"details": {
|
||||||
|
"path": "ad_hoc_objects/1/age"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -177,7 +182,9 @@
|
|||||||
"errors": [
|
"errors": [
|
||||||
{
|
{
|
||||||
"code": "MINIMUM_VIOLATED",
|
"code": "MINIMUM_VIOLATED",
|
||||||
"details": { "path": "entities/entity-beta/value" }
|
"details": {
|
||||||
|
"path": "entities/entity-beta/value"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -208,51 +215,20 @@
|
|||||||
"errors": [
|
"errors": [
|
||||||
{
|
{
|
||||||
"code": "INVALID_TYPE",
|
"code": "INVALID_TYPE",
|
||||||
"details": { "path": "deep_entities/parent-omega/nested/child-beta/flag" }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Polymorphic Structure Pathing",
|
|
||||||
"database": {
|
|
||||||
"types": [
|
|
||||||
{
|
|
||||||
"name": "widget",
|
|
||||||
"variations": ["widget"],
|
|
||||||
"schemas": [
|
|
||||||
{
|
|
||||||
"$id": "widget",
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"id": { "type": "string" },
|
|
||||||
"type": { "type": "string" }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$id": "stock.widget",
|
|
||||||
"type": "widget",
|
|
||||||
"properties": {
|
|
||||||
"kind": { "type": "string" },
|
|
||||||
"amount": { "type": "integer" },
|
|
||||||
"details": {
|
"details": {
|
||||||
"type": "object",
|
"path": "deep_entities/parent-omega/nested/child-beta/flag"
|
||||||
"properties": {
|
|
||||||
"nested_metric": { "type": "number" }
|
|
||||||
},
|
|
||||||
"required": ["nested_metric"]
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"required": ["amount", "details"]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
}
|
||||||
"schemas": [
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"$id": "polymorphic_pathing",
|
"description": "Ad-Hoc Union Pathing",
|
||||||
|
"database": {
|
||||||
|
"schemas": {
|
||||||
|
"ad_hoc_pathing": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"metadata_bubbles": {
|
"metadata_bubbles": {
|
||||||
@ -260,26 +236,98 @@
|
|||||||
"items": {
|
"items": {
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{
|
{
|
||||||
"$id": "contact_metadata",
|
"type": "string"
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"type": { "const": "contact" },
|
|
||||||
"phone": { "type": "string" }
|
|
||||||
},
|
|
||||||
"required": ["phone"]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"$id": "invoice_metadata",
|
"type": "integer"
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"type": { "const": "invoice" },
|
|
||||||
"invoice_id": { "type": "integer" }
|
|
||||||
},
|
|
||||||
"required": ["invoice_id"]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
"tests": [
|
||||||
|
{
|
||||||
|
"description": "oneOf arrays natively support disjoint primitive types dynamically mapped into topological paths natively",
|
||||||
|
"data": {
|
||||||
|
"metadata_bubbles": [
|
||||||
|
100,
|
||||||
|
"metadata string",
|
||||||
|
true
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"schema_id": "ad_hoc_pathing",
|
||||||
|
"action": "validate",
|
||||||
|
"expect": {
|
||||||
|
"success": false,
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": "NO_ONEOF_MATCH",
|
||||||
|
"details": {
|
||||||
|
"path": "metadata_bubbles/2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Polymorphic Family Pathing",
|
||||||
|
"database": {
|
||||||
|
"types": [
|
||||||
|
{
|
||||||
|
"name": "widget",
|
||||||
|
"variations": [
|
||||||
|
"widget"
|
||||||
|
],
|
||||||
|
"schemas": {
|
||||||
|
"widget": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"stock.widget": {
|
||||||
|
"type": "widget",
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"details": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"nested_metric": {
|
||||||
|
"type": "number"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"nested_metric"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"amount",
|
||||||
|
"details"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"schemas": {
|
||||||
|
"family_pathing": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
"table_families": {
|
"table_families": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@ -288,33 +336,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
|
||||||
"description": "oneOf tags natively bubble specific schema paths into deep array roots",
|
|
||||||
"data": {
|
|
||||||
"metadata_bubbles": [
|
|
||||||
{ "type": "invoice", "invoice_id": 100 },
|
|
||||||
{ "type": "contact", "phone": 12345, "rogue_field": "x" }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"schema_id": "polymorphic_pathing",
|
|
||||||
"action": "validate",
|
|
||||||
"expect": {
|
|
||||||
"success": false,
|
|
||||||
"errors": [
|
|
||||||
{
|
|
||||||
"code": "INVALID_TYPE",
|
|
||||||
"details": { "path": "metadata_bubbles/1/phone" }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"code": "STRICT_PROPERTY_VIOLATION",
|
|
||||||
"details": { "path": "metadata_bubbles/1/rogue_field" }
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"description": "families mechanically map physical variants directly onto topological uuid array paths",
|
"description": "families mechanically map physical variants directly onto topological uuid array paths",
|
||||||
"data": {
|
"data": {
|
||||||
@ -324,7 +349,9 @@
|
|||||||
"type": "widget",
|
"type": "widget",
|
||||||
"kind": "stock",
|
"kind": "stock",
|
||||||
"amount": 500,
|
"amount": 500,
|
||||||
"details": { "nested_metric": 42.0 }
|
"details": {
|
||||||
|
"nested_metric": 42.0
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "widget-2",
|
"id": "widget-2",
|
||||||
@ -338,26 +365,34 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"schema_id": "polymorphic_pathing",
|
"schema_id": "family_pathing",
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {
|
"expect": {
|
||||||
"success": false,
|
"success": false,
|
||||||
"errors": [
|
"errors": [
|
||||||
{
|
{
|
||||||
"code": "INVALID_TYPE",
|
"code": "INVALID_TYPE",
|
||||||
"details": { "path": "table_families/widget-2/amount" }
|
"details": {
|
||||||
|
"path": "table_families/widget-2/amount"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "REQUIRED_FIELD_MISSING",
|
"code": "REQUIRED_FIELD_MISSING",
|
||||||
"details": { "path": "table_families/widget-2/details/nested_metric" }
|
"details": {
|
||||||
|
"path": "table_families/widget-2/details/nested_metric"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "STRICT_PROPERTY_VIOLATION",
|
"code": "STRICT_PROPERTY_VIOLATION",
|
||||||
"details": { "path": "table_families/widget-2/details/stray_child" }
|
"details": {
|
||||||
|
"path": "table_families/widget-2/details/stray_child"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "STRICT_PROPERTY_VIOLATION",
|
"code": "STRICT_PROPERTY_VIOLATION",
|
||||||
"details": { "path": "table_families/widget-2/unexpected_root_prop" }
|
"details": {
|
||||||
|
"path": "table_families/widget-2/unexpected_root_prop"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
{
|
{
|
||||||
"description": "pattern validation",
|
"description": "pattern validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"pattern_0_0": {
|
||||||
"pattern": "^a*$",
|
"pattern": "^a*$"
|
||||||
"$id": "pattern_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -87,12 +86,11 @@
|
|||||||
{
|
{
|
||||||
"description": "pattern is not anchored",
|
"description": "pattern is not anchored",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"pattern_1_0": {
|
||||||
"pattern": "a+",
|
"pattern": "a+"
|
||||||
"$id": "pattern_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,17 +2,16 @@
|
|||||||
{
|
{
|
||||||
"description": "patternProperties validates properties matching a regex",
|
"description": "patternProperties validates properties matching a regex",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"patternProperties_0_0": {
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"f.*o": {
|
"f.*o": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"items": {},
|
"items": {}
|
||||||
"$id": "patternProperties_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -108,8 +107,8 @@
|
|||||||
{
|
{
|
||||||
"description": "multiple simultaneous patternProperties are validated",
|
"description": "multiple simultaneous patternProperties are validated",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"patternProperties_1_0": {
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"a*": {
|
"a*": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
@ -117,10 +116,9 @@
|
|||||||
"aaa*": {
|
"aaa*": {
|
||||||
"maximum": 20
|
"maximum": 20
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "patternProperties_1_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -196,8 +194,8 @@
|
|||||||
{
|
{
|
||||||
"description": "regexes are not anchored by default and are case sensitive",
|
"description": "regexes are not anchored by default and are case sensitive",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"patternProperties_2_0": {
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"[0-9]{2,}": {
|
"[0-9]{2,}": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@ -206,10 +204,9 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "patternProperties_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -261,15 +258,14 @@
|
|||||||
{
|
{
|
||||||
"description": "patternProperties with boolean schemas",
|
"description": "patternProperties with boolean schemas",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"patternProperties_3_0": {
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"f.*": true,
|
"f.*": true,
|
||||||
"b.*": false
|
"b.*": false
|
||||||
},
|
|
||||||
"$id": "patternProperties_3_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -331,16 +327,15 @@
|
|||||||
{
|
{
|
||||||
"description": "patternProperties with null valued instance properties",
|
"description": "patternProperties with null valued instance properties",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"patternProperties_4_0": {
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"^.*bar$": {
|
"^.*bar$": {
|
||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "patternProperties_4_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -359,17 +354,16 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties NOT matching pattern",
|
"description": "extensible: true allows extra properties NOT matching pattern",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"patternProperties_5_0": {
|
||||||
"patternProperties": {
|
"patternProperties": {
|
||||||
"f.*o": {
|
"f.*o": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "patternProperties_5_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,93 +5,147 @@
|
|||||||
"types": [
|
"types": [
|
||||||
{
|
{
|
||||||
"name": "entity",
|
"name": "entity",
|
||||||
"variations": ["entity", "organization", "person", "bot"],
|
"variations": [
|
||||||
"schemas": [
|
"entity",
|
||||||
{
|
"organization",
|
||||||
"$id": "entity",
|
"person",
|
||||||
|
"bot"
|
||||||
|
],
|
||||||
|
"schemas": {
|
||||||
|
"entity": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": { "type": "string" },
|
"type": {
|
||||||
"id": { "type": "string" }
|
"type": "string"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "organization",
|
"name": "organization",
|
||||||
"variations": ["organization", "person"],
|
"variations": [
|
||||||
"schemas": [
|
"organization",
|
||||||
{
|
"person"
|
||||||
"$id": "organization",
|
],
|
||||||
|
"schemas": {
|
||||||
|
"organization": {
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": { "type": "string" }
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "person",
|
"name": "person",
|
||||||
"variations": ["person"],
|
"variations": [
|
||||||
"schemas": [
|
"person"
|
||||||
{
|
],
|
||||||
"$id": "person",
|
"schemas": {
|
||||||
|
"person": {
|
||||||
"type": "organization",
|
"type": "organization",
|
||||||
"properties": {
|
"properties": {
|
||||||
"first_name": { "type": "string" }
|
"first_name": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bot",
|
"name": "bot",
|
||||||
"variations": ["bot"],
|
"variations": [
|
||||||
"schemas": [
|
"bot"
|
||||||
{
|
],
|
||||||
"$id": "bot",
|
"schemas": {
|
||||||
|
"bot": {
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"model": { "type": "string" }
|
"model": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"family_entity": {
|
||||||
"$id": "family_entity",
|
|
||||||
"$family": "entity"
|
"$family": "entity"
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"description": "Matches base entity",
|
"description": "Matches base entity",
|
||||||
"schema_id": "family_entity",
|
"schema_id": "family_entity",
|
||||||
"data": { "type": "entity", "id": "1" },
|
"data": {
|
||||||
|
"type": "entity",
|
||||||
|
"id": "1"
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Matches descendant person natively",
|
"description": "Matches descendant person natively",
|
||||||
"schema_id": "family_entity",
|
"schema_id": "family_entity",
|
||||||
"data": { "type": "person", "id": "2", "first_name": "Bob" },
|
"data": {
|
||||||
|
"type": "person",
|
||||||
|
"id": "2",
|
||||||
|
"first_name": "Bob"
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Missing type fails out immediately",
|
"description": "Missing type fails out immediately",
|
||||||
"schema_id": "family_entity",
|
"schema_id": "family_entity",
|
||||||
"data": { "id": "3", "first_name": "Bob" },
|
"data": {
|
||||||
|
"id": "3",
|
||||||
|
"first_name": "Bob"
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": false, "errors": [ { "code": "MISSING_TYPE", "details": { "path": "" } } ] }
|
"expect": {
|
||||||
|
"success": false,
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": "MISSING_TYPE",
|
||||||
|
"details": {
|
||||||
|
"path": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Alias matching failure",
|
"description": "Alias matching failure",
|
||||||
"schema_id": "family_entity",
|
"schema_id": "family_entity",
|
||||||
"data": { "type": "alien", "id": "4" },
|
"data": {
|
||||||
|
"type": "alien",
|
||||||
|
"id": "4"
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": false, "errors": [ { "code": "NO_FAMILY_MATCH", "details": { "path": "" } } ] }
|
"expect": {
|
||||||
|
"success": false,
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": "NO_FAMILY_MATCH",
|
||||||
|
"details": {
|
||||||
|
"path": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -101,95 +155,125 @@
|
|||||||
"types": [
|
"types": [
|
||||||
{
|
{
|
||||||
"name": "entity",
|
"name": "entity",
|
||||||
"variations": ["entity", "organization", "person", "bot"],
|
"variations": [
|
||||||
"schemas": [
|
"entity",
|
||||||
{
|
"organization",
|
||||||
"$id": "entity",
|
"person",
|
||||||
|
"bot"
|
||||||
|
],
|
||||||
|
"schemas": {
|
||||||
|
"entity": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": { "type": "string" }
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"light.entity": {
|
||||||
"$id": "light.entity",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"kind": { "type": "string" }
|
"kind": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "organization",
|
"name": "organization",
|
||||||
"variations": ["organization", "person"],
|
"variations": [
|
||||||
"schemas": [
|
"organization",
|
||||||
{
|
"person"
|
||||||
"$id": "organization",
|
],
|
||||||
|
"schemas": {
|
||||||
|
"organization": {
|
||||||
"type": "entity"
|
"type": "entity"
|
||||||
},
|
},
|
||||||
{
|
"light.organization": {
|
||||||
"$id": "light.organization",
|
|
||||||
"type": "light.entity"
|
"type": "light.entity"
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "person",
|
"name": "person",
|
||||||
"variations": ["person"],
|
"variations": [
|
||||||
"schemas": [
|
"person"
|
||||||
{
|
],
|
||||||
"$id": "person",
|
"schemas": {
|
||||||
|
"person": {
|
||||||
"type": "organization"
|
"type": "organization"
|
||||||
},
|
},
|
||||||
{
|
"light.person": {
|
||||||
"$id": "light.person",
|
|
||||||
"type": "light.organization"
|
"type": "light.organization"
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bot",
|
"name": "bot",
|
||||||
"variations": ["bot"],
|
"variations": [
|
||||||
"schemas": [
|
"bot"
|
||||||
{
|
],
|
||||||
"$id": "bot",
|
"schemas": {
|
||||||
|
"bot": {
|
||||||
"type": "entity"
|
"type": "entity"
|
||||||
},
|
},
|
||||||
{
|
"light.bot": {
|
||||||
"$id": "light.bot",
|
|
||||||
"type": "light.entity"
|
"type": "light.entity"
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"family_light_org": {
|
||||||
"$id": "family_light_org",
|
|
||||||
"$family": "light.organization"
|
"$family": "light.organization"
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"description": "Matches light.organization exact matrix target",
|
"description": "Matches light.organization exact matrix target",
|
||||||
"schema_id": "family_light_org",
|
"schema_id": "family_light_org",
|
||||||
"data": { "type": "organization", "kind": "light" },
|
"data": {
|
||||||
|
"type": "organization",
|
||||||
|
"kind": "light"
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Matches descendant light.person through matrix evaluation",
|
"description": "Matches descendant light.person through matrix evaluation",
|
||||||
"schema_id": "family_light_org",
|
"schema_id": "family_light_org",
|
||||||
"data": { "type": "person", "kind": "light" },
|
"data": {
|
||||||
|
"type": "person",
|
||||||
|
"kind": "light"
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Structurally fails to route bot (bot is not descendant of organization)",
|
"description": "Structurally fails to route bot (bot is not descendant of organization)",
|
||||||
"schema_id": "family_light_org",
|
"schema_id": "family_light_org",
|
||||||
"data": { "type": "bot", "kind": "light" },
|
"data": {
|
||||||
|
"type": "bot",
|
||||||
|
"kind": "light"
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": false, "errors": [ { "code": "NO_FAMILY_MATCH", "details": { "path": "" } } ] }
|
"expect": {
|
||||||
|
"success": false,
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": "NO_FAMILY_MATCH",
|
||||||
|
"details": {
|
||||||
|
"path": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -199,72 +283,112 @@
|
|||||||
"types": [
|
"types": [
|
||||||
{
|
{
|
||||||
"name": "widget",
|
"name": "widget",
|
||||||
"variations": ["widget"],
|
"variations": [
|
||||||
"schemas": [
|
"widget"
|
||||||
{
|
],
|
||||||
"$id": "widget",
|
"schemas": {
|
||||||
|
"widget": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": { "type": "string" }
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"stock.widget": {
|
||||||
"$id": "stock.widget",
|
|
||||||
"type": "widget",
|
"type": "widget",
|
||||||
"properties": {
|
"properties": {
|
||||||
"kind": { "type": "string" },
|
"kind": {
|
||||||
"amount": { "type": "integer" }
|
"type": "string"
|
||||||
|
},
|
||||||
|
"amount": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"super_stock.widget": {
|
||||||
"$id": "super_stock.widget",
|
|
||||||
"type": "stock.widget",
|
"type": "stock.widget",
|
||||||
"properties": {
|
"properties": {
|
||||||
"super_amount": { "type": "integer" }
|
"super_amount": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"family_widget": {
|
||||||
"$id": "family_widget",
|
|
||||||
"$family": "widget"
|
"$family": "widget"
|
||||||
},
|
},
|
||||||
{
|
"family_stock_widget": {
|
||||||
"$id": "family_stock_widget",
|
|
||||||
"$family": "stock.widget"
|
"$family": "stock.widget"
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"description": "Base widget resolves stock widget horizontally",
|
"description": "Base widget resolves stock widget horizontally",
|
||||||
"schema_id": "family_widget",
|
"schema_id": "family_widget",
|
||||||
"data": { "type": "widget", "kind": "stock", "amount": 5 },
|
"data": {
|
||||||
|
"type": "widget",
|
||||||
|
"kind": "stock",
|
||||||
|
"amount": 5
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Base widget resolves nested super stock widget natively via descendants crawl",
|
"description": "Base widget resolves nested super stock widget natively via descendants crawl",
|
||||||
"schema_id": "family_widget",
|
"schema_id": "family_widget",
|
||||||
"data": { "type": "widget", "kind": "super_stock", "amount": 5, "super_amount": 10 },
|
"data": {
|
||||||
|
"type": "widget",
|
||||||
|
"kind": "super_stock",
|
||||||
|
"amount": 5,
|
||||||
|
"super_amount": 10
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "stock.widget explicit family resolves nested super stock via fast path",
|
"description": "stock.widget explicit family resolves nested super stock via fast path",
|
||||||
"schema_id": "family_stock_widget",
|
"schema_id": "family_stock_widget",
|
||||||
"data": { "type": "widget", "kind": "super_stock", "amount": 5, "super_amount": 10 },
|
"data": {
|
||||||
|
"type": "widget",
|
||||||
|
"kind": "super_stock",
|
||||||
|
"amount": 5,
|
||||||
|
"super_amount": 10
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "stock.widget fails when presented an invalid payload constraint",
|
"description": "stock.widget fails when presented an invalid payload constraint",
|
||||||
"schema_id": "family_stock_widget",
|
"schema_id": "family_stock_widget",
|
||||||
"data": { "type": "widget", "kind": "super_stock", "amount": 5, "super_amount": "not_an_int" },
|
"data": {
|
||||||
|
"type": "widget",
|
||||||
|
"kind": "super_stock",
|
||||||
|
"amount": 5,
|
||||||
|
"super_amount": "not_an_int"
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": false, "errors": [ { "code": "INVALID_TYPE", "details": { "path": "super_amount" } } ] }
|
"expect": {
|
||||||
|
"success": false,
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": "INVALID_TYPE",
|
||||||
|
"details": {
|
||||||
|
"path": "super_amount"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -274,212 +398,241 @@
|
|||||||
"types": [
|
"types": [
|
||||||
{
|
{
|
||||||
"name": "entity",
|
"name": "entity",
|
||||||
"variations": ["entity", "person", "bot"],
|
"variations": [
|
||||||
"schemas": [
|
"entity",
|
||||||
{
|
"person",
|
||||||
"$id": "entity",
|
"bot"
|
||||||
|
],
|
||||||
|
"schemas": {
|
||||||
|
"entity": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": { "type": "string" }
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "person",
|
"name": "person",
|
||||||
"variations": ["person"],
|
"variations": [
|
||||||
"schemas": [
|
"person"
|
||||||
{
|
],
|
||||||
"$id": "person",
|
"schemas": {
|
||||||
|
"person": {
|
||||||
"type": "entity"
|
"type": "entity"
|
||||||
},
|
},
|
||||||
{
|
"full.person": {
|
||||||
"$id": "full.person",
|
|
||||||
"type": "person",
|
"type": "person",
|
||||||
"properties": {
|
"properties": {
|
||||||
"kind": { "type": "string" },
|
"kind": {
|
||||||
"age": { "type": "integer" }
|
"type": "string"
|
||||||
},
|
},
|
||||||
"required": ["age"]
|
"age": {
|
||||||
|
"type": "integer"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"age"
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bot",
|
"name": "bot",
|
||||||
"variations": ["bot"],
|
"variations": [
|
||||||
"schemas": [
|
"bot"
|
||||||
{
|
],
|
||||||
"$id": "bot",
|
"schemas": {
|
||||||
|
"bot": {
|
||||||
"type": "entity"
|
"type": "entity"
|
||||||
},
|
},
|
||||||
{
|
"full.bot": {
|
||||||
"$id": "full.bot",
|
|
||||||
"type": "bot",
|
"type": "bot",
|
||||||
"properties": {
|
"properties": {
|
||||||
"kind": { "type": "string" },
|
"kind": {
|
||||||
"version": { "type": "string" }
|
"type": "string"
|
||||||
},
|
},
|
||||||
"required": ["version"]
|
"version": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"version"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"oneOf_union": {
|
||||||
"$id": "oneOf_union",
|
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{ "type": "full.person" },
|
{
|
||||||
{ "type": "full.bot" }
|
"type": "full.person"
|
||||||
]
|
},
|
||||||
|
{
|
||||||
|
"type": "full.bot"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"description": "Throws MISSING_TYPE if discriminator matches neither",
|
"description": "Throws MISSING_TYPE if discriminator matches neither",
|
||||||
"schema_id": "oneOf_union",
|
"schema_id": "oneOf_union",
|
||||||
"data": { "kind": "full", "age": 5 },
|
"data": {
|
||||||
|
"kind": "full",
|
||||||
|
"age": 5
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": false, "errors": [ { "code": "MISSING_TYPE", "details": { "path": "" } } ] }
|
"expect": {
|
||||||
|
"success": false,
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": "MISSING_TYPE",
|
||||||
|
"details": {
|
||||||
|
"path": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Golden match throws pure structural error exclusively on person",
|
"description": "Golden match throws pure structural error exclusively on person",
|
||||||
"schema_id": "oneOf_union",
|
"schema_id": "oneOf_union",
|
||||||
"data": { "type": "person", "kind": "full", "age": "five" },
|
"data": {
|
||||||
|
"type": "person",
|
||||||
|
"kind": "full",
|
||||||
|
"age": "five"
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": false, "errors": [ { "code": "INVALID_TYPE", "details": { "path": "age" } } ] }
|
"expect": {
|
||||||
|
"success": false,
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": "INVALID_TYPE",
|
||||||
|
"details": {
|
||||||
|
"path": "age"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Golden matches perfectly",
|
"description": "Golden matches perfectly",
|
||||||
"schema_id": "oneOf_union",
|
"schema_id": "oneOf_union",
|
||||||
"data": { "type": "person", "kind": "full", "age": 5 },
|
"data": {
|
||||||
|
"type": "person",
|
||||||
|
"kind": "full",
|
||||||
|
"age": 5
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": true }
|
"expect": {
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Fails nicely with NO_ONEOF_MATCH",
|
"description": "Fails nicely with NO_ONEOF_MATCH",
|
||||||
"schema_id": "oneOf_union",
|
"schema_id": "oneOf_union",
|
||||||
"data": { "type": "alien", "kind": "full", "age": 5 },
|
"data": {
|
||||||
|
"type": "alien",
|
||||||
|
"kind": "full",
|
||||||
|
"age": 5
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": { "success": false, "errors": [ { "code": "NO_ONEOF_MATCH", "details": { "path": "" } } ] }
|
"expect": {
|
||||||
|
"success": false,
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": "NO_ONEOF_MATCH",
|
||||||
|
"details": {
|
||||||
|
"path": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "JSONB Field Bubble oneOf Discrimination (Promoted IDs)",
|
"description": "JSONB Field Bubble oneOf Discrimination (Promoted IDs)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"metadata": {
|
||||||
"$id": "metadata",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": { "type": "string" }
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"invoice.metadata": {
|
||||||
"$id": "invoice.metadata",
|
|
||||||
"type": "metadata",
|
"type": "metadata",
|
||||||
"properties": {
|
"properties": {
|
||||||
"invoice_id": { "type": "integer" }
|
"invoice_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"required": ["invoice_id"]
|
"required": [
|
||||||
|
"invoice_id"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
"payment.metadata": {
|
||||||
"$id": "payment.metadata",
|
|
||||||
"type": "metadata",
|
"type": "metadata",
|
||||||
"properties": {
|
"properties": {
|
||||||
"payment_id": { "type": "integer" }
|
"payment_id": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"required": ["payment_id"]
|
"required": [
|
||||||
|
"payment_id"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
"oneOf_bubble": {
|
||||||
"$id": "oneOf_bubble",
|
|
||||||
"oneOf": [
|
"oneOf": [
|
||||||
{ "type": "invoice.metadata" },
|
{
|
||||||
{ "type": "payment.metadata" }
|
"type": "invoice.metadata"
|
||||||
]
|
},
|
||||||
|
{
|
||||||
|
"type": "payment.metadata"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
"description": "Extracts golden match natively from explicit JSONB type discriminator",
|
"description": "Extracts golden match natively from explicit JSONB type discriminator",
|
||||||
"schema_id": "oneOf_bubble",
|
"schema_id": "oneOf_bubble",
|
||||||
"data": { "type": "invoice.metadata", "invoice_id": "nan" },
|
"data": {
|
||||||
|
"type": "invoice.metadata",
|
||||||
|
"invoice_id": "nan"
|
||||||
|
},
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {
|
"expect": {
|
||||||
"success": false,
|
"success": false,
|
||||||
"errors": [ { "code": "INVALID_TYPE", "details": { "path": "invoice_id" } } ]
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": "INVALID_TYPE",
|
||||||
|
"details": {
|
||||||
|
"path": "invoice_id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Valid payload succeeds perfectly in JSONB universe",
|
"description": "Valid payload succeeds perfectly in JSONB universe",
|
||||||
"schema_id": "oneOf_bubble",
|
"schema_id": "oneOf_bubble",
|
||||||
"data": { "type": "payment.metadata", "payment_id": 123 },
|
"data": {
|
||||||
"action": "validate",
|
"type": "payment.metadata",
|
||||||
"expect": { "success": true }
|
"payment_id": 123
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"description": "Standard JSON Schema oneOf",
|
|
||||||
"database": {
|
|
||||||
"schemas": [
|
|
||||||
{
|
|
||||||
"$id": "oneOf_scalars",
|
|
||||||
"oneOf": [
|
|
||||||
{ "type": "integer" },
|
|
||||||
{ "minimum": 2 }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"$id": "oneOf_dedupe",
|
|
||||||
"oneOf": [
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"shared": { "type": "integer" }
|
|
||||||
},
|
|
||||||
"required": ["shared"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"shared": { "type": "integer" },
|
|
||||||
"extra": { "type": "string" }
|
|
||||||
},
|
|
||||||
"required": ["shared", "extra"]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"tests": [
|
|
||||||
{
|
|
||||||
"description": "Valid exclusively against first scalar choice",
|
|
||||||
"schema_id": "oneOf_scalars",
|
|
||||||
"data": 1,
|
|
||||||
"action": "validate",
|
|
||||||
"expect": { "success": true }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Fails mathematically if matches both schemas natively",
|
|
||||||
"schema_id": "oneOf_scalars",
|
|
||||||
"data": 3,
|
|
||||||
"action": "validate",
|
|
||||||
"expect": { "success": false }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Deduper merges shared errors dynamically exactly like JSON Schema",
|
|
||||||
"schema_id": "oneOf_dedupe",
|
|
||||||
"data": { "shared": "nan" },
|
|
||||||
"action": "validate",
|
"action": "validate",
|
||||||
"expect": {
|
"expect": {
|
||||||
"success": false,
|
"success": true
|
||||||
"errors": [
|
|
||||||
{ "code": "NO_ONEOF_MATCH", "details": { "path": "" } },
|
|
||||||
{ "code": "INVALID_TYPE", "details": { "path": "shared" } }
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
{
|
{
|
||||||
"description": "a schema given for prefixItems",
|
"description": "a schema given for prefixItems",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"prefixItems_0_0": {
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
@ -11,10 +11,9 @@
|
|||||||
{
|
{
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"$id": "prefixItems_0_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -92,15 +91,14 @@
|
|||||||
{
|
{
|
||||||
"description": "prefixItems with boolean schemas",
|
"description": "prefixItems with boolean schemas",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"prefixItems_1_0": {
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
true,
|
true,
|
||||||
false
|
false
|
||||||
],
|
|
||||||
"$id": "prefixItems_1_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -140,17 +138,16 @@
|
|||||||
{
|
{
|
||||||
"description": "additional items are allowed by default",
|
"description": "additional items are allowed by default",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"prefixItems_2_0": {
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "prefixItems_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -171,16 +168,15 @@
|
|||||||
{
|
{
|
||||||
"description": "prefixItems with null instance elements",
|
"description": "prefixItems with null instance elements",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"prefixItems_3_0": {
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"$id": "prefixItems_3_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -199,17 +195,16 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra items with prefixItems",
|
"description": "extensible: true allows extra items with prefixItems",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"prefixItems_4_0": {
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "prefixItems_4_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,12 +2,11 @@
|
|||||||
{
|
{
|
||||||
"description": "integer type matches integers",
|
"description": "integer type matches integers",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_0_0": {
|
||||||
"type": "integer",
|
"type": "integer"
|
||||||
"$id": "type_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -96,12 +95,11 @@
|
|||||||
{
|
{
|
||||||
"description": "number type matches numbers",
|
"description": "number type matches numbers",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_1_0": {
|
||||||
"type": "number",
|
"type": "number"
|
||||||
"$id": "type_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -190,12 +188,11 @@
|
|||||||
{
|
{
|
||||||
"description": "string type matches strings",
|
"description": "string type matches strings",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_2_0": {
|
||||||
"type": "string",
|
"type": "string"
|
||||||
"$id": "type_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -284,12 +281,11 @@
|
|||||||
{
|
{
|
||||||
"description": "object type matches objects",
|
"description": "object type matches objects",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_3_0": {
|
||||||
"type": "object",
|
"type": "object"
|
||||||
"$id": "type_3_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -360,12 +356,11 @@
|
|||||||
{
|
{
|
||||||
"description": "array type matches arrays",
|
"description": "array type matches arrays",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_4_0": {
|
||||||
"type": "array",
|
"type": "array"
|
||||||
"$id": "type_4_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -436,12 +431,11 @@
|
|||||||
{
|
{
|
||||||
"description": "boolean type matches booleans",
|
"description": "boolean type matches booleans",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_5_0": {
|
||||||
"type": "boolean",
|
"type": "boolean"
|
||||||
"$id": "type_5_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -539,12 +533,11 @@
|
|||||||
{
|
{
|
||||||
"description": "null type matches only the null object",
|
"description": "null type matches only the null object",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_6_0": {
|
||||||
"type": "null",
|
"type": "null"
|
||||||
"$id": "type_6_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -642,15 +635,14 @@
|
|||||||
{
|
{
|
||||||
"description": "multiple types can be specified in an array",
|
"description": "multiple types can be specified in an array",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_7_0": {
|
||||||
"type": [
|
"type": [
|
||||||
"integer",
|
"integer",
|
||||||
"string"
|
"string"
|
||||||
],
|
|
||||||
"$id": "type_7_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -721,14 +713,13 @@
|
|||||||
{
|
{
|
||||||
"description": "type as array with one item",
|
"description": "type as array with one item",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_8_0": {
|
||||||
"type": [
|
"type": [
|
||||||
"string"
|
"string"
|
||||||
],
|
|
||||||
"$id": "type_8_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -754,16 +745,15 @@
|
|||||||
{
|
{
|
||||||
"description": "type: array or object",
|
"description": "type: array or object",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_9_0": {
|
||||||
"type": [
|
"type": [
|
||||||
"array",
|
"array",
|
||||||
"object"
|
"object"
|
||||||
],
|
],
|
||||||
"items": {},
|
"items": {}
|
||||||
"$id": "type_9_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -820,17 +810,16 @@
|
|||||||
{
|
{
|
||||||
"description": "type: array, object or null",
|
"description": "type: array, object or null",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_10_0": {
|
||||||
"type": [
|
"type": [
|
||||||
"array",
|
"array",
|
||||||
"object",
|
"object",
|
||||||
"null"
|
"null"
|
||||||
],
|
],
|
||||||
"items": {},
|
"items": {}
|
||||||
"$id": "type_10_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -887,13 +876,12 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties",
|
"description": "extensible: true allows extra properties",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"type_11_0": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "type_11_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
{
|
{
|
||||||
"description": "object properties validation",
|
"description": "object properties validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_0_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {
|
"foo": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
@ -11,10 +11,9 @@
|
|||||||
"bar": {
|
"bar": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "properties_0_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -85,15 +84,14 @@
|
|||||||
{
|
{
|
||||||
"description": "properties with boolean schema",
|
"description": "properties with boolean schema",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_1_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": true,
|
"foo": true,
|
||||||
"bar": false
|
"bar": false
|
||||||
},
|
|
||||||
"$id": "properties_1_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -144,8 +142,8 @@
|
|||||||
{
|
{
|
||||||
"description": "properties with escaped characters",
|
"description": "properties with escaped characters",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_2_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo\nbar": {
|
"foo\nbar": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
@ -165,10 +163,9 @@
|
|||||||
"foo\fbar": {
|
"foo\fbar": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "properties_2_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -208,16 +205,15 @@
|
|||||||
{
|
{
|
||||||
"description": "properties with null valued instance properties",
|
"description": "properties with null valued instance properties",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_3_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {
|
"foo": {
|
||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "properties_3_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -237,8 +233,8 @@
|
|||||||
"description": "properties whose names are Javascript object property names",
|
"description": "properties whose names are Javascript object property names",
|
||||||
"comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.",
|
"comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_4_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"__proto__": {
|
"__proto__": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
@ -253,10 +249,9 @@
|
|||||||
"constructor": {
|
"constructor": {
|
||||||
"type": "number"
|
"type": "number"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "properties_4_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -343,17 +338,16 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties",
|
"description": "extensible: true allows extra properties",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_5_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {
|
"foo": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "properties_5_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -373,16 +367,15 @@
|
|||||||
{
|
{
|
||||||
"description": "strict by default: extra properties invalid",
|
"description": "strict by default: extra properties invalid",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_6_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {
|
"foo": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "properties_6_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -402,8 +395,8 @@
|
|||||||
{
|
{
|
||||||
"description": "inheritance: nested object inherits strictness from strict parent",
|
"description": "inheritance: nested object inherits strictness from strict parent",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_7_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"nested": {
|
"nested": {
|
||||||
"properties": {
|
"properties": {
|
||||||
@ -412,10 +405,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "properties_7_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -437,8 +429,8 @@
|
|||||||
{
|
{
|
||||||
"description": "override: nested object allows extra properties if extensible: true",
|
"description": "override: nested object allows extra properties if extensible: true",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_8_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"nested": {
|
"nested": {
|
||||||
"extensible": true,
|
"extensible": true,
|
||||||
@ -448,10 +440,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "properties_8_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -473,8 +464,8 @@
|
|||||||
{
|
{
|
||||||
"description": "inheritance: nested object inherits looseness from loose parent",
|
"description": "inheritance: nested object inherits looseness from loose parent",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_9_0": {
|
||||||
"extensible": true,
|
"extensible": true,
|
||||||
"properties": {
|
"properties": {
|
||||||
"nested": {
|
"nested": {
|
||||||
@ -484,10 +475,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "properties_9_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -509,8 +499,8 @@
|
|||||||
{
|
{
|
||||||
"description": "override: nested object enforces strictness if extensible: false",
|
"description": "override: nested object enforces strictness if extensible: false",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_10_0": {
|
||||||
"extensible": true,
|
"extensible": true,
|
||||||
"properties": {
|
"properties": {
|
||||||
"nested": {
|
"nested": {
|
||||||
@ -521,10 +511,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "properties_10_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -546,8 +535,8 @@
|
|||||||
{
|
{
|
||||||
"description": "arrays: inline items inherit strictness from strict parent",
|
"description": "arrays: inline items inherit strictness from strict parent",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_11_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"list": {
|
"list": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
@ -559,10 +548,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "properties_11_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -586,8 +574,8 @@
|
|||||||
{
|
{
|
||||||
"description": "arrays: inline items inherit looseness from loose parent",
|
"description": "arrays: inline items inherit looseness from loose parent",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"properties_12_0": {
|
||||||
"extensible": true,
|
"extensible": true,
|
||||||
"properties": {
|
"properties": {
|
||||||
"list": {
|
"list": {
|
||||||
@ -600,10 +588,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"$id": "properties_12_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,15 +2,14 @@
|
|||||||
{
|
{
|
||||||
"description": "propertyNames validation",
|
"description": "propertyNames validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"propertyNames_0_0": {
|
||||||
"propertyNames": {
|
"propertyNames": {
|
||||||
"maxLength": 3
|
"maxLength": 3
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "propertyNames_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -83,15 +82,14 @@
|
|||||||
{
|
{
|
||||||
"description": "propertyNames validation with pattern",
|
"description": "propertyNames validation with pattern",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"propertyNames_1_0": {
|
||||||
"propertyNames": {
|
"propertyNames": {
|
||||||
"pattern": "^a+$"
|
"pattern": "^a+$"
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "propertyNames_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -132,13 +130,12 @@
|
|||||||
{
|
{
|
||||||
"description": "propertyNames with boolean schema true",
|
"description": "propertyNames with boolean schema true",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"propertyNames_2_0": {
|
||||||
"propertyNames": true,
|
"propertyNames": true,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "propertyNames_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -166,13 +163,12 @@
|
|||||||
{
|
{
|
||||||
"description": "propertyNames with boolean schema false",
|
"description": "propertyNames with boolean schema false",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"propertyNames_3_0": {
|
||||||
"propertyNames": false,
|
"propertyNames": false,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "propertyNames_3_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -200,15 +196,14 @@
|
|||||||
{
|
{
|
||||||
"description": "propertyNames with const",
|
"description": "propertyNames with const",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"propertyNames_4_0": {
|
||||||
"propertyNames": {
|
"propertyNames": {
|
||||||
"const": "foo"
|
"const": "foo"
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "propertyNames_4_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -247,18 +242,17 @@
|
|||||||
{
|
{
|
||||||
"description": "propertyNames with enum",
|
"description": "propertyNames with enum",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"propertyNames_5_0": {
|
||||||
"propertyNames": {
|
"propertyNames": {
|
||||||
"enum": [
|
"enum": [
|
||||||
"foo",
|
"foo",
|
||||||
"bar"
|
"bar"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "propertyNames_5_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -309,15 +303,14 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties (checked by propertyNames)",
|
"description": "extensible: true allows extra properties (checked by propertyNames)",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"propertyNames_6_0": {
|
||||||
"propertyNames": {
|
"propertyNames": {
|
||||||
"maxLength": 3
|
"maxLength": 3
|
||||||
},
|
},
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "propertyNames_6_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -5,66 +5,60 @@
|
|||||||
"puncs": [
|
"puncs": [
|
||||||
{
|
{
|
||||||
"name": "get_organization",
|
"name": "get_organization",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"get_organization.response": {
|
||||||
"$id": "get_organization.response",
|
|
||||||
"type": "organization"
|
"type": "organization"
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "get_organizations",
|
"name": "get_organizations",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"get_organizations.response": {
|
||||||
"$id": "get_organizations.response",
|
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$family": "organization"
|
"$family": "organization"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "get_light_organization",
|
"name": "get_light_organization",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"get_light_organization.response": {
|
||||||
"$id": "get_light_organization.response",
|
|
||||||
"$family": "light.organization"
|
"$family": "light.organization"
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "get_full_organization",
|
"name": "get_full_organization",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"get_full_organization.response": {
|
||||||
"$id": "get_full_organization.response",
|
|
||||||
"$family": "full.organization"
|
"$family": "full.organization"
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "get_orders",
|
"name": "get_orders",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"get_orders.response": {
|
||||||
"$id": "get_orders.response",
|
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"type": "light.order"
|
"type": "light.order"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "get_widgets",
|
"name": "get_widgets",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"get_widgets.response": {
|
||||||
"$id": "get_widgets.response",
|
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
"$family": "widget"
|
"$family": "widget"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"enums": [],
|
"enums": [],
|
||||||
@ -165,9 +159,8 @@
|
|||||||
"created_at": "timestamptz",
|
"created_at": "timestamptz",
|
||||||
"type": "text"
|
"type": "text"
|
||||||
},
|
},
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"entity": {
|
||||||
"$id": "entity",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
@ -189,7 +182,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"fields": [
|
"fields": [
|
||||||
"id",
|
"id",
|
||||||
"type",
|
"type",
|
||||||
@ -256,9 +249,8 @@
|
|||||||
"organization",
|
"organization",
|
||||||
"person"
|
"person"
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"organization": {
|
||||||
"$id": "organization",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
"name": {
|
||||||
@ -266,7 +258,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "bot",
|
"name": "bot",
|
||||||
@ -309,9 +301,8 @@
|
|||||||
"role": "text",
|
"role": "text",
|
||||||
"created_at": "timestamptz"
|
"created_at": "timestamptz"
|
||||||
},
|
},
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"bot": {
|
||||||
"$id": "bot",
|
|
||||||
"type": "organization",
|
"type": "organization",
|
||||||
"properties": {
|
"properties": {
|
||||||
"token": {
|
"token": {
|
||||||
@ -322,8 +313,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"light.bot": {
|
||||||
"$id": "light.bot",
|
|
||||||
"type": "organization",
|
"type": "organization",
|
||||||
"properties": {
|
"properties": {
|
||||||
"token": {
|
"token": {
|
||||||
@ -331,7 +321,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"variations": [
|
"variations": [
|
||||||
"bot"
|
"bot"
|
||||||
]
|
]
|
||||||
@ -379,9 +369,8 @@
|
|||||||
"age": "numeric",
|
"age": "numeric",
|
||||||
"created_at": "timestamptz"
|
"created_at": "timestamptz"
|
||||||
},
|
},
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"person": {
|
||||||
"$id": "person",
|
|
||||||
"type": "organization",
|
"type": "organization",
|
||||||
"properties": {
|
"properties": {
|
||||||
"first_name": {
|
"first_name": {
|
||||||
@ -395,8 +384,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"light.person": {
|
||||||
"$id": "light.person",
|
|
||||||
"type": "organization",
|
"type": "organization",
|
||||||
"properties": {
|
"properties": {
|
||||||
"first_name": {
|
"first_name": {
|
||||||
@ -407,8 +395,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"full.person": {
|
||||||
"$id": "full.person",
|
|
||||||
"type": "person",
|
"type": "person",
|
||||||
"properties": {
|
"properties": {
|
||||||
"phone_numbers": {
|
"phone_numbers": {
|
||||||
@ -467,7 +454,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"variations": [
|
"variations": [
|
||||||
"person"
|
"person"
|
||||||
]
|
]
|
||||||
@ -513,13 +500,12 @@
|
|||||||
"target_type": "text",
|
"target_type": "text",
|
||||||
"created_at": "timestamptz"
|
"created_at": "timestamptz"
|
||||||
},
|
},
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"relationship": {
|
||||||
"$id": "relationship",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {}
|
"properties": {}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"variations": [
|
"variations": [
|
||||||
"contact",
|
"contact",
|
||||||
"relationship"
|
"relationship"
|
||||||
@ -572,9 +558,8 @@
|
|||||||
"is_primary": "boolean",
|
"is_primary": "boolean",
|
||||||
"created_at": "timestamptz"
|
"created_at": "timestamptz"
|
||||||
},
|
},
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"contact": {
|
||||||
"$id": "contact",
|
|
||||||
"type": "relationship",
|
"type": "relationship",
|
||||||
"properties": {
|
"properties": {
|
||||||
"is_primary": {
|
"is_primary": {
|
||||||
@ -582,7 +567,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"variations": [
|
"variations": [
|
||||||
"contact"
|
"contact"
|
||||||
]
|
]
|
||||||
@ -618,9 +603,8 @@
|
|||||||
"number": "text",
|
"number": "text",
|
||||||
"created_at": "timestamptz"
|
"created_at": "timestamptz"
|
||||||
},
|
},
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"phone_number": {
|
||||||
"$id": "phone_number",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"number": {
|
"number": {
|
||||||
@ -628,7 +612,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"variations": [
|
"variations": [
|
||||||
"phone_number"
|
"phone_number"
|
||||||
]
|
]
|
||||||
@ -664,9 +648,8 @@
|
|||||||
"address": "text",
|
"address": "text",
|
||||||
"created_at": "timestamptz"
|
"created_at": "timestamptz"
|
||||||
},
|
},
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"email_address": {
|
||||||
"$id": "email_address",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"address": {
|
"address": {
|
||||||
@ -674,7 +657,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"variations": [
|
"variations": [
|
||||||
"email_address"
|
"email_address"
|
||||||
]
|
]
|
||||||
@ -710,9 +693,8 @@
|
|||||||
"city": "text",
|
"city": "text",
|
||||||
"created_at": "timestamptz"
|
"created_at": "timestamptz"
|
||||||
},
|
},
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"address": {
|
||||||
"$id": "address",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"city": {
|
"city": {
|
||||||
@ -720,16 +702,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"variations": [
|
"variations": [
|
||||||
"address"
|
"address"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "order",
|
"name": "order",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"order": {
|
||||||
"$id": "order",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"total": {
|
"total": {
|
||||||
@ -740,8 +721,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"light.order": {
|
||||||
"$id": "light.order",
|
|
||||||
"type": "order",
|
"type": "order",
|
||||||
"properties": {
|
"properties": {
|
||||||
"customer": {
|
"customer": {
|
||||||
@ -749,8 +729,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"full.order": {
|
||||||
"$id": "full.order",
|
|
||||||
"type": "order",
|
"type": "order",
|
||||||
"properties": {
|
"properties": {
|
||||||
"customer": {
|
"customer": {
|
||||||
@ -764,7 +743,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"order",
|
"order",
|
||||||
"entity"
|
"entity"
|
||||||
@ -825,9 +804,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "order_line",
|
"name": "order_line",
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"order_line": {
|
||||||
"$id": "order_line",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"order_id": {
|
"order_id": {
|
||||||
@ -841,7 +819,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
},
|
||||||
"hierarchy": [
|
"hierarchy": [
|
||||||
"order_line",
|
"order_line",
|
||||||
"entity"
|
"entity"
|
||||||
@ -929,9 +907,8 @@
|
|||||||
"variations": [
|
"variations": [
|
||||||
"widget"
|
"widget"
|
||||||
],
|
],
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"widget": {
|
||||||
"$id": "widget",
|
|
||||||
"type": "entity",
|
"type": "entity",
|
||||||
"properties": {
|
"properties": {
|
||||||
"kind": {
|
"kind": {
|
||||||
@ -939,27 +916,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
"stock.widget": {
|
||||||
"$id": "stock.widget",
|
|
||||||
"type": "widget",
|
"type": "widget",
|
||||||
"properties": {
|
"properties": {}
|
||||||
"kind": {
|
|
||||||
"const": "stock"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
"tasks.widget": {
|
||||||
"$id": "tasks.widget",
|
|
||||||
"type": "widget",
|
"type": "widget",
|
||||||
"properties": {
|
"properties": {}
|
||||||
"kind": {
|
|
||||||
"const": "tasks"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1506,7 +1473,7 @@
|
|||||||
"success": true,
|
"success": true,
|
||||||
"sql": [
|
"sql": [
|
||||||
[
|
[
|
||||||
"(SELECT jsonb_strip_nulls((SELECT jsonb_build_object(",
|
"(SELECT jsonb_strip_nulls((SELECT COALESCE(jsonb_agg(jsonb_build_object(",
|
||||||
" 'archived', entity_3.archived,",
|
" 'archived', entity_3.archived,",
|
||||||
" 'created_at', entity_3.created_at,",
|
" 'created_at', entity_3.created_at,",
|
||||||
" 'id', entity_3.id,",
|
" 'id', entity_3.id,",
|
||||||
@ -1525,7 +1492,7 @@
|
|||||||
" NOT entity_5.archived",
|
" NOT entity_5.archived",
|
||||||
" AND relationship_2.target_id = entity_5.id),",
|
" AND relationship_2.target_id = entity_5.id),",
|
||||||
" 'type', entity_3.type",
|
" 'type', entity_3.type",
|
||||||
")",
|
")), '[]'::jsonb)",
|
||||||
"FROM agreego.contact contact_1",
|
"FROM agreego.contact contact_1",
|
||||||
"JOIN agreego.relationship relationship_2 ON relationship_2.id = contact_1.id",
|
"JOIN agreego.relationship relationship_2 ON relationship_2.id = contact_1.id",
|
||||||
"JOIN agreego.entity entity_3 ON entity_3.id = relationship_2.id",
|
"JOIN agreego.entity entity_3 ON entity_3.id = relationship_2.id",
|
||||||
|
|||||||
@ -2,18 +2,17 @@
|
|||||||
{
|
{
|
||||||
"description": "required validation",
|
"description": "required validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"required_0_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {},
|
"foo": {},
|
||||||
"bar": {}
|
"bar": {}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"foo"
|
"foo"
|
||||||
],
|
|
||||||
"$id": "required_0_0"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -88,14 +87,13 @@
|
|||||||
{
|
{
|
||||||
"description": "required default validation",
|
"description": "required default validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"required_1_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {}
|
"foo": {}
|
||||||
},
|
|
||||||
"$id": "required_1_0"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -112,15 +110,14 @@
|
|||||||
{
|
{
|
||||||
"description": "required with empty array",
|
"description": "required with empty array",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"required_2_0": {
|
||||||
"properties": {
|
"properties": {
|
||||||
"foo": {}
|
"foo": {}
|
||||||
},
|
},
|
||||||
"required": [],
|
"required": []
|
||||||
"$id": "required_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -137,8 +134,8 @@
|
|||||||
{
|
{
|
||||||
"description": "required with escaped characters",
|
"description": "required with escaped characters",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"required_3_0": {
|
||||||
"required": [
|
"required": [
|
||||||
"foo\nbar",
|
"foo\nbar",
|
||||||
"foo\"bar",
|
"foo\"bar",
|
||||||
@ -147,10 +144,9 @@
|
|||||||
"foo\tbar",
|
"foo\tbar",
|
||||||
"foo\fbar"
|
"foo\fbar"
|
||||||
],
|
],
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "required_3_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -187,17 +183,16 @@
|
|||||||
"description": "required properties whose names are Javascript object property names",
|
"description": "required properties whose names are Javascript object property names",
|
||||||
"comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.",
|
"comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"required_4_0": {
|
||||||
"required": [
|
"required": [
|
||||||
"__proto__",
|
"__proto__",
|
||||||
"toString",
|
"toString",
|
||||||
"constructor"
|
"constructor"
|
||||||
],
|
],
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "required_4_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -284,15 +279,14 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra properties in required",
|
"description": "extensible: true allows extra properties in required",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"required_5_0": {
|
||||||
"required": [
|
"required": [
|
||||||
"foo"
|
"foo"
|
||||||
],
|
],
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "required_5_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,13 +2,12 @@
|
|||||||
{
|
{
|
||||||
"description": "uniqueItems validation",
|
"description": "uniqueItems validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"uniqueItems_0_0": {
|
||||||
"uniqueItems": true,
|
"uniqueItems": true,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "uniqueItems_0_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -469,8 +468,8 @@
|
|||||||
{
|
{
|
||||||
"description": "uniqueItems with an array of items",
|
"description": "uniqueItems with an array of items",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"uniqueItems_1_0": {
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@ -480,10 +479,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"uniqueItems": true,
|
"uniqueItems": true,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "uniqueItems_1_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -595,8 +593,8 @@
|
|||||||
{
|
{
|
||||||
"description": "uniqueItems with an array of items and additionalItems=false",
|
"description": "uniqueItems with an array of items and additionalItems=false",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"uniqueItems_2_0": {
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@ -606,10 +604,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"uniqueItems": true,
|
"uniqueItems": true,
|
||||||
"items": false,
|
"items": false
|
||||||
"$id": "uniqueItems_2_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -678,13 +675,12 @@
|
|||||||
{
|
{
|
||||||
"description": "uniqueItems=false validation",
|
"description": "uniqueItems=false validation",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"uniqueItems_3_0": {
|
||||||
"uniqueItems": false,
|
"uniqueItems": false,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "uniqueItems_3_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -924,8 +920,8 @@
|
|||||||
{
|
{
|
||||||
"description": "uniqueItems=false with an array of items",
|
"description": "uniqueItems=false with an array of items",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"uniqueItems_4_0": {
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@ -935,10 +931,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"uniqueItems": false,
|
"uniqueItems": false,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "uniqueItems_4_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1050,8 +1045,8 @@
|
|||||||
{
|
{
|
||||||
"description": "uniqueItems=false with an array of items and additionalItems=false",
|
"description": "uniqueItems=false with an array of items and additionalItems=false",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"uniqueItems_5_0": {
|
||||||
"prefixItems": [
|
"prefixItems": [
|
||||||
{
|
{
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
@ -1061,10 +1056,9 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"uniqueItems": false,
|
"uniqueItems": false,
|
||||||
"items": false,
|
"items": false
|
||||||
"$id": "uniqueItems_5_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
@ -1133,13 +1127,12 @@
|
|||||||
{
|
{
|
||||||
"description": "extensible: true allows extra items in uniqueItems",
|
"description": "extensible: true allows extra items in uniqueItems",
|
||||||
"database": {
|
"database": {
|
||||||
"schemas": [
|
"schemas": {
|
||||||
{
|
"uniqueItems_6_0": {
|
||||||
"uniqueItems": true,
|
"uniqueItems": true,
|
||||||
"extensible": true,
|
"extensible": true
|
||||||
"$id": "uniqueItems_6_0"
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"tests": [
|
"tests": [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
use crate::database::schema::Schema;
|
use crate::database::schema::Schema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@ -8,5 +9,6 @@ pub struct Enum {
|
|||||||
pub module: String,
|
pub module: String,
|
||||||
pub source: String,
|
pub source: String,
|
||||||
pub values: Vec<String>,
|
pub values: Vec<String>,
|
||||||
pub schemas: Vec<Schema>,
|
#[serde(default)]
|
||||||
|
pub schemas: std::collections::BTreeMap<String, Arc<Schema>>,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -125,22 +125,16 @@ impl Database {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(arr) = val.get("schemas").and_then(|v| v.as_array()) {
|
if let Some(map) = val.get("schemas").and_then(|v| v.as_object()) {
|
||||||
for (i, item) in arr.iter().enumerate() {
|
for (key, item) in map.iter() {
|
||||||
match serde_json::from_value::<Schema>(item.clone()) {
|
match serde_json::from_value::<Schema>(item.clone()) {
|
||||||
Ok(mut schema) => {
|
Ok(schema) => {
|
||||||
let id = schema
|
db.schemas.insert(key.clone(), Arc::new(schema));
|
||||||
.obj
|
|
||||||
.id
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(|| format!("schema_{}", i));
|
|
||||||
schema.obj.id = Some(id.clone());
|
|
||||||
db.schemas.insert(id, Arc::new(schema));
|
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
errors.push(crate::drop::Error {
|
errors.push(crate::drop::Error {
|
||||||
code: "DATABASE_SCHEMA_PARSE_FAILED".to_string(),
|
code: "DATABASE_SCHEMA_PARSE_FAILED".to_string(),
|
||||||
message: format!("Failed to parse database schema: {}", e),
|
message: format!("Failed to parse database schema key '{}': {}", key, e),
|
||||||
details: crate::drop::ErrorDetails::default(),
|
details: crate::drop::ErrorDetails::default(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -185,21 +179,21 @@ impl Database {
|
|||||||
|
|
||||||
pub fn compile(&mut self, errors: &mut Vec<crate::drop::Error>) {
|
pub fn compile(&mut self, errors: &mut Vec<crate::drop::Error>) {
|
||||||
let mut harvested = Vec::new();
|
let mut harvested = Vec::new();
|
||||||
for schema_arc in self.schemas.values_mut() {
|
for (id, schema_arc) in &self.schemas {
|
||||||
if let Some(s) = std::sync::Arc::get_mut(schema_arc) {
|
crate::database::schema::Schema::collect_schemas(schema_arc, id, id.clone(), &mut harvested, errors);
|
||||||
s.collect_schemas(None, &mut harvested, errors);
|
|
||||||
}
|
}
|
||||||
}
|
for (id, schema_arc) in harvested {
|
||||||
for (id, schema) in harvested {
|
self.schemas.insert(id, schema_arc);
|
||||||
self.schemas.insert(id, Arc::new(schema));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.collect_schemas(errors);
|
self.collect_schemas(errors);
|
||||||
|
|
||||||
// Mathematically evaluate all property inheritances, formats, schemas, and foreign key edges topographically over OnceLocks
|
// Mathematically evaluate all property inheritances, formats, schemas, and foreign key edges topographically over OnceLocks
|
||||||
let mut visited = std::collections::HashSet::new();
|
let mut visited = std::collections::HashSet::new();
|
||||||
for schema_arc in self.schemas.values() {
|
for (id, schema_arc) in &self.schemas {
|
||||||
schema_arc.as_ref().compile(self, &mut visited, errors);
|
// First compile pass initializes exact structural root_id mapping to resolve DB constraints
|
||||||
|
let root_id = id.split('/').next().unwrap_or(id);
|
||||||
|
schema_arc.as_ref().compile(self, root_id, id.clone(), &mut visited, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,23 +203,26 @@ impl Database {
|
|||||||
// Pass 1: Extract all Schemas structurally off top level definitions into the master registry.
|
// Pass 1: Extract all Schemas structurally off top level definitions into the master registry.
|
||||||
// Validate every node recursively via string filters natively!
|
// Validate every node recursively via string filters natively!
|
||||||
for type_def in self.types.values() {
|
for type_def in self.types.values() {
|
||||||
for mut schema in type_def.schemas.clone() {
|
for (id, schema_arc) in &type_def.schemas {
|
||||||
schema.collect_schemas(None, &mut to_insert, errors);
|
to_insert.push((id.clone(), Arc::clone(schema_arc)));
|
||||||
|
crate::database::schema::Schema::collect_schemas(schema_arc, id, id.clone(), &mut to_insert, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for punc_def in self.puncs.values() {
|
for punc_def in self.puncs.values() {
|
||||||
for mut schema in punc_def.schemas.clone() {
|
for (id, schema_arc) in &punc_def.schemas {
|
||||||
schema.collect_schemas(None, &mut to_insert, errors);
|
to_insert.push((id.clone(), Arc::clone(schema_arc)));
|
||||||
|
crate::database::schema::Schema::collect_schemas(schema_arc, id, id.clone(), &mut to_insert, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for enum_def in self.enums.values() {
|
for enum_def in self.enums.values() {
|
||||||
for mut schema in enum_def.schemas.clone() {
|
for (id, schema_arc) in &enum_def.schemas {
|
||||||
schema.collect_schemas(None, &mut to_insert, errors);
|
to_insert.push((id.clone(), Arc::clone(schema_arc)));
|
||||||
|
crate::database::schema::Schema::collect_schemas(schema_arc, id, id.clone(), &mut to_insert, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (id, schema) in to_insert {
|
for (id, schema_arc) in to_insert {
|
||||||
self.schemas.insert(id, Arc::new(schema));
|
self.schemas.insert(id, schema_arc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
|
use crate::database::schema::Schema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
use crate::database::schema::Schema;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct Case {
|
pub struct Case {
|
||||||
@ -19,9 +19,6 @@ pub struct Case {
|
|||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
pub struct SchemaObject {
|
pub struct SchemaObject {
|
||||||
// Core Schema Keywords
|
// Core Schema Keywords
|
||||||
#[serde(rename = "$id")]
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
|
||||||
pub id: Option<String>,
|
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub description: Option<String>,
|
pub description: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
@ -176,7 +173,7 @@ pub struct SchemaObject {
|
|||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
#[serde(skip_serializing_if = "crate::database::object::is_once_lock_map_empty")]
|
#[serde(skip_serializing_if = "crate::database::object::is_once_lock_map_empty")]
|
||||||
#[serde(serialize_with = "crate::database::object::serialize_once_lock")]
|
#[serde(serialize_with = "crate::database::object::serialize_once_lock")]
|
||||||
pub compiled_options: OnceLock<BTreeMap<String, String>>,
|
pub compiled_options: OnceLock<BTreeMap<String, (Option<usize>, Option<String>)>>,
|
||||||
|
|
||||||
#[serde(rename = "compiledEdges")]
|
#[serde(rename = "compiledEdges")]
|
||||||
#[serde(skip_deserializing)]
|
#[serde(skip_deserializing)]
|
||||||
@ -275,93 +272,49 @@ pub fn is_primitive_type(t: &str) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SchemaObject {
|
impl SchemaObject {
|
||||||
pub fn identifier(&self) -> Option<String> {
|
pub fn get_discriminator_value(&self, dim: &str, schema_id: &str) -> Option<String> {
|
||||||
if let Some(id) = &self.id {
|
|
||||||
return Some(id.split('.').next_back().unwrap_or("").to_string());
|
|
||||||
}
|
|
||||||
if let Some(SchemaTypeOrArray::Single(t)) = &self.type_ {
|
|
||||||
if !is_primitive_type(t) {
|
|
||||||
return Some(t.split('.').next_back().unwrap_or("").to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_discriminator_value(&self, dim: &str) -> Option<String> {
|
|
||||||
let is_split = self
|
let is_split = self
|
||||||
.compiled_properties
|
.compiled_properties
|
||||||
.get()
|
.get()
|
||||||
.map_or(false, |p| p.contains_key("kind"));
|
.map_or(false, |p| p.contains_key("kind"));
|
||||||
if let Some(id) = &self.id {
|
|
||||||
if id.contains("light.person") || id.contains("light.organization") {
|
|
||||||
println!(
|
|
||||||
"[DEBUG SPLIT] ID: {}, dim: {}, is_split: {:?}, props: {:?}",
|
|
||||||
id,
|
|
||||||
dim,
|
|
||||||
is_split,
|
|
||||||
self
|
|
||||||
.compiled_properties
|
|
||||||
.get()
|
|
||||||
.map(|p| p.keys().cloned().collect::<Vec<_>>())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(props) = self.compiled_properties.get() {
|
|
||||||
if let Some(prop_schema) = props.get(dim) {
|
|
||||||
if let Some(c) = &prop_schema.obj.const_ {
|
|
||||||
if let Some(s) = c.as_str() {
|
|
||||||
return Some(s.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if let Some(e) = &prop_schema.obj.enum_ {
|
|
||||||
if e.len() == 1 {
|
|
||||||
if let Some(s) = e[0].as_str() {
|
|
||||||
return Some(s.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if dim == "kind" {
|
if dim == "kind" {
|
||||||
if let Some(id) = &self.id {
|
let base = schema_id.split('/').last().unwrap_or(schema_id);
|
||||||
let base = id.split('/').last().unwrap_or(id);
|
|
||||||
if let Some(idx) = base.rfind('.') {
|
if let Some(idx) = base.rfind('.') {
|
||||||
return Some(base[..idx].to_string());
|
return Some(base[..idx].to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(SchemaTypeOrArray::Single(t)) = &self.type_ {
|
|
||||||
if !is_primitive_type(t) {
|
|
||||||
let base = t.split('/').last().unwrap_or(t);
|
|
||||||
if let Some(idx) = base.rfind('.') {
|
|
||||||
return Some(base[..idx].to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if dim == "type" {
|
if dim == "type" {
|
||||||
if let Some(id) = &self.id {
|
let base = schema_id.split('/').last().unwrap_or(schema_id);
|
||||||
let base = id.split('/').last().unwrap_or(id);
|
|
||||||
if is_split {
|
if is_split {
|
||||||
return Some(base.split('.').next_back().unwrap_or(base).to_string());
|
return Some(base.split('.').next_back().unwrap_or(base).to_string());
|
||||||
} else {
|
} else {
|
||||||
return Some(base.to_string());
|
return Some(base.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(SchemaTypeOrArray::Single(t)) = &self.type_ {
|
|
||||||
if !is_primitive_type(t) {
|
|
||||||
let base = t.split('/').last().unwrap_or(t);
|
|
||||||
if is_split {
|
|
||||||
return Some(base.split('.').next_back().unwrap_or(base).to_string());
|
|
||||||
} else {
|
|
||||||
return Some(base.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn requires_uuid_path(&self, db: &crate::database::Database) -> bool {
|
||||||
|
// 1. Explicitly defines "id" either directly or via inheritance/extension?
|
||||||
|
if self
|
||||||
|
.compiled_properties
|
||||||
|
.get()
|
||||||
|
.map_or(false, |p| p.contains_key("id"))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Implicit table-backed rule: Does its $family boundary map directly to the global database catalog?
|
||||||
|
if let Some(family) = &self.family {
|
||||||
|
let base = family.split('.').next_back().unwrap_or(family);
|
||||||
|
if db.types.contains_key(base) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use crate::database::page::Page;
|
use crate::database::page::Page;
|
||||||
use crate::database::schema::Schema;
|
use crate::database::schema::Schema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
@ -16,5 +17,5 @@ pub struct Punc {
|
|||||||
pub get: Option<String>,
|
pub get: Option<String>,
|
||||||
pub page: Option<Page>,
|
pub page: Option<Page>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub schemas: Vec<Schema>,
|
pub schemas: std::collections::BTreeMap<String, Arc<Schema>>,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
|
use crate::database::object::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use crate::database::object::*;
|
|
||||||
#[derive(Debug, Clone, Serialize, Default)]
|
#[derive(Debug, Clone, Serialize, Default)]
|
||||||
pub struct Schema {
|
pub struct Schema {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
@ -26,6 +26,8 @@ impl Schema {
|
|||||||
pub fn compile(
|
pub fn compile(
|
||||||
&self,
|
&self,
|
||||||
db: &crate::database::Database,
|
db: &crate::database::Database,
|
||||||
|
root_id: &str,
|
||||||
|
path: String,
|
||||||
visited: &mut std::collections::HashSet<String>,
|
visited: &mut std::collections::HashSet<String>,
|
||||||
errors: &mut Vec<crate::drop::Error>,
|
errors: &mut Vec<crate::drop::Error>,
|
||||||
) {
|
) {
|
||||||
@ -33,11 +35,13 @@ impl Schema {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(id) = &self.obj.id {
|
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &self.obj.type_ {
|
||||||
if !visited.insert(id.clone()) {
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
|
if !visited.insert(t.clone()) {
|
||||||
return; // Break cyclical resolution
|
return; // Break cyclical resolution
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(format_str) = &self.obj.format {
|
if let Some(format_str) = &self.obj.format {
|
||||||
if let Some(fmt) = crate::database::formats::FORMATS.get(format_str.as_str()) {
|
if let Some(fmt) = crate::database::formats::FORMATS.get(format_str.as_str()) {
|
||||||
@ -75,7 +79,7 @@ impl Schema {
|
|||||||
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &self.obj.type_ {
|
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &self.obj.type_ {
|
||||||
if !crate::database::object::is_primitive_type(t) {
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
if let Some(parent) = db.schemas.get(t) {
|
if let Some(parent) = db.schemas.get(t) {
|
||||||
parent.as_ref().compile(db, visited, errors);
|
parent.as_ref().compile(db, t, t.clone(), visited, errors);
|
||||||
if let Some(p_props) = parent.obj.compiled_properties.get() {
|
if let Some(p_props) = parent.obj.compiled_properties.get() {
|
||||||
props.extend(p_props.clone());
|
props.extend(p_props.clone());
|
||||||
}
|
}
|
||||||
@ -95,11 +99,12 @@ impl Schema {
|
|||||||
errors.push(crate::drop::Error {
|
errors.push(crate::drop::Error {
|
||||||
code: "MULTIPLE_INHERITANCE_PROHIBITED".to_string(),
|
code: "MULTIPLE_INHERITANCE_PROHIBITED".to_string(),
|
||||||
message: format!(
|
message: format!(
|
||||||
"Schema '{}' attempts to extend multiple custom object pointers in its type array. Use 'oneOf' for polymorphism and tagged unions.",
|
"Schema attempts to extend multiple custom object pointers in its type array {:?}. Use 'oneOf' for polymorphism and tagged unions.",
|
||||||
self.obj.identifier().unwrap_or("unknown".to_string())
|
types
|
||||||
),
|
),
|
||||||
details: crate::drop::ErrorDetails {
|
details: crate::drop::ErrorDetails {
|
||||||
path: self.obj.identifier().unwrap_or("unknown".to_string()),
|
path: path.clone(),
|
||||||
|
schema: Some(root_id.to_string()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -108,7 +113,7 @@ impl Schema {
|
|||||||
for t in types {
|
for t in types {
|
||||||
if !crate::database::object::is_primitive_type(t) {
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
if let Some(parent) = db.schemas.get(t) {
|
if let Some(parent) = db.schemas.get(t) {
|
||||||
parent.as_ref().compile(db, visited, errors);
|
parent.as_ref().compile(db, t, t.clone(), visited, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,60 +133,68 @@ impl Schema {
|
|||||||
let _ = self.obj.compiled_property_names.set(names);
|
let _ = self.obj.compiled_property_names.set(names);
|
||||||
|
|
||||||
// 4. Compute Edges natively
|
// 4. Compute Edges natively
|
||||||
let schema_edges = self.compile_edges(db, visited, &props, errors);
|
let schema_edges = self.compile_edges(db, root_id, &path, visited, &props, errors);
|
||||||
let _ = self.obj.compiled_edges.set(schema_edges);
|
let _ = self.obj.compiled_edges.set(schema_edges);
|
||||||
|
|
||||||
// 5. Build our inline children properties recursively NOW! (Depth-first search)
|
// 5. Build our inline children properties recursively NOW! (Depth-first search)
|
||||||
if let Some(local_props) = &self.obj.properties {
|
if let Some(local_props) = &self.obj.properties {
|
||||||
for child in local_props.values() {
|
for (k, child) in local_props {
|
||||||
child.compile(db, visited, errors);
|
child.compile(db, root_id, format!("{}/{}", path, k), visited, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(items) = &self.obj.items {
|
if let Some(items) = &self.obj.items {
|
||||||
items.compile(db, visited, errors);
|
items.compile(db, root_id, format!("{}/items", path), visited, errors);
|
||||||
}
|
}
|
||||||
if let Some(pattern_props) = &self.obj.pattern_properties {
|
if let Some(pattern_props) = &self.obj.pattern_properties {
|
||||||
for child in pattern_props.values() {
|
for (k, child) in pattern_props {
|
||||||
child.compile(db, visited, errors);
|
child.compile(db, root_id, format!("{}/{}", path, k), visited, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(additional_props) = &self.obj.additional_properties {
|
if let Some(additional_props) = &self.obj.additional_properties {
|
||||||
additional_props.compile(db, visited, errors);
|
additional_props.compile(
|
||||||
|
db,
|
||||||
|
root_id,
|
||||||
|
format!("{}/additionalProperties", path),
|
||||||
|
visited,
|
||||||
|
errors,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if let Some(one_of) = &self.obj.one_of {
|
if let Some(one_of) = &self.obj.one_of {
|
||||||
for child in one_of {
|
for (i, child) in one_of.iter().enumerate() {
|
||||||
child.compile(db, visited, errors);
|
child.compile(db, root_id, format!("{}/oneOf/{}", path, i), visited, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(arr) = &self.obj.prefix_items {
|
if let Some(arr) = &self.obj.prefix_items {
|
||||||
for child in arr {
|
for (i, child) in arr.iter().enumerate() {
|
||||||
child.compile(db, visited, errors);
|
child.compile(db, root_id, format!("{}/prefixItems/{}", path, i), visited, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(child) = &self.obj.not {
|
if let Some(child) = &self.obj.not {
|
||||||
child.compile(db, visited, errors);
|
child.compile(db, root_id, format!("{}/not", path), visited, errors);
|
||||||
}
|
}
|
||||||
if let Some(child) = &self.obj.contains {
|
if let Some(child) = &self.obj.contains {
|
||||||
child.compile(db, visited, errors);
|
child.compile(db, root_id, format!("{}/contains", path), visited, errors);
|
||||||
}
|
}
|
||||||
if let Some(cases) = &self.obj.cases {
|
if let Some(cases) = &self.obj.cases {
|
||||||
for c in cases {
|
for (i, c) in cases.iter().enumerate() {
|
||||||
if let Some(child) = &c.when {
|
if let Some(child) = &c.when {
|
||||||
child.compile(db, visited, errors);
|
child.compile(db, root_id, format!("{}/cases/{}/when", path, i), visited, errors);
|
||||||
}
|
}
|
||||||
if let Some(child) = &c.then {
|
if let Some(child) = &c.then {
|
||||||
child.compile(db, visited, errors);
|
child.compile(db, root_id, format!("{}/cases/{}/then", path, i), visited, errors);
|
||||||
}
|
}
|
||||||
if let Some(child) = &c.else_ {
|
if let Some(child) = &c.else_ {
|
||||||
child.compile(db, visited, errors);
|
child.compile(db, root_id, format!("{}/cases/{}/else", path, i), visited, errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.compile_polymorphism(db, errors);
|
self.compile_polymorphism(db, root_id, &path, errors);
|
||||||
|
|
||||||
if let Some(id) = &self.obj.id {
|
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &self.obj.type_ {
|
||||||
visited.remove(id);
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
|
visited.remove(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,6 +205,8 @@ impl Schema {
|
|||||||
pub fn compile_edges(
|
pub fn compile_edges(
|
||||||
&self,
|
&self,
|
||||||
db: &crate::database::Database,
|
db: &crate::database::Database,
|
||||||
|
root_id: &str,
|
||||||
|
path: &str,
|
||||||
visited: &mut std::collections::HashSet<String>,
|
visited: &mut std::collections::HashSet<String>,
|
||||||
props: &std::collections::BTreeMap<String, std::sync::Arc<Schema>>,
|
props: &std::collections::BTreeMap<String, std::sync::Arc<Schema>>,
|
||||||
errors: &mut Vec<crate::drop::Error>,
|
errors: &mut Vec<crate::drop::Error>,
|
||||||
@ -201,16 +216,33 @@ impl Schema {
|
|||||||
// Determine the physical Database Table Name this schema structurally represents
|
// Determine the physical Database Table Name this schema structurally represents
|
||||||
// Plucks the polymorphic discriminator via dot-notation (e.g. extracting "person" from "full.person")
|
// Plucks the polymorphic discriminator via dot-notation (e.g. extracting "person" from "full.person")
|
||||||
let mut parent_type_name = None;
|
let mut parent_type_name = None;
|
||||||
|
|
||||||
if let Some(family) = &self.obj.family {
|
if let Some(family) = &self.obj.family {
|
||||||
|
// 1. Explicit horizontal routing
|
||||||
parent_type_name = Some(family.split('.').next_back().unwrap_or(family).to_string());
|
parent_type_name = Some(family.split('.').next_back().unwrap_or(family).to_string());
|
||||||
} else if let Some(identifier) = self.obj.identifier() {
|
} else if !path.contains('/') {
|
||||||
parent_type_name = Some(
|
// 2. Root nodes trust their exact registry footprint
|
||||||
identifier
|
let base_type_name = path.split('.').next_back().unwrap_or(path).to_string();
|
||||||
|
if db.types.contains_key(&base_type_name) {
|
||||||
|
parent_type_name = Some(base_type_name);
|
||||||
|
}
|
||||||
|
} else if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &self.obj.type_ {
|
||||||
|
// 3. Nested graphs trust their explicit struct pointer reference
|
||||||
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
|
parent_type_name = Some(t.split('.').next_back().unwrap_or(t).to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if parent_type_name.is_none() {
|
||||||
|
// 4. Absolute fallback for completely anonymous inline structures
|
||||||
|
let base_type_name = root_id
|
||||||
.split('.')
|
.split('.')
|
||||||
.next_back()
|
.next_back()
|
||||||
.unwrap_or(&identifier)
|
.unwrap_or(root_id)
|
||||||
.to_string(),
|
.to_string();
|
||||||
);
|
if db.types.contains_key(&base_type_name) {
|
||||||
|
parent_type_name = Some(base_type_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(p_type) = parent_type_name {
|
if let Some(p_type) = parent_type_name {
|
||||||
@ -237,13 +269,19 @@ impl Schema {
|
|||||||
// Determine the physical Postgres table backing the nested child schema recursively
|
// Determine the physical Postgres table backing the nested child schema recursively
|
||||||
if let Some(family) = &target_schema.obj.family {
|
if let Some(family) = &target_schema.obj.family {
|
||||||
child_type_name = Some(family.split('.').next_back().unwrap_or(family).to_string());
|
child_type_name = Some(family.split('.').next_back().unwrap_or(family).to_string());
|
||||||
} else if let Some(ref_id) = target_schema.obj.identifier() {
|
} else if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) =
|
||||||
child_type_name = Some(ref_id.split('.').next_back().unwrap_or(&ref_id).to_string());
|
&target_schema.obj.type_
|
||||||
|
{
|
||||||
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
|
child_type_name = Some(t.split('.').next_back().unwrap_or(t).to_string());
|
||||||
|
}
|
||||||
} else if let Some(arr) = &target_schema.obj.one_of {
|
} else if let Some(arr) = &target_schema.obj.one_of {
|
||||||
if let Some(first) = arr.first() {
|
if let Some(first) = arr.first() {
|
||||||
if let Some(ref_id) = first.obj.identifier() {
|
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &first.obj.type_
|
||||||
child_type_name =
|
{
|
||||||
Some(ref_id.split('.').next_back().unwrap_or(&ref_id).to_string());
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
|
child_type_name = Some(t.split('.').next_back().unwrap_or(t).to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -252,7 +290,7 @@ impl Schema {
|
|||||||
if db.types.contains_key(&c_type) {
|
if db.types.contains_key(&c_type) {
|
||||||
// Ensure the child Schema's AST has accurately compiled its own physical property keys so we can
|
// Ensure the child Schema's AST has accurately compiled its own physical property keys so we can
|
||||||
// inject them securely for Many-to-Many Twin Deduction disambiguation matching.
|
// inject them securely for Many-to-Many Twin Deduction disambiguation matching.
|
||||||
target_schema.compile(db, visited, errors);
|
target_schema.compile(db, root_id, format!("{}/{}", path, prop_name), visited, errors);
|
||||||
if let Some(compiled_target_props) = target_schema.obj.compiled_properties.get() {
|
if let Some(compiled_target_props) = target_schema.obj.compiled_properties.get() {
|
||||||
let keys_for_ambiguity: Vec<String> =
|
let keys_for_ambiguity: Vec<String> =
|
||||||
compiled_target_props.keys().cloned().collect();
|
compiled_target_props.keys().cloned().collect();
|
||||||
@ -264,8 +302,8 @@ impl Schema {
|
|||||||
prop_name,
|
prop_name,
|
||||||
Some(&keys_for_ambiguity),
|
Some(&keys_for_ambiguity),
|
||||||
is_array,
|
is_array,
|
||||||
self.id.as_deref(),
|
Some(root_id),
|
||||||
&format!("/{}", prop_name),
|
&format!("{}/{}", path, prop_name),
|
||||||
errors,
|
errors,
|
||||||
) {
|
) {
|
||||||
schema_edges.insert(
|
schema_edges.insert(
|
||||||
@ -288,6 +326,8 @@ impl Schema {
|
|||||||
pub fn compile_polymorphism(
|
pub fn compile_polymorphism(
|
||||||
&self,
|
&self,
|
||||||
db: &crate::database::Database,
|
db: &crate::database::Database,
|
||||||
|
root_id: &str,
|
||||||
|
path: &str,
|
||||||
errors: &mut Vec<crate::drop::Error>,
|
errors: &mut Vec<crate::drop::Error>,
|
||||||
) {
|
) {
|
||||||
let mut options = std::collections::BTreeMap::new();
|
let mut options = std::collections::BTreeMap::new();
|
||||||
@ -312,7 +352,7 @@ impl Schema {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if db.schemas.contains_key(&target_id) {
|
if db.schemas.contains_key(&target_id) {
|
||||||
options.insert(var.to_string(), target_id);
|
options.insert(var.to_string(), (None, Some(target_id)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -321,12 +361,10 @@ impl Schema {
|
|||||||
|
|
||||||
let suffix = format!(".{}", family_base);
|
let suffix = format!(".{}", family_base);
|
||||||
|
|
||||||
for schema in &type_def.schemas {
|
for (id, schema) in &type_def.schemas {
|
||||||
if let Some(id) = &schema.obj.id {
|
|
||||||
if id.ends_with(&suffix) || id == &family_base {
|
if id.ends_with(&suffix) || id == &family_base {
|
||||||
if let Some(kind_val) = schema.obj.get_discriminator_value("kind") {
|
if let Some(kind_val) = schema.obj.get_discriminator_value("kind", id) {
|
||||||
options.insert(kind_val, id.to_string());
|
options.insert(kind_val, (None, Some(id.to_string())));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,16 +373,47 @@ impl Schema {
|
|||||||
} else if let Some(one_of) = &self.obj.one_of {
|
} else if let Some(one_of) = &self.obj.one_of {
|
||||||
let mut type_vals = std::collections::HashSet::new();
|
let mut type_vals = std::collections::HashSet::new();
|
||||||
let mut kind_vals = std::collections::HashSet::new();
|
let mut kind_vals = std::collections::HashSet::new();
|
||||||
|
let mut disjoint_base = true;
|
||||||
|
let mut structural_types = std::collections::HashSet::new();
|
||||||
|
|
||||||
for c in one_of {
|
for c in one_of {
|
||||||
if let Some(t_val) = c.obj.get_discriminator_value("type") {
|
let mut child_id = String::new();
|
||||||
|
let mut child_is_primitive = false;
|
||||||
|
|
||||||
|
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &c.obj.type_ {
|
||||||
|
if crate::database::object::is_primitive_type(t) {
|
||||||
|
child_is_primitive = true;
|
||||||
|
structural_types.insert(t.clone());
|
||||||
|
} else {
|
||||||
|
child_id = t.clone();
|
||||||
|
structural_types.insert("object".to_string());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
disjoint_base = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !child_is_primitive {
|
||||||
|
if let Some(t_val) = c.obj.get_discriminator_value("type", &child_id) {
|
||||||
type_vals.insert(t_val);
|
type_vals.insert(t_val);
|
||||||
}
|
}
|
||||||
if let Some(k_val) = c.obj.get_discriminator_value("kind") {
|
if let Some(k_val) = c.obj.get_discriminator_value("kind", &child_id) {
|
||||||
kind_vals.insert(k_val);
|
kind_vals.insert(k_val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if disjoint_base && structural_types.len() == one_of.len() {
|
||||||
|
strategy = "".to_string();
|
||||||
|
for (i, c) in one_of.iter().enumerate() {
|
||||||
|
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &c.obj.type_ {
|
||||||
|
if crate::database::object::is_primitive_type(t) {
|
||||||
|
options.insert(t.clone(), (Some(i), None));
|
||||||
|
} else {
|
||||||
|
options.insert("object".to_string(), (Some(i), None));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
strategy = if type_vals.len() > 1 && type_vals.len() == one_of.len() {
|
strategy = if type_vals.len() > 1 && type_vals.len() == one_of.len() {
|
||||||
"type".to_string()
|
"type".to_string()
|
||||||
} else if kind_vals.len() > 1 && kind_vals.len() == one_of.len() {
|
} else if kind_vals.len() > 1 && kind_vals.len() == one_of.len() {
|
||||||
@ -354,31 +423,41 @@ impl Schema {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if strategy.is_empty() {
|
if strategy.is_empty() {
|
||||||
|
errors.push(crate::drop::Error {
|
||||||
|
code: "AMBIGUOUS_POLYMORPHISM".to_string(),
|
||||||
|
message: format!("oneOf boundaries must map mathematically unique 'type' or 'kind' discriminators, or strictly contain disjoint primitive types."),
|
||||||
|
details: crate::drop::ErrorDetails {
|
||||||
|
path: path.to_string(),
|
||||||
|
schema: Some(root_id.to_string()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for c in one_of {
|
for (i, c) in one_of.iter().enumerate() {
|
||||||
if let Some(val) = c.obj.get_discriminator_value(&strategy) {
|
let mut child_id = String::new();
|
||||||
|
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &c.obj.type_ {
|
||||||
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
|
child_id = t.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(val) = c.obj.get_discriminator_value(&strategy, &child_id) {
|
||||||
if options.contains_key(&val) {
|
if options.contains_key(&val) {
|
||||||
errors.push(crate::drop::Error {
|
errors.push(crate::drop::Error {
|
||||||
code: "POLYMORPHIC_COLLISION".to_string(),
|
code: "POLYMORPHIC_COLLISION".to_string(),
|
||||||
message: format!("Polymorphic boundary defines multiple candidates mapped to the identical discriminator value '{}'.", val),
|
message: format!("Polymorphic boundary defines multiple candidates mapped to the identical discriminator value '{}'.", val),
|
||||||
details: crate::drop::ErrorDetails::default()
|
details: crate::drop::ErrorDetails {
|
||||||
|
path: path.to_string(),
|
||||||
|
schema: Some(root_id.to_string()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut target_id = c.obj.id.clone();
|
options.insert(val, (Some(i), None));
|
||||||
if target_id.is_none() {
|
|
||||||
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &c.obj.type_ {
|
|
||||||
if !crate::database::object::is_primitive_type(t) {
|
|
||||||
target_id = Some(t.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(tid) = target_id {
|
|
||||||
options.insert(val, tid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -387,13 +466,21 @@ impl Schema {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !options.is_empty() {
|
if !options.is_empty() {
|
||||||
|
if !strategy.is_empty() {
|
||||||
let _ = self.obj.compiled_discriminator.set(strategy);
|
let _ = self.obj.compiled_discriminator.set(strategy);
|
||||||
|
}
|
||||||
let _ = self.obj.compiled_options.set(options);
|
let _ = self.obj.compiled_options.set(options);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn validate_identifier(id: &str, field_name: &str, errors: &mut Vec<crate::drop::Error>) {
|
fn validate_identifier(
|
||||||
|
id: &str,
|
||||||
|
field_name: &str,
|
||||||
|
root_id: &str,
|
||||||
|
path: &str,
|
||||||
|
errors: &mut Vec<crate::drop::Error>,
|
||||||
|
) {
|
||||||
#[cfg(not(test))]
|
#[cfg(not(test))]
|
||||||
for c in id.chars() {
|
for c in id.chars() {
|
||||||
if !c.is_ascii_lowercase() && !c.is_ascii_digit() && c != '_' && c != '.' {
|
if !c.is_ascii_lowercase() && !c.is_ascii_digit() && c != '_' && c != '.' {
|
||||||
@ -403,7 +490,11 @@ impl Schema {
|
|||||||
"Invalid character '{}' in JSON Schema '{}' property: '{}'. Identifiers must exclusively contain [a-z0-9_.]",
|
"Invalid character '{}' in JSON Schema '{}' property: '{}'. Identifiers must exclusively contain [a-z0-9_.]",
|
||||||
c, field_name, id
|
c, field_name, id
|
||||||
),
|
),
|
||||||
details: crate::drop::ErrorDetails::default(),
|
details: crate::drop::ErrorDetails {
|
||||||
|
path: path.to_string(),
|
||||||
|
schema: Some(root_id.to_string()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -411,116 +502,124 @@ impl Schema {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_schemas(
|
pub fn collect_schemas(
|
||||||
&mut self,
|
schema_arc: &Arc<Schema>,
|
||||||
tracking_path: Option<String>,
|
root_id: &str,
|
||||||
to_insert: &mut Vec<(String, Schema)>,
|
path: String,
|
||||||
|
to_insert: &mut Vec<(String, Arc<Schema>)>,
|
||||||
errors: &mut Vec<crate::drop::Error>,
|
errors: &mut Vec<crate::drop::Error>,
|
||||||
) {
|
) {
|
||||||
if let Some(id) = &self.obj.id {
|
let mut should_push = false;
|
||||||
Self::validate_identifier(id, "$id", errors);
|
|
||||||
to_insert.push((id.clone(), self.clone()));
|
// Push ad-hoc inline composition into the addressable registry
|
||||||
|
if schema_arc.obj.properties.is_some()
|
||||||
|
|| schema_arc.obj.items.is_some()
|
||||||
|
|| schema_arc.obj.family.is_some()
|
||||||
|
|| schema_arc.obj.one_of.is_some()
|
||||||
|
{
|
||||||
|
should_push = true;
|
||||||
}
|
}
|
||||||
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &self.obj.type_ {
|
|
||||||
|
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &schema_arc.obj.type_ {
|
||||||
if !crate::database::object::is_primitive_type(t) {
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
Self::validate_identifier(t, "type", errors);
|
Self::validate_identifier(t, "type", root_id, &path, errors);
|
||||||
}
|
should_push = true;
|
||||||
}
|
|
||||||
if let Some(family) = &self.obj.family {
|
|
||||||
Self::validate_identifier(family, "$family", errors);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is this schema an inline ad-hoc composition?
|
|
||||||
// Meaning it has a tracking context, lacks an explicit $id, but extends an Entity ref with explicit properties!
|
|
||||||
if self.obj.id.is_none() && self.obj.properties.is_some() {
|
|
||||||
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &self.obj.type_ {
|
|
||||||
if !crate::database::object::is_primitive_type(t) {
|
|
||||||
if let Some(ref path) = tracking_path {
|
|
||||||
to_insert.push((path.clone(), self.clone()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide the path origin to children natively, prioritizing the explicit `$id` boundary if one exists
|
if let Some(family) = &schema_arc.obj.family {
|
||||||
let origin_path = self.obj.id.clone().or(tracking_path);
|
Self::validate_identifier(family, "$family", root_id, &path, errors);
|
||||||
|
}
|
||||||
|
|
||||||
self.collect_child_schemas(origin_path, to_insert, errors);
|
if should_push {
|
||||||
|
to_insert.push((path.clone(), Arc::clone(schema_arc)));
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::collect_child_schemas(schema_arc, root_id, path, to_insert, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn collect_child_schemas(
|
pub fn collect_child_schemas(
|
||||||
&mut self,
|
schema_arc: &Arc<Schema>,
|
||||||
origin_path: Option<String>,
|
root_id: &str,
|
||||||
to_insert: &mut Vec<(String, Schema)>,
|
path: String,
|
||||||
|
to_insert: &mut Vec<(String, Arc<Schema>)>,
|
||||||
errors: &mut Vec<crate::drop::Error>,
|
errors: &mut Vec<crate::drop::Error>,
|
||||||
) {
|
) {
|
||||||
if let Some(props) = &mut self.obj.properties {
|
if let Some(props) = &schema_arc.obj.properties {
|
||||||
for (k, v) in props.iter_mut() {
|
for (k, v) in props.iter() {
|
||||||
let mut inner = (**v).clone();
|
let next_path = format!("{}/{}", path, k);
|
||||||
let next_path = origin_path.as_ref().map(|o| format!("{}/{}", o, k));
|
Self::collect_schemas(v, root_id, next_path, to_insert, errors);
|
||||||
inner.collect_schemas(next_path, to_insert, errors);
|
|
||||||
*v = Arc::new(inner);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(pattern_props) = &mut self.obj.pattern_properties {
|
if let Some(pattern_props) = &schema_arc.obj.pattern_properties {
|
||||||
for (k, v) in pattern_props.iter_mut() {
|
for (k, v) in pattern_props.iter() {
|
||||||
let mut inner = (**v).clone();
|
let next_path = format!("{}/{}", path, k);
|
||||||
let next_path = origin_path.as_ref().map(|o| format!("{}/{}", o, k));
|
Self::collect_schemas(v, root_id, next_path, to_insert, errors);
|
||||||
inner.collect_schemas(next_path, to_insert, errors);
|
|
||||||
*v = Arc::new(inner);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut map_arr = |arr: &mut Vec<Arc<Schema>>| {
|
let mut map_arr = |arr: &Vec<Arc<Schema>>, sub: &str| {
|
||||||
for v in arr.iter_mut() {
|
for (i, v) in arr.iter().enumerate() {
|
||||||
let mut inner = (**v).clone();
|
Self::collect_schemas(v, root_id, format!("{}/{}/{}", path, sub, i), to_insert, errors);
|
||||||
inner.collect_schemas(origin_path.clone(), to_insert, errors);
|
|
||||||
*v = Arc::new(inner);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(arr) = &mut self.obj.prefix_items {
|
if let Some(arr) = &schema_arc.obj.prefix_items {
|
||||||
map_arr(arr);
|
map_arr(arr, "prefixItems");
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(arr) = &mut self.obj.one_of {
|
if let Some(arr) = &schema_arc.obj.one_of {
|
||||||
map_arr(arr);
|
map_arr(arr, "oneOf");
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut map_opt = |opt: &mut Option<Arc<Schema>>, pass_path: bool| {
|
let mut map_opt = |opt: &Option<Arc<Schema>>, pass_path: bool, sub: &str| {
|
||||||
if let Some(v) = opt {
|
if let Some(v) = opt {
|
||||||
let mut inner = (**v).clone();
|
if pass_path {
|
||||||
let next = if pass_path { origin_path.clone() } else { None };
|
Self::collect_schemas(v, root_id, format!("{}/{}", path, sub), to_insert, errors);
|
||||||
inner.collect_schemas(next, to_insert, errors);
|
} else {
|
||||||
*v = Arc::new(inner);
|
Self::collect_child_schemas(v, root_id, format!("{}/{}", path, sub), to_insert, errors);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
map_opt(&mut self.obj.additional_properties, false);
|
map_opt(
|
||||||
|
&schema_arc.obj.additional_properties,
|
||||||
|
false,
|
||||||
|
"additionalProperties",
|
||||||
|
);
|
||||||
|
map_opt(&schema_arc.obj.items, true, "items");
|
||||||
|
map_opt(&schema_arc.obj.not, false, "not");
|
||||||
|
map_opt(&schema_arc.obj.contains, false, "contains");
|
||||||
|
map_opt(&schema_arc.obj.property_names, false, "propertyNames");
|
||||||
|
|
||||||
// `items` absolutely must inherit the EXACT property path assigned to the Array wrapper!
|
if let Some(cases) = &schema_arc.obj.cases {
|
||||||
// This allows nested Arrays enclosing bare Entity structs to correctly register as the boundary mapping.
|
for (i, c) in cases.iter().enumerate() {
|
||||||
map_opt(&mut self.obj.items, true);
|
if let Some(when) = &c.when {
|
||||||
|
Self::collect_schemas(
|
||||||
map_opt(&mut self.obj.not, false);
|
when,
|
||||||
map_opt(&mut self.obj.contains, false);
|
root_id,
|
||||||
map_opt(&mut self.obj.property_names, false);
|
format!("{}/cases/{}/when", path, i),
|
||||||
if let Some(cases) = &mut self.obj.cases {
|
to_insert,
|
||||||
for c in cases.iter_mut() {
|
errors,
|
||||||
if let Some(when) = &mut c.when {
|
);
|
||||||
let mut inner = (**when).clone();
|
|
||||||
inner.collect_schemas(origin_path.clone(), to_insert, errors);
|
|
||||||
*when = Arc::new(inner);
|
|
||||||
}
|
}
|
||||||
if let Some(then) = &mut c.then {
|
if let Some(then) = &c.then {
|
||||||
let mut inner = (**then).clone();
|
Self::collect_schemas(
|
||||||
inner.collect_schemas(origin_path.clone(), to_insert, errors);
|
then,
|
||||||
*then = Arc::new(inner);
|
root_id,
|
||||||
|
format!("{}/cases/{}/then", path, i),
|
||||||
|
to_insert,
|
||||||
|
errors,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if let Some(else_) = &mut c.else_ {
|
if let Some(else_) = &c.else_ {
|
||||||
let mut inner = (**else_).clone();
|
Self::collect_schemas(
|
||||||
inner.collect_schemas(origin_path.clone(), to_insert, errors);
|
else_,
|
||||||
*else_ = Arc::new(inner);
|
root_id,
|
||||||
|
format!("{}/cases/{}/else", path, i),
|
||||||
|
to_insert,
|
||||||
|
errors,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ use std::collections::HashSet;
|
|||||||
|
|
||||||
use crate::database::schema::Schema;
|
use crate::database::schema::Schema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::sync::Arc;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||||
@ -38,5 +39,5 @@ pub struct Type {
|
|||||||
pub default_fields: Vec<String>,
|
pub default_fields: Vec<String>,
|
||||||
pub field_types: Option<Value>,
|
pub field_types: Option<Value>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub schemas: Vec<Schema>,
|
pub schemas: std::collections::BTreeMap<String, Arc<Schema>>,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -142,12 +142,22 @@ impl Merger {
|
|||||||
if let Some(disc) = schema.obj.compiled_discriminator.get() {
|
if let Some(disc) = schema.obj.compiled_discriminator.get() {
|
||||||
let val = map.get(disc).and_then(|v| v.as_str());
|
let val = map.get(disc).and_then(|v| v.as_str());
|
||||||
if let Some(v) = val {
|
if let Some(v) = val {
|
||||||
if let Some(target_id) = options.get(v) {
|
if let Some((idx_opt, target_id_opt)) = options.get(v) {
|
||||||
|
if let Some(target_id) = target_id_opt {
|
||||||
if let Some(target_schema) = self.db.schemas.get(target_id) {
|
if let Some(target_schema) = self.db.schemas.get(target_id) {
|
||||||
schema = Arc::clone(target_schema);
|
schema = Arc::clone(target_schema);
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("Polymorphic mapped target '{}' not found in database registry", target_id));
|
return Err(format!("Polymorphic mapped target '{}' not found in database registry", target_id));
|
||||||
}
|
}
|
||||||
|
} else if let Some(idx) = idx_opt {
|
||||||
|
if let Some(target_schema) = schema.obj.one_of.as_ref().and_then(|options| options.get(*idx)) {
|
||||||
|
schema = Arc::clone(target_schema);
|
||||||
|
} else {
|
||||||
|
return Err(format!("Polymorphic index target '{}' not found in local oneOf array", idx));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Err(format!("Polymorphic mapped target has no path"));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(format!("Polymorphic discriminator {}='{}' matched no compiled options", disc, v));
|
return Err(format!("Polymorphic discriminator {}='{}' matched no compiled options", disc, v));
|
||||||
}
|
}
|
||||||
@ -215,7 +225,7 @@ impl Merger {
|
|||||||
for (k, v) in obj {
|
for (k, v) in obj {
|
||||||
// Always retain system and unmapped core fields natively implicitly mapped to the Postgres tables
|
// Always retain system and unmapped core fields natively implicitly mapped to the Postgres tables
|
||||||
if k == "id" || k == "type" || k == "created" {
|
if k == "id" || k == "type" || k == "created" {
|
||||||
entity_fields.insert(k.clone(), v.clone());
|
entity_fields.insert(k, v);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,18 +244,18 @@ impl Merger {
|
|||||||
_ => "field", // Malformed edge data?
|
_ => "field", // Malformed edge data?
|
||||||
};
|
};
|
||||||
if typeof_v == "object" {
|
if typeof_v == "object" {
|
||||||
entity_objects.insert(k.clone(), (v.clone(), prop_schema.clone()));
|
entity_objects.insert(k, (v, prop_schema.clone()));
|
||||||
} else if typeof_v == "array" {
|
} else if typeof_v == "array" {
|
||||||
entity_arrays.insert(k.clone(), (v.clone(), prop_schema.clone()));
|
entity_arrays.insert(k, (v, prop_schema.clone()));
|
||||||
} else {
|
} else {
|
||||||
entity_fields.insert(k.clone(), v.clone());
|
entity_fields.insert(k, v);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Not an edge! It's a raw Postgres column (e.g., JSONB, text[])
|
// Not an edge! It's a raw Postgres column (e.g., JSONB, text[])
|
||||||
entity_fields.insert(k.clone(), v.clone());
|
entity_fields.insert(k, v);
|
||||||
}
|
}
|
||||||
} else if type_def.fields.contains(&k) {
|
} else if type_def.fields.contains(&k) {
|
||||||
entity_fields.insert(k.clone(), v.clone());
|
entity_fields.insert(k, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,7 +534,7 @@ impl Merger {
|
|||||||
|
|
||||||
entity_change_kind = Some("create".to_string());
|
entity_change_kind = Some("create".to_string());
|
||||||
|
|
||||||
let mut new_fields = changes.clone();
|
let mut new_fields = changes;
|
||||||
new_fields.insert("id".to_string(), id_val);
|
new_fields.insert("id".to_string(), id_val);
|
||||||
new_fields.insert("type".to_string(), Value::String(type_name.to_string()));
|
new_fields.insert("type".to_string(), Value::String(type_name.to_string()));
|
||||||
new_fields.insert("created_by".to_string(), Value::String(user_id.to_string()));
|
new_fields.insert("created_by".to_string(), Value::String(user_id.to_string()));
|
||||||
@ -564,7 +574,7 @@ impl Merger {
|
|||||||
Some("update".to_string())
|
Some("update".to_string())
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut new_fields = changes.clone();
|
let mut new_fields = changes;
|
||||||
new_fields.insert(
|
new_fields.insert(
|
||||||
"id".to_string(),
|
"id".to_string(),
|
||||||
entity_fetched.as_ref().unwrap().get("id").unwrap().clone(),
|
entity_fetched.as_ref().unwrap().get("id").unwrap().clone(),
|
||||||
|
|||||||
@ -18,6 +18,7 @@ pub struct Node<'a> {
|
|||||||
pub depth: usize,
|
pub depth: usize,
|
||||||
pub ast_path: String,
|
pub ast_path: String,
|
||||||
pub is_polymorphic_branch: bool,
|
pub is_polymorphic_branch: bool,
|
||||||
|
pub schema_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Compiler<'a> {
|
impl<'a> Compiler<'a> {
|
||||||
@ -47,6 +48,7 @@ impl<'a> Compiler<'a> {
|
|||||||
depth: 0,
|
depth: 0,
|
||||||
ast_path: String::new(),
|
ast_path: String::new(),
|
||||||
is_polymorphic_branch: false,
|
is_polymorphic_branch: false,
|
||||||
|
schema_id: Some(schema_id.to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (sql, _) = compiler.compile_node(node)?;
|
let (sql, _) = compiler.compile_node(node)?;
|
||||||
@ -66,17 +68,31 @@ impl<'a> Compiler<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn compile_array(&mut self, node: Node<'a>) -> Result<(String, String), String> {
|
fn compile_array(&mut self, node: Node<'a>) -> Result<(String, String), String> {
|
||||||
// 1. Array of DB Entities (`type` or `$family` pointing to a table limit)
|
|
||||||
if let Some(items) = &node.schema.obj.items {
|
if let Some(items) = &node.schema.obj.items {
|
||||||
let mut resolved_type = None;
|
let mut resolved_type = None;
|
||||||
|
if let Some(sid) = &node.schema_id {
|
||||||
|
resolved_type = self
|
||||||
|
.db
|
||||||
|
.types
|
||||||
|
.get(&sid.split('.').next_back().unwrap_or(sid).to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if resolved_type.is_none() {
|
||||||
if let Some(family_target) = items.obj.family.as_ref() {
|
if let Some(family_target) = items.obj.family.as_ref() {
|
||||||
let base_type_name = family_target
|
let base_type_name = family_target
|
||||||
.split('.')
|
.split('.')
|
||||||
.next_back()
|
.next_back()
|
||||||
.unwrap_or(family_target);
|
.unwrap_or(family_target);
|
||||||
resolved_type = self.db.types.get(base_type_name);
|
resolved_type = self.db.types.get(base_type_name);
|
||||||
} else if let Some(base_type_name) = items.obj.identifier() {
|
} else if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &items.obj.type_
|
||||||
resolved_type = self.db.types.get(&base_type_name);
|
{
|
||||||
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
|
resolved_type = self
|
||||||
|
.db
|
||||||
|
.types
|
||||||
|
.get(&t.split('.').next_back().unwrap_or(t).to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(type_def) = resolved_type {
|
if let Some(type_def) = resolved_type {
|
||||||
@ -105,15 +121,27 @@ impl<'a> Compiler<'a> {
|
|||||||
// Determine if this schema represents a Database Entity
|
// Determine if this schema represents a Database Entity
|
||||||
let mut resolved_type = None;
|
let mut resolved_type = None;
|
||||||
|
|
||||||
|
if let Some(sid) = &node.schema_id {
|
||||||
|
let base_type_name = sid.split('.').next_back().unwrap_or(sid).to_string();
|
||||||
|
resolved_type = self.db.types.get(&base_type_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if resolved_type.is_none() {
|
||||||
if let Some(family_target) = node.schema.obj.family.as_ref() {
|
if let Some(family_target) = node.schema.obj.family.as_ref() {
|
||||||
let base_type_name = family_target
|
let base_type_name = family_target
|
||||||
.split('.')
|
.split('.')
|
||||||
.next_back()
|
.next_back()
|
||||||
.unwrap_or(family_target);
|
.unwrap_or(family_target);
|
||||||
resolved_type = self.db.types.get(base_type_name);
|
resolved_type = self.db.types.get(base_type_name);
|
||||||
} else if let Some(base_type_name) = node.schema.obj.identifier() {
|
} else if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) =
|
||||||
|
&node.schema.obj.type_
|
||||||
|
{
|
||||||
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
|
let base_type_name = t.split('.').next_back().unwrap_or(t).to_string();
|
||||||
resolved_type = self.db.types.get(&base_type_name);
|
resolved_type = self.db.types.get(&base_type_name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(type_def) = resolved_type {
|
if let Some(type_def) = resolved_type {
|
||||||
return self.compile_entity(type_def, node.clone(), false);
|
return self.compile_entity(type_def, node.clone(), false);
|
||||||
@ -126,6 +154,7 @@ impl<'a> Compiler<'a> {
|
|||||||
if let Some(target_schema) = self.db.schemas.get(t) {
|
if let Some(target_schema) = self.db.schemas.get(t) {
|
||||||
let mut ref_node = node.clone();
|
let mut ref_node = node.clone();
|
||||||
ref_node.schema = Arc::clone(target_schema);
|
ref_node.schema = Arc::clone(target_schema);
|
||||||
|
ref_node.schema_id = Some(t.clone());
|
||||||
return self.compile_node(ref_node);
|
return self.compile_node(ref_node);
|
||||||
}
|
}
|
||||||
return Err(format!("Unresolved schema type pointer: {}", t));
|
return Err(format!("Unresolved schema type pointer: {}", t));
|
||||||
@ -135,14 +164,18 @@ impl<'a> Compiler<'a> {
|
|||||||
if node.schema.obj.family.is_some() || node.schema.obj.one_of.is_some() {
|
if node.schema.obj.family.is_some() || node.schema.obj.one_of.is_some() {
|
||||||
if let Some(options) = node.schema.obj.compiled_options.get() {
|
if let Some(options) = node.schema.obj.compiled_options.get() {
|
||||||
if options.len() == 1 {
|
if options.len() == 1 {
|
||||||
let target_id = options.values().next().unwrap();
|
let (_, target_opt) = options.values().next().unwrap();
|
||||||
|
if let Some(target_id) = target_opt {
|
||||||
let mut bypass_schema = crate::database::schema::Schema::default();
|
let mut bypass_schema = crate::database::schema::Schema::default();
|
||||||
bypass_schema.obj.type_ = Some(crate::database::object::SchemaTypeOrArray::Single(target_id.clone()));
|
bypass_schema.obj.type_ = Some(crate::database::object::SchemaTypeOrArray::Single(
|
||||||
|
target_id.clone(),
|
||||||
|
));
|
||||||
let mut bypass_node = node.clone();
|
let mut bypass_node = node.clone();
|
||||||
bypass_node.schema = std::sync::Arc::new(bypass_schema);
|
bypass_node.schema = std::sync::Arc::new(bypass_schema);
|
||||||
return self.compile_node(bypass_node);
|
return self.compile_node(bypass_node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return self.compile_one_of(node);
|
return self.compile_one_of(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,14 +282,21 @@ impl<'a> Compiler<'a> {
|
|||||||
Ok((combined, "object".to_string()))
|
Ok((combined, "object".to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_one_of(
|
fn compile_one_of(&mut self, node: Node<'a>) -> Result<(String, String), String> {
|
||||||
&mut self,
|
|
||||||
node: Node<'a>,
|
|
||||||
) -> Result<(String, String), String> {
|
|
||||||
let mut case_statements = Vec::new();
|
let mut case_statements = Vec::new();
|
||||||
|
|
||||||
let options = node.schema.obj.compiled_options.get().ok_or("Missing compiled options for polymorphism")?;
|
let options = node
|
||||||
let disc = node.schema.obj.compiled_discriminator.get().ok_or("Missing compiled discriminator for polymorphism")?;
|
.schema
|
||||||
|
.obj
|
||||||
|
.compiled_options
|
||||||
|
.get()
|
||||||
|
.ok_or("Missing compiled options for polymorphism")?;
|
||||||
|
let disc = node
|
||||||
|
.schema
|
||||||
|
.obj
|
||||||
|
.compiled_discriminator
|
||||||
|
.get()
|
||||||
|
.ok_or("Missing compiled discriminator for polymorphism")?;
|
||||||
|
|
||||||
let type_col = if let Some(prop) = &node.property_name {
|
let type_col = if let Some(prop) = &node.property_name {
|
||||||
format!("{}_{}", prop, disc)
|
format!("{}_{}", prop, disc)
|
||||||
@ -264,8 +304,45 @@ impl<'a> Compiler<'a> {
|
|||||||
disc.to_string()
|
disc.to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
for (disc_val, target_id) in options {
|
for (disc_val, (idx_opt, target_id_opt)) in options {
|
||||||
|
if let Some(target_id) = target_id_opt {
|
||||||
if let Some(target_schema) = self.db.schemas.get(target_id) {
|
if let Some(target_schema) = self.db.schemas.get(target_id) {
|
||||||
|
let mut child_node = node.clone();
|
||||||
|
child_node.schema = Arc::clone(target_schema);
|
||||||
|
child_node.schema_id = Some(target_id.clone());
|
||||||
|
child_node.is_polymorphic_branch = true;
|
||||||
|
|
||||||
|
let val_sql =
|
||||||
|
if disc == "kind" && node.parent_type.is_some() && node.parent_type_aliases.is_some() {
|
||||||
|
let aliases_arc = node.parent_type_aliases.as_ref().unwrap();
|
||||||
|
let aliases = aliases_arc.as_ref();
|
||||||
|
let p_type = node.parent_type.unwrap();
|
||||||
|
|
||||||
|
let select_args = self.compile_select_clause(p_type, aliases, child_node.clone())?;
|
||||||
|
|
||||||
|
if select_args.is_empty() {
|
||||||
|
"jsonb_build_object()".to_string()
|
||||||
|
} else {
|
||||||
|
format!("jsonb_build_object({})", select_args.join(", "))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let (sql, _) = self.compile_node(child_node)?;
|
||||||
|
sql
|
||||||
|
};
|
||||||
|
|
||||||
|
case_statements.push(format!(
|
||||||
|
"WHEN {}.{} = '{}' THEN ({})",
|
||||||
|
node.parent_alias, type_col, disc_val, val_sql
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if let Some(idx) = idx_opt {
|
||||||
|
if let Some(target_schema) = node
|
||||||
|
.schema
|
||||||
|
.obj
|
||||||
|
.one_of
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|options| options.get(*idx))
|
||||||
|
{
|
||||||
let mut child_node = node.clone();
|
let mut child_node = node.clone();
|
||||||
child_node.schema = Arc::clone(target_schema);
|
child_node.schema = Arc::clone(target_schema);
|
||||||
child_node.is_polymorphic_branch = true;
|
child_node.is_polymorphic_branch = true;
|
||||||
@ -293,7 +370,7 @@ impl<'a> Compiler<'a> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if case_statements.is_empty() {
|
if case_statements.is_empty() {
|
||||||
return Ok(("NULL".to_string(), "string".to_string()));
|
return Ok(("NULL".to_string(), "string".to_string()));
|
||||||
}
|
}
|
||||||
@ -339,14 +416,14 @@ impl<'a> Compiler<'a> {
|
|||||||
let mut select_args = Vec::new();
|
let mut select_args = Vec::new();
|
||||||
let grouped_fields = r#type.grouped_fields.as_ref().and_then(|v| v.as_object());
|
let grouped_fields = r#type.grouped_fields.as_ref().and_then(|v| v.as_object());
|
||||||
let default_props = std::collections::BTreeMap::new();
|
let default_props = std::collections::BTreeMap::new();
|
||||||
let merged_props = node.schema.obj.compiled_properties.get().unwrap_or(&default_props);
|
let merged_props = node
|
||||||
|
.schema
|
||||||
let mut sorted_keys: Vec<&String> = merged_props.keys().collect();
|
.obj
|
||||||
sorted_keys.sort();
|
.compiled_properties
|
||||||
|
.get()
|
||||||
for prop_key in sorted_keys {
|
.unwrap_or(&default_props);
|
||||||
let prop_schema = &merged_props[prop_key];
|
|
||||||
|
|
||||||
|
for (prop_key, prop_schema) in merged_props {
|
||||||
let is_object_or_array = match &prop_schema.obj.type_ {
|
let is_object_or_array = match &prop_schema.obj.type_ {
|
||||||
Some(crate::database::object::SchemaTypeOrArray::Single(s)) => {
|
Some(crate::database::object::SchemaTypeOrArray::Single(s)) => {
|
||||||
s == "object" || s == "array"
|
s == "object" || s == "array"
|
||||||
@ -410,6 +487,7 @@ impl<'a> Compiler<'a> {
|
|||||||
format!("{}/{}", node.ast_path, prop_key)
|
format!("{}/{}", node.ast_path, prop_key)
|
||||||
},
|
},
|
||||||
is_polymorphic_branch: false,
|
is_polymorphic_branch: false,
|
||||||
|
schema_id: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (val_sql, val_type) = self.compile_node(child_node)?;
|
let (val_sql, val_type) = self.compile_node(child_node)?;
|
||||||
@ -491,8 +569,12 @@ impl<'a> Compiler<'a> {
|
|||||||
.unwrap_or(family_target)
|
.unwrap_or(family_target)
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
} else if let Some(lookup_key) = prop_schema.obj.identifier() {
|
} else if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) =
|
||||||
bound_type_name = Some(lookup_key);
|
&prop_schema.obj.type_
|
||||||
|
{
|
||||||
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
|
bound_type_name = Some(t.split('.').next_back().unwrap_or(t).to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(type_name) = bound_type_name {
|
if let Some(type_name) = bound_type_name {
|
||||||
|
|||||||
@ -1553,24 +1553,6 @@ fn test_polymorphism_4_1() {
|
|||||||
crate::tests::runner::run_test_case(&path, 4, 1).unwrap();
|
crate::tests::runner::run_test_case(&path, 4, 1).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_polymorphism_5_0() {
|
|
||||||
let path = format!("{}/fixtures/polymorphism.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::tests::runner::run_test_case(&path, 5, 0).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_polymorphism_5_1() {
|
|
||||||
let path = format!("{}/fixtures/polymorphism.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::tests::runner::run_test_case(&path, 5, 1).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_polymorphism_5_2() {
|
|
||||||
let path = format!("{}/fixtures/polymorphism.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::tests::runner::run_test_case(&path, 5, 2).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_not_0_0() {
|
fn test_not_0_0() {
|
||||||
let path = format!("{}/fixtures/not.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/fixtures/not.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
@ -3558,9 +3540,9 @@ fn test_paths_1_0() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_paths_1_1() {
|
fn test_paths_2_0() {
|
||||||
let path = format!("{}/fixtures/paths.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/fixtures/paths.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
crate::tests::runner::run_test_case(&path, 1, 1).unwrap();
|
crate::tests::runner::run_test_case(&path, 2, 0).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -7740,21 +7722,9 @@ fn test_object_types_2_1() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_object_types_3_0() {
|
fn test_object_types_2_2() {
|
||||||
let path = format!("{}/fixtures/objectTypes.json", env!("CARGO_MANIFEST_DIR"));
|
let path = format!("{}/fixtures/objectTypes.json", env!("CARGO_MANIFEST_DIR"));
|
||||||
crate::tests::runner::run_test_case(&path, 3, 0).unwrap();
|
crate::tests::runner::run_test_case(&path, 2, 2).unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_object_types_3_1() {
|
|
||||||
let path = format!("{}/fixtures/objectTypes.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::tests::runner::run_test_case(&path, 3, 1).unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_object_types_3_2() {
|
|
||||||
let path = format!("{}/fixtures/objectTypes.json", env!("CARGO_MANIFEST_DIR"));
|
|
||||||
crate::tests::runner::run_test_case(&path, 3, 2).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -44,27 +44,30 @@ fn test_library_api() {
|
|||||||
"name": "source_schema",
|
"name": "source_schema",
|
||||||
"variations": ["source_schema"],
|
"variations": ["source_schema"],
|
||||||
"hierarchy": ["source_schema", "entity"],
|
"hierarchy": ["source_schema", "entity"],
|
||||||
"schemas": [{
|
"schemas": {
|
||||||
"$id": "source_schema",
|
"source_schema": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"type": { "type": "string" },
|
||||||
"name": { "type": "string" },
|
"name": { "type": "string" },
|
||||||
"target": { "type": "target_schema" }
|
"target": { "type": "target_schema" }
|
||||||
},
|
},
|
||||||
"required": ["name"]
|
"required": ["name"]
|
||||||
}]
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "target_schema",
|
"name": "target_schema",
|
||||||
"variations": ["target_schema"],
|
"variations": ["target_schema"],
|
||||||
"hierarchy": ["target_schema", "entity"],
|
"hierarchy": ["target_schema", "entity"],
|
||||||
"schemas": [{
|
"schemas": {
|
||||||
"$id": "target_schema",
|
"target_schema": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"value": { "type": "number" }
|
"value": { "type": "number" }
|
||||||
}
|
}
|
||||||
}]
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -86,9 +89,9 @@ fn test_library_api() {
|
|||||||
"type": "drop",
|
"type": "drop",
|
||||||
"response": {
|
"response": {
|
||||||
"source_schema": {
|
"source_schema": {
|
||||||
"$id": "source_schema",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"type": { "type": "string" },
|
||||||
"name": { "type": "string" },
|
"name": { "type": "string" },
|
||||||
"target": {
|
"target": {
|
||||||
"type": "target_schema",
|
"type": "target_schema",
|
||||||
@ -96,7 +99,7 @@ fn test_library_api() {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["name"],
|
"required": ["name"],
|
||||||
"compiledProperties": ["name", "target"],
|
"compiledProperties": ["name", "target", "type"],
|
||||||
"compiledEdges": {
|
"compiledEdges": {
|
||||||
"target": {
|
"target": {
|
||||||
"constraint": "fk_test_target",
|
"constraint": "fk_test_target",
|
||||||
@ -104,8 +107,11 @@ fn test_library_api() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"source_schema/target": {
|
||||||
|
"type": "target_schema",
|
||||||
|
"compiledProperties": ["value"]
|
||||||
|
},
|
||||||
"target_schema": {
|
"target_schema": {
|
||||||
"$id": "target_schema",
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"value": { "type": "number" }
|
"value": { "type": "number" }
|
||||||
|
|||||||
@ -93,11 +93,14 @@ impl<'a> ValidationContext<'a> {
|
|||||||
if i < len {
|
if i < len {
|
||||||
if let Some(child_instance) = arr.get(i) {
|
if let Some(child_instance) = arr.get(i) {
|
||||||
let mut item_path = self.join_path(&i.to_string());
|
let mut item_path = self.join_path(&i.to_string());
|
||||||
|
let is_topological = sub_schema.obj.requires_uuid_path(self.db);
|
||||||
|
if is_topological {
|
||||||
if let Some(obj) = child_instance.as_object() {
|
if let Some(obj) = child_instance.as_object() {
|
||||||
if let Some(id_str) = obj.get("id").and_then(|v| v.as_str()) {
|
if let Some(id_str) = obj.get("id").and_then(|v| v.as_str()) {
|
||||||
item_path = self.join_path(id_str);
|
item_path = self.join_path(id_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
let derived = self.derive(
|
let derived = self.derive(
|
||||||
sub_schema,
|
sub_schema,
|
||||||
child_instance,
|
child_instance,
|
||||||
@ -116,14 +119,17 @@ impl<'a> ValidationContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref items_schema) = self.schema.items {
|
if let Some(ref items_schema) = self.schema.items {
|
||||||
|
let is_topological = items_schema.obj.requires_uuid_path(self.db);
|
||||||
for i in validation_index..len {
|
for i in validation_index..len {
|
||||||
if let Some(child_instance) = arr.get(i) {
|
if let Some(child_instance) = arr.get(i) {
|
||||||
let mut item_path = self.join_path(&i.to_string());
|
let mut item_path = self.join_path(&i.to_string());
|
||||||
|
if is_topological {
|
||||||
if let Some(obj) = child_instance.as_object() {
|
if let Some(obj) = child_instance.as_object() {
|
||||||
if let Some(id_str) = obj.get("id").and_then(|v| v.as_str()) {
|
if let Some(id_str) = obj.get("id").and_then(|v| v.as_str()) {
|
||||||
item_path = self.join_path(id_str);
|
item_path = self.join_path(id_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
let derived = self.derive(
|
let derived = self.derive(
|
||||||
items_schema,
|
items_schema,
|
||||||
child_instance,
|
child_instance,
|
||||||
|
|||||||
@ -13,10 +13,17 @@ impl<'a> ValidationContext<'a> {
|
|||||||
) -> Result<bool, ValidationError> {
|
) -> Result<bool, ValidationError> {
|
||||||
let current = self.instance;
|
let current = self.instance;
|
||||||
if let Some(obj) = current.as_object() {
|
if let Some(obj) = current.as_object() {
|
||||||
|
let mut schema_identifier = None;
|
||||||
|
if let Some(crate::database::object::SchemaTypeOrArray::Single(t)) = &self.schema.type_ {
|
||||||
|
if !crate::database::object::is_primitive_type(t) {
|
||||||
|
schema_identifier = Some(t.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Entity implicit type validation
|
// Entity implicit type validation
|
||||||
if let Some(schema_identifier) = self.schema.identifier() {
|
if let Some(ref schema_identifier_str) = schema_identifier {
|
||||||
// We decompose identity string routing inherently
|
// We decompose identity string routing inherently
|
||||||
let expected_type = schema_identifier.split('.').last().unwrap_or(&schema_identifier);
|
let expected_type = schema_identifier_str.split('.').last().unwrap_or(schema_identifier_str);
|
||||||
|
|
||||||
// Check if the identifier represents a registered global database entity boundary mathematically
|
// Check if the identifier represents a registered global database entity boundary mathematically
|
||||||
if let Some(type_def) = self.db.types.get(expected_type) {
|
if let Some(type_def) = self.db.types.get(expected_type) {
|
||||||
@ -46,7 +53,7 @@ impl<'a> ValidationContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If the target mathematically declares a horizontal structural STI variation natively
|
// If the target mathematically declares a horizontal structural STI variation natively
|
||||||
if schema_identifier.contains('.') {
|
if schema_identifier_str.contains('.') {
|
||||||
if obj.get("kind").is_none() {
|
if obj.get("kind").is_none() {
|
||||||
result.errors.push(ValidationError {
|
result.errors.push(ValidationError {
|
||||||
code: "MISSING_KIND".to_string(),
|
code: "MISSING_KIND".to_string(),
|
||||||
@ -69,7 +76,7 @@ impl<'a> ValidationContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(kind_val) = obj.get("kind") {
|
if let Some(kind_val) = obj.get("kind") {
|
||||||
if let Some((kind_str, _)) = schema_identifier.rsplit_once('.') {
|
if let Some((kind_str, _)) = schema_identifier_str.rsplit_once('.') {
|
||||||
if let Some(actual_kind) = kind_val.as_str() {
|
if let Some(actual_kind) = kind_val.as_str() {
|
||||||
if actual_kind == kind_str {
|
if actual_kind == kind_str {
|
||||||
result.evaluated_keys.insert("kind".to_string());
|
result.evaluated_keys.insert("kind".to_string());
|
||||||
|
|||||||
@ -30,9 +30,14 @@ impl<'a> ValidationContext<'a> {
|
|||||||
|
|
||||||
if self.schema.family.is_some() {
|
if self.schema.family.is_some() {
|
||||||
if let Some(options) = self.schema.compiled_options.get() {
|
if let Some(options) = self.schema.compiled_options.get() {
|
||||||
if let Some(disc) = self.schema.compiled_discriminator.get() {
|
return self.execute_polymorph(options, result);
|
||||||
return self.execute_polymorph(disc, options, result);
|
} else {
|
||||||
}
|
result.errors.push(ValidationError {
|
||||||
|
code: "UNCOMPILED_FAMILY".to_string(),
|
||||||
|
message: "Encountered family block that could not be mapped to deterministic options during db schema compilation.".to_string(),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
return Ok(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,61 +48,13 @@ impl<'a> ValidationContext<'a> {
|
|||||||
&self,
|
&self,
|
||||||
result: &mut ValidationResult,
|
result: &mut ValidationResult,
|
||||||
) -> Result<bool, ValidationError> {
|
) -> Result<bool, ValidationError> {
|
||||||
if let Some(one_of) = &self.schema.one_of {
|
if self.schema.one_of.is_some() {
|
||||||
if let Some(options) = self.schema.compiled_options.get() {
|
if let Some(options) = self.schema.compiled_options.get() {
|
||||||
if let Some(disc) = self.schema.compiled_discriminator.get() {
|
return self.execute_polymorph(options, result);
|
||||||
return self.execute_polymorph(disc, options, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Native Draft2020-12 oneOf Evaluation Fallback
|
|
||||||
let mut valid_count = 0;
|
|
||||||
let mut final_successful_result = None;
|
|
||||||
let mut failed_candidates = Vec::new();
|
|
||||||
|
|
||||||
for child_schema in one_of {
|
|
||||||
let derived = self.derive_for_schema(child_schema, false);
|
|
||||||
if let Ok(sub_res) = derived.validate_scoped() {
|
|
||||||
if sub_res.is_valid() {
|
|
||||||
valid_count += 1;
|
|
||||||
final_successful_result = Some(sub_res.clone());
|
|
||||||
} else {
|
|
||||||
failed_candidates.push(sub_res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if valid_count == 1 {
|
|
||||||
if let Some(successful_res) = final_successful_result {
|
|
||||||
result.merge(successful_res);
|
|
||||||
}
|
|
||||||
return Ok(true);
|
|
||||||
} else if valid_count == 0 {
|
|
||||||
result.errors.push(ValidationError {
|
|
||||||
code: "NO_ONEOF_MATCH".to_string(),
|
|
||||||
message: "Payload matches none of the required candidate sub-schemas natively".to_string(),
|
|
||||||
path: self.path.to_string(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(first) = failed_candidates.first() {
|
|
||||||
let mut shared_errors = first.errors.clone();
|
|
||||||
for sub_res in failed_candidates.iter().skip(1) {
|
|
||||||
shared_errors.retain(|e1| {
|
|
||||||
sub_res.errors.iter().any(|e2| e1.code == e2.code && e1.path == e2.path)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
for e in shared_errors {
|
|
||||||
if !result.errors.iter().any(|existing| existing.code == e.code && existing.path == e.path) {
|
|
||||||
result.errors.push(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(false);
|
|
||||||
} else {
|
} else {
|
||||||
result.errors.push(ValidationError {
|
result.errors.push(ValidationError {
|
||||||
code: "AMBIGUOUS_POLYMORPHIC_MATCH".to_string(),
|
code: "UNCOMPILED_ONEOF".to_string(),
|
||||||
message: "Matches multiple polymorphic candidates inextricably natively".to_string(),
|
message: "Encountered oneOf block that could not be mapped to deterministic compiled options natively.".to_string(),
|
||||||
path: self.path.to_string(),
|
path: self.path.to_string(),
|
||||||
});
|
});
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
@ -108,17 +65,40 @@ impl<'a> ValidationContext<'a> {
|
|||||||
|
|
||||||
pub(crate) fn execute_polymorph(
|
pub(crate) fn execute_polymorph(
|
||||||
&self,
|
&self,
|
||||||
disc: &str,
|
options: &std::collections::BTreeMap<String, (Option<usize>, Option<String>)>,
|
||||||
options: &std::collections::BTreeMap<String, String>,
|
|
||||||
result: &mut ValidationResult,
|
result: &mut ValidationResult,
|
||||||
) -> Result<bool, ValidationError> {
|
) -> Result<bool, ValidationError> {
|
||||||
// 1. O(1) Fast-Path Router & Extractor
|
// 1. O(1) Fast-Path Router & Extractor
|
||||||
let instance_val = self.instance.as_object().and_then(|o| o.get(disc)).and_then(|t| t.as_str());
|
let instance_val = if let Some(disc) = self.schema.compiled_discriminator.get() {
|
||||||
|
let val = self
|
||||||
|
.instance
|
||||||
|
.as_object()
|
||||||
|
.and_then(|o| o.get(disc))
|
||||||
|
.and_then(|t| t.as_str());
|
||||||
|
if val.is_some() {
|
||||||
|
result.evaluated_keys.insert(disc.to_string());
|
||||||
|
}
|
||||||
|
val.map(|s| s.to_string())
|
||||||
|
} else {
|
||||||
|
match self.instance {
|
||||||
|
serde_json::Value::Null => Some("null".to_string()),
|
||||||
|
serde_json::Value::Bool(_) => Some("boolean".to_string()),
|
||||||
|
serde_json::Value::Number(n) => {
|
||||||
|
if n.is_i64() || n.is_u64() {
|
||||||
|
Some("integer".to_string())
|
||||||
|
} else {
|
||||||
|
Some("number".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serde_json::Value::String(_) => Some("string".to_string()),
|
||||||
|
serde_json::Value::Array(_) => Some("array".to_string()),
|
||||||
|
serde_json::Value::Object(_) => Some("object".to_string()),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(val) = instance_val {
|
if let Some(val) = instance_val {
|
||||||
result.evaluated_keys.insert(disc.to_string());
|
if let Some((idx_opt, target_id_opt)) = options.get(&val) {
|
||||||
|
if let Some(target_id) = target_id_opt {
|
||||||
if let Some(target_id) = options.get(val) {
|
|
||||||
if let Some(target_schema) = self.db.schemas.get(target_id) {
|
if let Some(target_schema) = self.db.schemas.get(target_id) {
|
||||||
let derived = self.derive_for_schema(target_schema.as_ref(), false);
|
let derived = self.derive_for_schema(target_schema.as_ref(), false);
|
||||||
let sub_res = derived.validate()?;
|
let sub_res = derived.validate()?;
|
||||||
@ -128,25 +108,71 @@ impl<'a> ValidationContext<'a> {
|
|||||||
} else {
|
} else {
|
||||||
result.errors.push(ValidationError {
|
result.errors.push(ValidationError {
|
||||||
code: "MISSING_COMPILED_SCHEMA".to_string(),
|
code: "MISSING_COMPILED_SCHEMA".to_string(),
|
||||||
message: format!("Polymorphic router target '{}' does not exist in the database schemas map", target_id),
|
message: format!(
|
||||||
|
"Polymorphic router target '{}' does not exist in the database schemas map",
|
||||||
|
target_id
|
||||||
|
),
|
||||||
path: self.path.to_string(),
|
path: self.path.to_string(),
|
||||||
});
|
});
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
} else if let Some(idx) = idx_opt {
|
||||||
|
if let Some(target_schema) = self
|
||||||
|
.schema
|
||||||
|
.one_of
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|options| options.get(*idx))
|
||||||
|
{
|
||||||
|
let derived = self.derive_for_schema(target_schema.as_ref(), false);
|
||||||
|
let sub_res = derived.validate()?;
|
||||||
|
let is_valid = sub_res.is_valid();
|
||||||
|
result.merge(sub_res);
|
||||||
|
return Ok(is_valid);
|
||||||
} else {
|
} else {
|
||||||
result.errors.push(ValidationError {
|
result.errors.push(ValidationError {
|
||||||
code: if self.schema.family.is_some() { "NO_FAMILY_MATCH".to_string() } else { "NO_ONEOF_MATCH".to_string() },
|
code: "MISSING_COMPILED_SCHEMA".to_string(),
|
||||||
message: format!("Payload provided discriminator {}='{}' which matches none of the required candidate sub-schemas", disc, val),
|
message: format!(
|
||||||
|
"Polymorphic index target '{}' does not exist in the local oneOf array",
|
||||||
|
idx
|
||||||
|
),
|
||||||
path: self.path.to_string(),
|
path: self.path.to_string(),
|
||||||
});
|
});
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let disc_msg = if let Some(d) = self.schema.compiled_discriminator.get() {
|
||||||
|
format!("discriminator {}='{}'", d, val)
|
||||||
|
} else {
|
||||||
|
format!("structural JSON base primitive '{}'", val)
|
||||||
|
};
|
||||||
|
result.errors.push(ValidationError {
|
||||||
|
code: if self.schema.family.is_some() {
|
||||||
|
"NO_FAMILY_MATCH".to_string()
|
||||||
|
} else {
|
||||||
|
"NO_ONEOF_MATCH".to_string()
|
||||||
|
},
|
||||||
|
message: format!(
|
||||||
|
"Payload matched no candidate boundaries based on its {}",
|
||||||
|
disc_msg
|
||||||
|
),
|
||||||
|
path: self.path.to_string(),
|
||||||
|
});
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(d) = self.schema.compiled_discriminator.get() {
|
||||||
result.errors.push(ValidationError {
|
result.errors.push(ValidationError {
|
||||||
code: "MISSING_TYPE".to_string(),
|
code: "MISSING_TYPE".to_string(),
|
||||||
message: format!("Missing '{}' discriminator. Unable to resolve polymorphic boundaries", disc),
|
message: format!(
|
||||||
|
"Missing explicit '{}' discriminator. Unable to resolve polymorphic boundaries",
|
||||||
|
d
|
||||||
|
),
|
||||||
path: self.path.to_string(),
|
path: self.path.to_string(),
|
||||||
});
|
});
|
||||||
|
}
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,7 +205,9 @@ impl<'a> ValidationContext<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(crate::database::object::SchemaTypeOrArray::Multiple(arr)) => {
|
Some(crate::database::object::SchemaTypeOrArray::Multiple(arr)) => {
|
||||||
if arr.contains(&payload_primitive.to_string()) || (payload_primitive == "integer" && arr.contains(&"number".to_string())) {
|
if arr.contains(&payload_primitive.to_string())
|
||||||
|
|| (payload_primitive == "integer" && arr.contains(&"number".to_string()))
|
||||||
|
{
|
||||||
// It natively matched a primitive in the array options, skip forcing custom proxy fallback
|
// It natively matched a primitive in the array options, skip forcing custom proxy fallback
|
||||||
} else {
|
} else {
|
||||||
for t in arr {
|
for t in arr {
|
||||||
|
|||||||
Reference in New Issue
Block a user