added limit 1 to arrays treated as a single value in schemas

This commit is contained in:
2026-07-16 13:43:08 -04:00
parent 1fedf5253c
commit c4bf6bde58
47 changed files with 616 additions and 586 deletions

View File

@ -227,8 +227,8 @@
{ {
"code": "CONTAINS_VIOLATED", "code": "CONTAINS_VIOLATED",
"values": { "values": {
"limit": "1", "count": "0",
"count": "0" "limit": "1"
}, },
"details": { "details": {
"path": "", "path": "",
@ -268,8 +268,8 @@
{ {
"code": "CONTAINS_VIOLATED", "code": "CONTAINS_VIOLATED",
"values": { "values": {
"limit": "1", "count": "0",
"count": "0" "limit": "1"
}, },
"details": { "details": {
"path": "", "path": "",
@ -347,8 +347,8 @@
{ {
"code": "CONTAINS_VIOLATED", "code": "CONTAINS_VIOLATED",
"values": { "values": {
"limit": "1", "count": "0",
"count": "0" "limit": "1"
}, },
"details": { "details": {
"path": "", "path": "",
@ -373,8 +373,8 @@
{ {
"code": "MULTIPLE_OF_VIOLATED", "code": "MULTIPLE_OF_VIOLATED",
"values": { "values": {
"multiple_of": "2", "value": "3",
"value": "3" "multiple_of": "2"
}, },
"details": { "details": {
"path": "0", "path": "0",
@ -384,8 +384,8 @@
{ {
"code": "MULTIPLE_OF_VIOLATED", "code": "MULTIPLE_OF_VIOLATED",
"values": { "values": {
"multiple_of": "2", "value": "9",
"value": "9" "multiple_of": "2"
}, },
"details": { "details": {
"path": "2", "path": "2",
@ -432,8 +432,8 @@
{ {
"code": "MULTIPLE_OF_VIOLATED", "code": "MULTIPLE_OF_VIOLATED",
"values": { "values": {
"multiple_of": "2", "value": "1",
"value": "1" "multiple_of": "2"
}, },
"details": { "details": {
"path": "0", "path": "0",

View File

@ -62,8 +62,8 @@
"code": "EDGE_MISSING", "code": "EDGE_MISSING",
"values": { "values": {
"parent_type": "org", "parent_type": "org",
"property_name": "missing_users", "child_type": "user",
"child_type": "user" "property_name": "missing_users"
}, },
"details": { "details": {
"path": "full.org/missing_users", "path": "full.org/missing_users",
@ -151,8 +151,8 @@
{ {
"code": "EDGE_MISSING", "code": "EDGE_MISSING",
"values": { "values": {
"child_type": "child",
"parent_type": "parent", "parent_type": "parent",
"child_type": "child",
"property_name": "children" "property_name": "children"
}, },
"details": { "details": {
@ -470,8 +470,8 @@
{ {
"code": "DATABASE_TYPE_PARSE_FAILED", "code": "DATABASE_TYPE_PARSE_FAILED",
"values": { "values": {
"reason": "invalid type: sequence, expected a string", "type": "failure",
"type": "failure" "reason": "invalid type: sequence, expected a string"
}, },
"details": { "details": {
"context": "failure" "context": "failure"

View File

@ -227,8 +227,8 @@
{ {
"code": "DEPENDENCY_MISSING", "code": "DEPENDENCY_MISSING",
"values": { "values": {
"required_property": "bar", "property_name": "quux",
"property_name": "quux" "required_property": "bar"
}, },
"details": { "details": {
"path": "", "path": "",
@ -386,8 +386,8 @@
{ {
"code": "DEPENDENCY_MISSING", "code": "DEPENDENCY_MISSING",
"values": { "values": {
"required_property": "foo'bar", "property_name": "foo\"bar",
"property_name": "foo\"bar" "required_property": "foo'bar"
}, },
"details": { "details": {
"path": "", "path": "",
@ -829,8 +829,8 @@
{ {
"code": "MIN_PROPERTIES_VIOLATED", "code": "MIN_PROPERTIES_VIOLATED",
"values": { "values": {
"limit": "4", "count": "2",
"count": "2" "limit": "4"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -34,8 +34,8 @@
{ {
"code": "EXCLUSIVE_MAXIMUM_VIOLATED", "code": "EXCLUSIVE_MAXIMUM_VIOLATED",
"values": { "values": {
"limit": "3", "value": "3",
"value": "3" "limit": "3"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -34,8 +34,8 @@
{ {
"code": "EXCLUSIVE_MINIMUM_VIOLATED", "code": "EXCLUSIVE_MINIMUM_VIOLATED",
"values": { "values": {
"limit": "1.1", "value": "1.1",
"value": "1.1" "limit": "1.1"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -211,13 +211,6 @@
"gender": {}, "gender": {},
"gender.condition": { "gender.condition": {
"type": "condition", "type": "condition",
"compiledPropertyNames": [
"kind",
"$eq",
"$ne",
"$of",
"$nof"
],
"properties": { "properties": {
"$eq": { "$eq": {
"type": [ "type": [
@ -231,15 +224,6 @@
"null" "null"
] ]
}, },
"$nof": {
"type": [
"array",
"null"
],
"items": {
"type": "gender"
}
},
"$of": { "$of": {
"type": [ "type": [
"array", "array",
@ -248,80 +232,32 @@
"items": { "items": {
"type": "gender" "type": "gender"
} }
},
"$nof": {
"type": [
"array",
"null"
],
"items": {
"type": "gender"
}
} }
} },
"compiledPropertyNames": [
"kind",
"$eq",
"$ne",
"$of",
"$nof"
]
}, },
"person": {}, "person": {},
"person.filter": { "person.filter": {
"compiledPropertyNames": [ "type": "filter",
"first_name",
"age",
"billing_address",
"gender",
"birth_date",
"uuid_field",
"tags",
"ad_hoc",
"$and",
"$or"
],
"properties": { "properties": {
"$and": { "first_name": {
"items": {
"compiledPropertyNames": [
"first_name",
"age",
"billing_address",
"gender",
"birth_date",
"uuid_field",
"tags",
"ad_hoc",
"$and",
"$or"
],
"type": "person.filter"
},
"type": [ "type": [
"array", "string.condition",
"null"
]
},
"$or": {
"items": {
"compiledPropertyNames": [
"first_name",
"age",
"billing_address",
"gender",
"birth_date",
"uuid_field",
"tags",
"ad_hoc",
"$and",
"$or"
],
"type": "person.filter"
},
"type": [
"array",
"null"
]
},
"ad_hoc": {
"compiledPropertyNames": [
"foo"
],
"properties": {
"foo": {
"type": [
"string.condition",
"null"
]
}
},
"type": [
"filter",
"null" "null"
] ]
}, },
@ -337,6 +273,12 @@
"null" "null"
] ]
}, },
"gender": {
"type": [
"gender.condition",
"null"
]
},
"birth_date": { "birth_date": {
"type": [ "type": [
"date.condition", "date.condition",
@ -349,48 +291,48 @@
"null" "null"
] ]
}, },
"first_name": {
"type": [
"string.condition",
"null"
]
},
"gender": {
"type": [
"gender.condition",
"null"
]
},
"tags": { "tags": {
"type": [ "type": [
"string.condition", "string.condition",
"null" "null"
] ]
} },
}, "ad_hoc": {
"type": "filter" "type": [
}, "filter",
"address": {}, "null"
"address.filter": { ],
"type": "filter", "properties": {
"compiledPropertyNames": [ "foo": {
"city", "type": [
"$and", "string.condition",
"$or" "null"
], ]
"properties": { }
},
"compiledPropertyNames": [
"foo"
]
},
"$and": { "$and": {
"type": [ "type": [
"array", "array",
"null" "null"
], ],
"items": { "items": {
"type": "person.filter",
"compiledPropertyNames": [ "compiledPropertyNames": [
"city", "first_name",
"age",
"billing_address",
"gender",
"birth_date",
"uuid_field",
"tags",
"ad_hoc",
"$and", "$and",
"$or" "$or"
], ]
"type": "address.filter"
} }
}, },
"$or": { "$or": {
@ -399,21 +341,79 @@
"null" "null"
], ],
"items": { "items": {
"type": "person.filter",
"compiledPropertyNames": [ "compiledPropertyNames": [
"city", "first_name",
"age",
"billing_address",
"gender",
"birth_date",
"uuid_field",
"tags",
"ad_hoc",
"$and", "$and",
"$or" "$or"
], ]
"type": "address.filter"
} }
}, }
},
"compiledPropertyNames": [
"first_name",
"age",
"billing_address",
"gender",
"birth_date",
"uuid_field",
"tags",
"ad_hoc",
"$and",
"$or"
]
},
"address": {},
"address.filter": {
"type": "filter",
"properties": {
"city": { "city": {
"type": [ "type": [
"string.condition", "string.condition",
"null" "null"
] ]
},
"$and": {
"type": [
"array",
"null"
],
"items": {
"type": "address.filter",
"compiledPropertyNames": [
"city",
"$and",
"$or"
]
}
},
"$or": {
"type": [
"array",
"null"
],
"items": {
"type": "address.filter",
"compiledPropertyNames": [
"city",
"$and",
"$or"
]
}
} }
} },
"compiledPropertyNames": [
"city",
"$and",
"$or"
]
}, },
"condition": {}, "condition": {},
"filter": {}, "filter": {},
@ -424,52 +424,7 @@
"search": {}, "search": {},
"search.filter": { "search.filter": {
"type": "filter", "type": "filter",
"compiledPropertyNames": [
"kind",
"name",
"filter",
"$and",
"$or"
],
"properties": { "properties": {
"$and": {
"type": [
"array",
"null"
],
"items": {
"compiledPropertyNames": [
"kind",
"name",
"filter",
"$and",
"$or"
],
"type": "search.filter"
}
},
"$or": {
"type": [
"array",
"null"
],
"items": {
"compiledPropertyNames": [
"kind",
"name",
"filter",
"$and",
"$or"
],
"type": "search.filter"
}
},
"filter": {
"type": [
"$kind.filter",
"null"
]
},
"kind": { "kind": {
"type": [ "type": [
"string.condition", "string.condition",
@ -481,8 +436,53 @@
"string.condition", "string.condition",
"null" "null"
] ]
},
"filter": {
"type": [
"$kind.filter",
"null"
]
},
"$and": {
"type": [
"array",
"null"
],
"items": {
"type": "search.filter",
"compiledPropertyNames": [
"kind",
"name",
"filter",
"$and",
"$or"
]
}
},
"$or": {
"type": [
"array",
"null"
],
"items": {
"type": "search.filter",
"compiledPropertyNames": [
"kind",
"name",
"filter",
"$and",
"$or"
]
}
} }
} },
"compiledPropertyNames": [
"kind",
"name",
"filter",
"$and",
"$or"
]
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -106,8 +106,8 @@
{ {
"code": "CONTAINS_VIOLATED", "code": "CONTAINS_VIOLATED",
"values": { "values": {
"limit": "1", "count": "2",
"count": "2" "limit": "1"
}, },
"details": { "details": {
"path": "", "path": "",
@ -144,8 +144,8 @@
{ {
"code": "CONTAINS_VIOLATED", "code": "CONTAINS_VIOLATED",
"values": { "values": {
"limit": "1", "count": "2",
"count": "2" "limit": "1"
}, },
"details": { "details": {
"path": "", "path": "",
@ -284,8 +284,8 @@
{ {
"code": "CONTAINS_VIOLATED", "code": "CONTAINS_VIOLATED",
"values": { "values": {
"limit": "3", "count": "4",
"count": "4" "limit": "3"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -52,8 +52,8 @@
{ {
"code": "MAX_ITEMS_VIOLATED", "code": "MAX_ITEMS_VIOLATED",
"values": { "values": {
"limit": "2", "count": "3",
"count": "3" "limit": "2"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -43,8 +43,8 @@
{ {
"code": "MAX_LENGTH_VIOLATED", "code": "MAX_LENGTH_VIOLATED",
"values": { "values": {
"limit": "2", "count": "3",
"count": "3" "limit": "2"
}, },
"details": { "details": {
"path": "", "path": "",
@ -109,8 +109,8 @@
{ {
"code": "MAX_LENGTH_VIOLATED", "code": "MAX_LENGTH_VIOLATED",
"values": { "values": {
"limit": "2", "count": "3",
"count": "3" "limit": "2"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -139,8 +139,8 @@
{ {
"code": "MAX_PROPERTIES_VIOLATED", "code": "MAX_PROPERTIES_VIOLATED",
"values": { "values": {
"limit": "2", "count": "3",
"count": "3" "limit": "2"
}, },
"details": { "details": {
"path": "", "path": "",
@ -190,8 +190,8 @@
{ {
"code": "MAX_PROPERTIES_VIOLATED", "code": "MAX_PROPERTIES_VIOLATED",
"values": { "values": {
"limit": "0", "count": "1",
"count": "1" "limit": "0"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -118,8 +118,8 @@
{ {
"code": "MAXIMUM_VIOLATED", "code": "MAXIMUM_VIOLATED",
"values": { "values": {
"limit": "300", "value": "300.5",
"value": "300.5" "limit": "300"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -239,8 +239,8 @@
{ {
"code": "DEPENDENCY_MISSING", "code": "DEPENDENCY_MISSING",
"values": { "values": {
"required_property": "base_dep", "property_name": "trigger",
"property_name": "trigger" "required_property": "base_dep"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -169,8 +169,8 @@
{ {
"code": "CONTAINS_VIOLATED", "code": "CONTAINS_VIOLATED",
"values": { "values": {
"limit": "2", "count": "0",
"count": "0" "limit": "2"
}, },
"details": { "details": {
"path": "", "path": "",
@ -357,8 +357,8 @@
{ {
"code": "CONTAINS_VIOLATED", "code": "CONTAINS_VIOLATED",
"values": { "values": {
"limit": "2", "count": "0",
"count": "0" "limit": "2"
}, },
"details": { "details": {
"path": "", "path": "",
@ -463,8 +463,8 @@
{ {
"code": "CONTAINS_VIOLATED", "code": "CONTAINS_VIOLATED",
"values": { "values": {
"limit": "3", "count": "0",
"count": "0" "limit": "3"
}, },
"details": { "details": {
"path": "", "path": "",
@ -487,8 +487,8 @@
{ {
"code": "CONTAINS_VIOLATED", "code": "CONTAINS_VIOLATED",
"values": { "values": {
"limit": "3", "count": "1",
"count": "1" "limit": "3"
}, },
"details": { "details": {
"path": "", "path": "",
@ -513,8 +513,8 @@
{ {
"code": "CONTAINS_VIOLATED", "code": "CONTAINS_VIOLATED",
"values": { "values": {
"limit": "1", "count": "3",
"count": "3" "limit": "1"
}, },
"details": { "details": {
"path": "", "path": "",
@ -657,8 +657,8 @@
{ {
"code": "CONTAINS_VIOLATED", "code": "CONTAINS_VIOLATED",
"values": { "values": {
"limit": "1", "count": "2",
"count": "2" "limit": "1"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -108,8 +108,8 @@
{ {
"code": "MIN_ITEMS_VIOLATED", "code": "MIN_ITEMS_VIOLATED",
"values": { "values": {
"limit": "1", "count": "0",
"count": "0" "limit": "1"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -43,8 +43,8 @@
{ {
"code": "MIN_LENGTH_VIOLATED", "code": "MIN_LENGTH_VIOLATED",
"values": { "values": {
"limit": "2", "count": "1",
"count": "1" "limit": "2"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -43,8 +43,8 @@
{ {
"code": "MINIMUM_VIOLATED", "code": "MINIMUM_VIOLATED",
"values": { "values": {
"limit": "1.1", "value": "0.6",
"value": "0.6" "limit": "1.1"
}, },
"details": { "details": {
"path": "", "path": "",
@ -127,8 +127,8 @@
{ {
"code": "MINIMUM_VIOLATED", "code": "MINIMUM_VIOLATED",
"values": { "values": {
"limit": "-2", "value": "-2.0001",
"value": "-2.0001" "limit": "-2"
}, },
"details": { "details": {
"path": "", "path": "",
@ -149,8 +149,8 @@
{ {
"code": "MINIMUM_VIOLATED", "code": "MINIMUM_VIOLATED",
"values": { "values": {
"limit": "-2", "value": "-3",
"value": "-3" "limit": "-2"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -148,8 +148,8 @@
{ {
"code": "MULTIPLE_OF_VIOLATED", "code": "MULTIPLE_OF_VIOLATED",
"values": { "values": {
"multiple_of": "0.0001", "value": "0.00751",
"value": "0.00751" "multiple_of": "0.0001"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -156,8 +156,8 @@
{ {
"code": "MAXIMUM_VIOLATED", "code": "MAXIMUM_VIOLATED",
"values": { "values": {
"limit": "50", "value": "60",
"value": "60" "limit": "50"
}, },
"details": { "details": {
"path": "max", "path": "max",

View File

@ -200,8 +200,8 @@
{ {
"code": "MINIMUM_VIOLATED", "code": "MINIMUM_VIOLATED",
"values": { "values": {
"limit": "10", "value": "5",
"value": "5" "limit": "10"
}, },
"details": { "details": {
"path": "entities/entity-beta/value", "path": "entities/entity-beta/value",

View File

@ -34,8 +34,8 @@
{ {
"code": "PATTERN_VIOLATED", "code": "PATTERN_VIOLATED",
"values": { "values": {
"value": "abc", "pattern": "^a*$",
"pattern": "^a*$" "value": "abc"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -148,8 +148,8 @@
{ {
"code": "NO_FAMILY_MATCH", "code": "NO_FAMILY_MATCH",
"values": { "values": {
"value": "alien", "discriminator": "type",
"discriminator": "type" "value": "alien"
}, },
"details": { "details": {
"path": "", "path": "",
@ -284,8 +284,8 @@
{ {
"code": "NO_FAMILY_MATCH", "code": "NO_FAMILY_MATCH",
"values": { "values": {
"value": "bot", "discriminator": "type",
"discriminator": "type" "value": "bot"
}, },
"details": { "details": {
"path": "", "path": "",
@ -591,8 +591,8 @@
{ {
"code": "NO_ONEOF_MATCH", "code": "NO_ONEOF_MATCH",
"values": { "values": {
"value": "alien", "discriminator": "type",
"discriminator": "type" "value": "alien"
}, },
"details": { "details": {
"path": "", "path": "",
@ -931,8 +931,8 @@
{ {
"code": "NO_FAMILY_MATCH", "code": "NO_FAMILY_MATCH",
"values": { "values": {
"value": "unknown_panel", "discriminator": "kind",
"discriminator": "kind" "value": "unknown_panel"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -431,8 +431,8 @@
{ {
"code": "MAX_LENGTH_VIOLATED", "code": "MAX_LENGTH_VIOLATED",
"values": { "values": {
"limit": "3", "count": "6",
"count": "6" "limit": "3"
}, },
"details": { "details": {
"path": "", "path": "",

View File

@ -2670,7 +2670,8 @@
" WHERE", " WHERE",
" NOT entity_3.archived", " NOT entity_3.archived",
" AND attachment_4.kind = 'cover'", " AND attachment_4.kind = 'cover'",
" AND attachment_4.attachable_id = entity_1.id LIMIT 1", " AND attachment_4.attachable_id = entity_1.id",
" LIMIT 1",
" ),", " ),",
" 'cover_attachments', (", " 'cover_attachments', (",
" SELECT COALESCE(jsonb_agg(jsonb_build_object(", " SELECT COALESCE(jsonb_agg(jsonb_build_object(",

View File

@ -139,8 +139,8 @@
{ {
"code": "MAX_LENGTH_VIOLATED", "code": "MAX_LENGTH_VIOLATED",
"values": { "values": {
"limit": "5", "count": "26",
"count": "26" "limit": "5"
}, },
"details": { "details": {
"path": "email", "path": "email",

View File

@ -2,7 +2,7 @@ use crate::database::schema::Schema;
#[allow(unused_imports)] #[allow(unused_imports)]
use crate::drop::{Error, ErrorDetails}; use crate::drop::{Error, ErrorDetails};
#[allow(unused_imports)] #[allow(unused_imports)]
use std::collections::HashMap; use indexmap::IndexMap;
use std::sync::Arc; use std::sync::Arc;
impl Schema { impl Schema {
@ -19,7 +19,7 @@ impl Schema {
if !c.is_ascii_lowercase() && !c.is_ascii_digit() && c != '_' && c != '.' && c != '$' { if !c.is_ascii_lowercase() && !c.is_ascii_digit() && c != '_' && c != '.' && c != '$' {
errors.push(Error { errors.push(Error {
code: "INVALID_IDENTIFIER".to_string(), code: "INVALID_IDENTIFIER".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("character".to_string(), c.to_string()), ("character".to_string(), c.to_string()),
("field_name".to_string(), field_name.to_string()), ("field_name".to_string(), field_name.to_string()),
("identifier".to_string(), id.to_string()), ("identifier".to_string(), id.to_string()),

View File

@ -7,7 +7,6 @@ pub mod polymorphism;
use crate::database::schema::Schema; use crate::database::schema::Schema;
use crate::drop::{Error, ErrorDetails}; use crate::drop::{Error, ErrorDetails};
use indexmap::IndexMap; use indexmap::IndexMap;
use std::collections::HashMap;
impl Schema { impl Schema {
pub fn compile( pub fn compile(
@ -64,7 +63,7 @@ impl Schema {
if custom_type_count > 1 { if custom_type_count > 1 {
errors.push(Error { errors.push(Error {
code: "MULTIPLE_INHERITANCE_PROHIBITED".to_string(), code: "MULTIPLE_INHERITANCE_PROHIBITED".to_string(),
values: Some(HashMap::from([("types".to_string(), types.join(", "))])), values: Some(IndexMap::from([("types".to_string(), types.join(", "))])),
details: ErrorDetails { details: ErrorDetails {
path: Some(path.clone()), path: Some(path.clone()),
schema: Some(root_id.to_string()), schema: Some(root_id.to_string()),

View File

@ -1,6 +1,6 @@
use crate::drop::{Error, ErrorDetails}; use crate::drop::{Error, ErrorDetails};
use indexmap::IndexSet; use indexmap::IndexSet;
use std::collections::HashMap; use indexmap::IndexMap;
use crate::database::schema::Schema; use crate::database::schema::Schema;
impl Schema { impl Schema {
@ -144,7 +144,7 @@ impl Schema {
if options.contains_key(&val) { if options.contains_key(&val) {
errors.push(Error { errors.push(Error {
code: "POLYMORPHIC_COLLISION".to_string(), code: "POLYMORPHIC_COLLISION".to_string(),
values: Some(HashMap::from([("value".to_string(), val.to_string())])), values: Some(IndexMap::from([("value".to_string(), val.to_string())])),
details: ErrorDetails { details: ErrorDetails {
path: Some(path.to_string()), path: Some(path.to_string()),
schema: Some(root_id.to_string()), schema: Some(root_id.to_string()),

View File

@ -1,6 +1,7 @@
use crate::drop::{Error, ErrorDetails}; use crate::drop::{Error, ErrorDetails};
use serde_json::Value; use serde_json::Value;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use indexmap::IndexMap;
pub fn compose(val: &mut Value, errors: &mut Vec<Error>) { pub fn compose(val: &mut Value, errors: &mut Vec<Error>) {
let mut traits = HashMap::new(); let mut traits = HashMap::new();
@ -114,7 +115,7 @@ fn resolve_in_place(
if visited.contains(inc_name) { if visited.contains(inc_name) {
errors.push(Error { errors.push(Error {
code: "CIRCULAR_INCLUDE_DETECTED".to_string(), code: "CIRCULAR_INCLUDE_DETECTED".to_string(),
values: Some(HashMap::from([( values: Some(IndexMap::from([(
"include".to_string(), "include".to_string(),
inc_name.to_string(), inc_name.to_string(),
)])), )])),
@ -218,7 +219,7 @@ fn resolve_in_place(
} else { } else {
errors.push(Error { errors.push(Error {
code: "TRAIT_NOT_FOUND".to_string(), code: "TRAIT_NOT_FOUND".to_string(),
values: Some(HashMap::from([( values: Some(IndexMap::from([(
"include".to_string(), "include".to_string(),
inc_name.to_string(), inc_name.to_string(),
)])), )])),

View File

@ -28,7 +28,7 @@ use serde_json::Value;
use indexmap::IndexMap; use indexmap::IndexMap;
use std::sync::Arc; use std::sync::Arc;
use r#type::Type; use r#type::Type;
use std::collections::HashMap;
use crate::drop::{Drop, Error, ErrorDetails}; use crate::drop::{Drop, Error, ErrorDetails};
#[derive(serde::Serialize)] #[derive(serde::Serialize)]
@ -76,7 +76,7 @@ impl Database {
Err(e) => { Err(e) => {
errors.push(Error { errors.push(Error {
code: "DATABASE_ENUM_PARSE_FAILED".to_string(), code: "DATABASE_ENUM_PARSE_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("enum".to_string(), name.clone()), ("enum".to_string(), name.clone()),
("reason".to_string(), e.to_string()), ("reason".to_string(), e.to_string()),
])), ])),
@ -104,7 +104,7 @@ impl Database {
Err(e) => { Err(e) => {
errors.push(Error { errors.push(Error {
code: "DATABASE_TYPE_PARSE_FAILED".to_string(), code: "DATABASE_TYPE_PARSE_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("type".to_string(), name.clone()), ("type".to_string(), name.clone()),
("reason".to_string(), e.to_string()), ("reason".to_string(), e.to_string()),
])), ])),
@ -136,7 +136,7 @@ impl Database {
Err(e) => { Err(e) => {
errors.push(Error { errors.push(Error {
code: "DATABASE_RELATION_PARSE_FAILED".to_string(), code: "DATABASE_RELATION_PARSE_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("relation".to_string(), constraint.clone()), ("relation".to_string(), constraint.clone()),
("reason".to_string(), e.to_string()), ("reason".to_string(), e.to_string()),
])), ])),
@ -164,7 +164,7 @@ impl Database {
Err(e) => { Err(e) => {
errors.push(Error { errors.push(Error {
code: "DATABASE_PUNC_PARSE_FAILED".to_string(), code: "DATABASE_PUNC_PARSE_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("punc".to_string(), name.clone()), ("punc".to_string(), name.clone()),
("reason".to_string(), e.to_string()), ("reason".to_string(), e.to_string()),
])), ])),
@ -461,7 +461,7 @@ impl Database {
errors.push(Error { errors.push(Error {
code: "EDGE_MISSING".to_string(), code: "EDGE_MISSING".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("parent_type".to_string(), parent_type.to_string()), ("parent_type".to_string(), parent_type.to_string()),
("child_type".to_string(), child_type.to_string()), ("child_type".to_string(), child_type.to_string()),
("property_name".to_string(), prop_name.to_string()), ("property_name".to_string(), prop_name.to_string()),
@ -563,7 +563,7 @@ impl Database {
errors.push(Error { errors.push(Error {
code: "AMBIGUOUS_TYPE_RELATIONS".to_string(), code: "AMBIGUOUS_TYPE_RELATIONS".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("parent_type".to_string(), parent_type.to_string()), ("parent_type".to_string(), parent_type.to_string()),
("child_type".to_string(), child_type.to_string()), ("child_type".to_string(), child_type.to_string()),
("property_name".to_string(), prop_name.to_string()), ("property_name".to_string(), prop_name.to_string()),

View File

@ -57,13 +57,13 @@ impl Drop {
} }
} }
use std::collections::HashMap; use indexmap::IndexMap;
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Error { pub struct Error {
pub code: String, pub code: String,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub values: Option<HashMap<String, String>>, pub values: Option<IndexMap<String, String>>,
pub details: ErrorDetails, pub details: ErrorDetails,
} }

View File

@ -7,7 +7,7 @@ use crate::database::Database;
use crate::database::r#type::Type; use crate::database::r#type::Type;
use crate::drop::{Drop, Error, ErrorDetails}; use crate::drop::{Drop, Error, ErrorDetails};
use serde_json::Value; use serde_json::Value;
use std::collections::HashMap; use indexmap::IndexMap;
use std::sync::Arc; use std::sync::Arc;
pub struct Merger { pub struct Merger {
@ -31,7 +31,7 @@ impl Merger {
None => { None => {
return Drop::with_errors(vec![Error { return Drop::with_errors(vec![Error {
code: "SCHEMA_NOT_FOUND".to_string(), code: "SCHEMA_NOT_FOUND".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("schema".to_string(), schema_id.to_string()), ("schema".to_string(), schema_id.to_string()),
])), ])),
details: ErrorDetails { details: ErrorDetails {
@ -78,7 +78,7 @@ impl Merger {
return Drop::with_errors(vec![Error { return Drop::with_errors(vec![Error {
code: final_code, code: final_code,
values: Some(HashMap::from([ values: Some(IndexMap::from([
("error".to_string(), final_message), ("error".to_string(), final_message),
])), ])),
details: ErrorDetails { details: ErrorDetails {
@ -96,7 +96,7 @@ impl Merger {
if let Err(e) = self.db.execute(&notify_sql, None) { if let Err(e) = self.db.execute(&notify_sql, None) {
return Drop::with_errors(vec![Error { return Drop::with_errors(vec![Error {
code: "MERGE_FAILED".to_string(), code: "MERGE_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("error".to_string(), e.to_string()), ("error".to_string(), e.to_string()),
])), ])),
details: ErrorDetails { details: ErrorDetails {

View File

@ -240,7 +240,7 @@ impl<'a> Compiler<'a> {
}; };
// 3. Build WHERE clauses // 3. Build WHERE clauses
let where_clauses = self.compile_where_clause(r#type, &table_aliases, node)?; let where_clauses = self.compile_where_clause(r#type, &table_aliases, node.clone())?;
let selection = if is_array { let selection = if is_array {
format!("COALESCE(jsonb_agg({}), '[]'::jsonb)", jsonb_obj_sql) format!("COALESCE(jsonb_agg({}), '[]'::jsonb)", jsonb_obj_sql)
@ -248,11 +248,38 @@ impl<'a> Compiler<'a> {
jsonb_obj_sql jsonb_obj_sql
}; };
let mut limit_clause = "";
if !is_array {
let is_reverse = if let Some(prop_ref) = &node.property_name {
let prop = prop_ref.as_str();
if let Some(parent_schema) = &node.parent_schema {
if let Some(compiled_edges) = parent_schema.obj.compiled_edges.get() {
if let Some(edge) = compiled_edges.get(prop) {
!edge.forward
} else {
false
}
} else {
false
}
} else {
false
}
} else {
false
};
if is_reverse {
limit_clause = " LIMIT 1";
}
}
let full_sql = format!( let full_sql = format!(
"(SELECT {} FROM {} WHERE {})", "(SELECT {} FROM {} WHERE {}{})",
selection, selection,
from_clauses.join(" "), from_clauses.join(" "),
where_clauses.join(" AND ") where_clauses.join(" AND "),
limit_clause
); );
Ok(( Ok((

View File

@ -1,6 +1,6 @@
use crate::database::Database; use crate::database::Database;
use crate::drop::{Drop, Error, ErrorDetails}; use crate::drop::{Drop, Error, ErrorDetails};
use std::collections::HashMap; use indexmap::IndexMap;
use std::sync::Arc; use std::sync::Arc;
pub mod compiler; pub mod compiler;
@ -33,7 +33,7 @@ impl Queryer {
Err(msg) => { Err(msg) => {
return Drop::with_errors(vec![Error { return Drop::with_errors(vec![Error {
code: "FILTER_PARSE_FAILED".to_string(), code: "FILTER_PARSE_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("error".to_string(), msg.clone()), ("error".to_string(), msg.clone()),
])), ])),
details: ErrorDetails { details: ErrorDetails {
@ -140,7 +140,7 @@ impl Queryer {
} }
Err(e) => Err(Drop::with_errors(vec![Error { Err(e) => Err(Drop::with_errors(vec![Error {
code: "QUERY_COMPILATION_FAILED".to_string(), code: "QUERY_COMPILATION_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("error".to_string(), e.clone()), ("error".to_string(), e.clone()),
])), ])),
details: ErrorDetails { details: ErrorDetails {
@ -169,7 +169,7 @@ impl Queryer {
} }
Ok(other) => Drop::with_errors(vec![Error { Ok(other) => Drop::with_errors(vec![Error {
code: "QUERY_FAILED".to_string(), code: "QUERY_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("error".to_string(), format!("Expected array from generic query, got: {:?}", other)), ("error".to_string(), format!("Expected array from generic query, got: {:?}", other)),
])), ])),
details: ErrorDetails { details: ErrorDetails {
@ -181,7 +181,7 @@ impl Queryer {
}]), }]),
Err(e) => Drop::with_errors(vec![Error { Err(e) => Drop::with_errors(vec![Error {
code: "QUERY_FAILED".to_string(), code: "QUERY_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("error".to_string(), e.to_string()), ("error".to_string(), e.to_string()),
])), ])),
details: ErrorDetails { details: ErrorDetails {

View File

@ -180,6 +180,9 @@ impl SqlFormatter {
fn format_query(&mut self, query: &Query) { fn format_query(&mut self, query: &Query) {
self.format_set_expr(&query.body); self.format_set_expr(&query.body);
if let Some(limit_clause) = &query.limit_clause {
self.push_line(&format!("{}", limit_clause.to_string().trim()));
}
} }
fn format_set_expr(&mut self, set_expr: &SetExpr) { fn format_set_expr(&mut self, set_expr: &SetExpr) {

View File

@ -1,9 +1,9 @@
use std::collections::HashMap; use indexmap::IndexMap;
#[derive(Debug, Clone, serde::Serialize)] #[derive(Debug, Clone, serde::Serialize)]
pub struct ValidationError { pub struct ValidationError {
pub code: String, pub code: String,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub values: Option<HashMap<String, String>>, pub values: Option<IndexMap<String, String>>,
pub path: String, pub path: String,
} }

View File

@ -1,4 +1,5 @@
use std::collections::{HashMap, HashSet}; use std::collections::HashSet;
use indexmap::IndexMap;
pub mod context; pub mod context;
pub mod error; pub mod error;
@ -92,7 +93,7 @@ impl Validator {
} else { } else {
Drop::with_errors(vec![Error { Drop::with_errors(vec![Error {
code: "SCHEMA_NOT_FOUND".to_string(), code: "SCHEMA_NOT_FOUND".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("schema".to_string(), schema_id.to_string()), ("schema".to_string(), schema_id.to_string()),
])), ])),
details: ErrorDetails { details: ErrorDetails {

View File

@ -1,4 +1,5 @@
use std::collections::{HashMap, HashSet}; use std::collections::HashSet;
use indexmap::IndexMap;
use serde_json::Value; use serde_json::Value;
@ -18,7 +19,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "MIN_ITEMS_VIOLATED".to_string(), code: "MIN_ITEMS_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("count".to_string(), arr.len().to_string()), ("count".to_string(), arr.len().to_string()),
("limit".to_string(), min.to_string()), ("limit".to_string(), min.to_string()),
])), ])),
@ -30,7 +31,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "MAX_ITEMS_VIOLATED".to_string(), code: "MAX_ITEMS_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("count".to_string(), arr.len().to_string()), ("count".to_string(), arr.len().to_string()),
("limit".to_string(), max.to_string()), ("limit".to_string(), max.to_string()),
])), ])),
@ -77,7 +78,7 @@ impl<'a> ValidationContext<'a> {
if _match_count < min { if _match_count < min {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "CONTAINS_VIOLATED".to_string(), code: "CONTAINS_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("count".to_string(), _match_count.to_string()), ("count".to_string(), _match_count.to_string()),
("limit".to_string(), min.to_string()), ("limit".to_string(), min.to_string()),
])), ])),
@ -89,7 +90,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "CONTAINS_VIOLATED".to_string(), code: "CONTAINS_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("count".to_string(), _match_count.to_string()), ("count".to_string(), _match_count.to_string()),
("limit".to_string(), max.to_string()), ("limit".to_string(), max.to_string()),
])), ])),

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use indexmap::IndexMap;
use crate::validator::Validator; use crate::validator::Validator;
use crate::validator::context::ValidationContext; use crate::validator::context::ValidationContext;
@ -19,7 +19,7 @@ impl<'a> ValidationContext<'a> {
if !Validator::check_type(t, current) { if !Validator::check_type(t, current) {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "INVALID_TYPE".to_string(), code: "INVALID_TYPE".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("expected".to_string(), t.to_string()), ("expected".to_string(), t.to_string()),
])), ])),
path: self.path.to_string(), path: self.path.to_string(),
@ -37,7 +37,7 @@ impl<'a> ValidationContext<'a> {
if !valid { if !valid {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "INVALID_TYPE".to_string(), code: "INVALID_TYPE".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("expected".to_string(), format!("{:?}", types)), ("expected".to_string(), format!("{:?}", types)),
])), ])),
path: self.path.to_string(), path: self.path.to_string(),
@ -51,7 +51,7 @@ impl<'a> ValidationContext<'a> {
if !equals(current, const_val) { if !equals(current, const_val) {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "CONST_VIOLATED".to_string(), code: "CONST_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("expected".to_string(), format!("{:?}", const_val)), ("expected".to_string(), format!("{:?}", const_val)),
])), ])),
path: self.path.to_string(), path: self.path.to_string(),
@ -74,7 +74,7 @@ impl<'a> ValidationContext<'a> {
if !found { if !found {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "ENUM_MISMATCH".to_string(), code: "ENUM_MISMATCH".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("expected".to_string(), format!("{:?}", enum_vals)), ("expected".to_string(), format!("{:?}", enum_vals)),
])), ])),
path: self.path.to_string(), path: self.path.to_string(),

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use indexmap::IndexMap;
use crate::database::object::{is_primitive_type, SchemaTypeOrArray}; use crate::database::object::{is_primitive_type, SchemaTypeOrArray};
use crate::database::schema::Schema; use crate::database::schema::Schema;
@ -75,7 +75,7 @@ impl<'a> ValidationContext<'a> {
if !result.evaluated_keys.contains(key) && !self.overrides.contains(key) { if !result.evaluated_keys.contains(key) && !self.overrides.contains(key) {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "STRICT_PROPERTY_VIOLATION".to_string(), code: "STRICT_PROPERTY_VIOLATION".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("property_name".to_string(), key.to_string()), ("property_name".to_string(), key.to_string()),
])), ])),
path: self.join_path(key), path: self.join_path(key),

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use indexmap::IndexMap;
use crate::validator::context::ValidationContext; use crate::validator::context::ValidationContext;
use crate::validator::error::ValidationError; use crate::validator::error::ValidationError;
@ -21,7 +21,7 @@ impl<'a> ValidationContext<'a> {
if should && let Err(e) = f(current) { if should && let Err(e) = f(current) {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "FORMAT_MISMATCH".to_string(), code: "FORMAT_MISMATCH".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("format".to_string(), self.schema.format.clone().unwrap_or_default()), ("format".to_string(), self.schema.format.clone().unwrap_or_default()),
("error".to_string(), e.to_string()), ("error".to_string(), e.to_string()),
])), ])),
@ -35,7 +35,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "FORMAT_MISMATCH".to_string(), code: "FORMAT_MISMATCH".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("format".to_string(), self.schema.format.clone().unwrap_or_default()), ("format".to_string(), self.schema.format.clone().unwrap_or_default()),
])), ])),
path: self.path.to_string(), path: self.path.to_string(),

View File

@ -1,7 +1,7 @@
use crate::validator::context::ValidationContext; use crate::validator::context::ValidationContext;
use crate::validator::error::ValidationError; use crate::validator::error::ValidationError;
use crate::validator::result::ValidationResult; use crate::validator::result::ValidationResult;
use std::collections::HashMap; use indexmap::IndexMap;
pub mod array; pub mod array;
pub mod cases; pub mod cases;
@ -64,7 +64,7 @@ impl<'a> ValidationContext<'a> {
if self.depth > 100 { if self.depth > 100 {
Err(ValidationError { Err(ValidationError {
code: "RECURSION_LIMIT_EXCEEDED".to_string(), code: "RECURSION_LIMIT_EXCEEDED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("limit".to_string(), 100.to_string()), ("limit".to_string(), 100.to_string()),
])), ])),
path: self.path.to_string(), path: self.path.to_string(),

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use indexmap::IndexMap;
use crate::validator::context::ValidationContext; use crate::validator::context::ValidationContext;
use crate::validator::error::ValidationError; use crate::validator::error::ValidationError;
@ -16,7 +16,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "MINIMUM_VIOLATED".to_string(), code: "MINIMUM_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("value".to_string(), num.to_string()), ("value".to_string(), num.to_string()),
("limit".to_string(), min.to_string()), ("limit".to_string(), min.to_string()),
])), ])),
@ -28,7 +28,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "MAXIMUM_VIOLATED".to_string(), code: "MAXIMUM_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("value".to_string(), num.to_string()), ("value".to_string(), num.to_string()),
("limit".to_string(), max.to_string()), ("limit".to_string(), max.to_string()),
])), ])),
@ -40,7 +40,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "EXCLUSIVE_MINIMUM_VIOLATED".to_string(), code: "EXCLUSIVE_MINIMUM_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("value".to_string(), num.to_string()), ("value".to_string(), num.to_string()),
("limit".to_string(), ex_min.to_string()), ("limit".to_string(), ex_min.to_string()),
])), ])),
@ -52,7 +52,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "EXCLUSIVE_MAXIMUM_VIOLATED".to_string(), code: "EXCLUSIVE_MAXIMUM_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("value".to_string(), num.to_string()), ("value".to_string(), num.to_string()),
("limit".to_string(), ex_max.to_string()), ("limit".to_string(), ex_max.to_string()),
])), ])),
@ -64,7 +64,7 @@ impl<'a> ValidationContext<'a> {
if (val - val.round()).abs() > f64::EPSILON { if (val - val.round()).abs() > f64::EPSILON {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "MULTIPLE_OF_VIOLATED".to_string(), code: "MULTIPLE_OF_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("value".to_string(), num.to_string()), ("value".to_string(), num.to_string()),
("multiple_of".to_string(), multiple_of.to_string()), ("multiple_of".to_string(), multiple_of.to_string()),
])), ])),

View File

@ -1,4 +1,5 @@
use std::collections::{HashMap, HashSet}; use std::collections::HashSet;
use indexmap::IndexMap;
use serde_json::Value; use serde_json::Value;
@ -38,7 +39,7 @@ impl<'a> ValidationContext<'a> {
} else { } else {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "CONST_VIOLATED".to_string(), // Aligning with original const override errors natively code: "CONST_VIOLATED".to_string(), // Aligning with original const override errors natively
values: Some(HashMap::from([ values: Some(IndexMap::from([
("value".to_string(), type_str.to_string()), ("value".to_string(), type_str.to_string()),
])), ])),
path: self.join_path("type"), path: self.join_path("type"),
@ -49,7 +50,7 @@ impl<'a> ValidationContext<'a> {
// Because it's a global entity target, the payload must structurally provide a discriminator natively // Because it's a global entity target, the payload must structurally provide a discriminator natively
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "MISSING_TYPE".to_string(), code: "MISSING_TYPE".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("expected".to_string(), expected_type.to_string()), ("expected".to_string(), expected_type.to_string()),
])), ])),
path: self.path.clone(), // Empty boundary path: self.path.clone(), // Empty boundary
@ -104,7 +105,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "MIN_PROPERTIES_VIOLATED".to_string(), code: "MIN_PROPERTIES_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("count".to_string(), obj.len().to_string()), ("count".to_string(), obj.len().to_string()),
("limit".to_string(), min.to_string()), ("limit".to_string(), min.to_string()),
])), ])),
@ -117,7 +118,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "MAX_PROPERTIES_VIOLATED".to_string(), code: "MAX_PROPERTIES_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("count".to_string(), obj.len().to_string()), ("count".to_string(), obj.len().to_string()),
("limit".to_string(), max.to_string()), ("limit".to_string(), max.to_string()),
])), ])),
@ -131,7 +132,7 @@ impl<'a> ValidationContext<'a> {
if field == "type" { if field == "type" {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "MISSING_TYPE".to_string(), code: "MISSING_TYPE".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("field_name".to_string(), "type".to_string()), ("field_name".to_string(), "type".to_string()),
])), ])),
path: self.join_path(field), path: self.join_path(field),
@ -139,7 +140,7 @@ impl<'a> ValidationContext<'a> {
} else { } else {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "REQUIRED_FIELD_MISSING".to_string(), code: "REQUIRED_FIELD_MISSING".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("field_name".to_string(), field.to_string()), ("field_name".to_string(), field.to_string()),
])), ])),
path: self.join_path(field), path: self.join_path(field),
@ -158,7 +159,7 @@ impl<'a> ValidationContext<'a> {
if !obj.contains_key(req_prop) { if !obj.contains_key(req_prop) {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "DEPENDENCY_MISSING".to_string(), code: "DEPENDENCY_MISSING".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("property_name".to_string(), prop.to_string()), ("property_name".to_string(), prop.to_string()),
("required_property".to_string(), req_prop.to_string()), ("required_property".to_string(), req_prop.to_string()),
])), ])),

View File

@ -1,5 +1,3 @@
use std::collections::HashMap;
use crate::validator::context::ValidationContext; use crate::validator::context::ValidationContext;
use crate::validator::error::ValidationError; use crate::validator::error::ValidationError;
use crate::validator::result::ValidationResult; use crate::validator::result::ValidationResult;
@ -55,10 +53,10 @@ impl<'a> ValidationContext<'a> {
return self.execute_polymorph(options, result); return self.execute_polymorph(options, result);
} else { } else {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "UNCOMPILED_ONEOF".to_string(), code: "UNCOMPILED_ONEOF".to_string(),
values: None, values: None,
path: self.path.to_string(), path: self.path.to_string(),
}); });
return Ok(false); return Ok(false);
} }
} }
@ -110,9 +108,10 @@ 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(),
values: Some(HashMap::from([ values: Some(IndexMap::from([(
("target_id".to_string(), target_id.to_string()), "target_id".to_string(),
])), target_id.to_string(),
)])),
path: self.path.to_string(), path: self.path.to_string(),
}); });
return Ok(false); return Ok(false);
@ -132,9 +131,7 @@ 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(),
values: Some(HashMap::from([ values: Some(IndexMap::from([("index".to_string(), idx.to_string())])),
("index".to_string(), idx.to_string()),
])),
path: self.path.to_string(), path: self.path.to_string(),
}); });
return Ok(false); return Ok(false);
@ -144,14 +141,12 @@ impl<'a> ValidationContext<'a> {
} }
} else { } else {
let values = if let Some(d) = self.schema.compiled_discriminator.get() { let values = if let Some(d) = self.schema.compiled_discriminator.get() {
Some(HashMap::from([ Some(IndexMap::from([
("discriminator".to_string(), d.to_string()), ("discriminator".to_string(), d.to_string()),
("value".to_string(), val.to_string()), ("value".to_string(), val.to_string()),
])) ]))
} else { } else {
Some(HashMap::from([ Some(IndexMap::from([("primitive".to_string(), val.to_string())]))
("primitive".to_string(), val.to_string()),
]))
}; };
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: if self.schema.family.is_some() { code: if self.schema.family.is_some() {
@ -168,9 +163,10 @@ impl<'a> ValidationContext<'a> {
if let Some(d) = self.schema.compiled_discriminator.get() { 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(),
values: Some(HashMap::from([ values: Some(IndexMap::from([(
("discriminator".to_string(), d.to_string()), "discriminator".to_string(),
])), d.to_string(),
)])),
path: self.path.to_string(), path: self.path.to_string(),
}); });
} }

View File

@ -1,4 +1,4 @@
use std::collections::HashMap; use indexmap::IndexMap;
use crate::validator::context::ValidationContext; use crate::validator::context::ValidationContext;
use crate::validator::error::ValidationError; use crate::validator::error::ValidationError;
@ -17,7 +17,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "MIN_LENGTH_VIOLATED".to_string(), code: "MIN_LENGTH_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("count".to_string(), s.chars().count().to_string()), ("count".to_string(), s.chars().count().to_string()),
("limit".to_string(), min.to_string()), ("limit".to_string(), min.to_string()),
])), ])),
@ -29,7 +29,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "MAX_LENGTH_VIOLATED".to_string(), code: "MAX_LENGTH_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("count".to_string(), s.chars().count().to_string()), ("count".to_string(), s.chars().count().to_string()),
("limit".to_string(), max.to_string()), ("limit".to_string(), max.to_string()),
])), ])),
@ -40,7 +40,7 @@ impl<'a> ValidationContext<'a> {
if !compiled_re.0.is_match(s) { if !compiled_re.0.is_match(s) {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "PATTERN_VIOLATED".to_string(), code: "PATTERN_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("pattern".to_string(), self.schema.pattern.clone().unwrap_or_default()), ("pattern".to_string(), self.schema.pattern.clone().unwrap_or_default()),
("value".to_string(), s.to_string()), ("value".to_string(), s.to_string()),
])), ])),
@ -53,7 +53,7 @@ impl<'a> ValidationContext<'a> {
{ {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "PATTERN_VIOLATED".to_string(), code: "PATTERN_VIOLATED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("pattern".to_string(), pattern.to_string()), ("pattern".to_string(), pattern.to_string()),
("value".to_string(), s.to_string()), ("value".to_string(), s.to_string()),
])), ])),

View File

@ -2,7 +2,7 @@ use crate::database::object::{is_primitive_type, SchemaTypeOrArray};
use crate::validator::context::ValidationContext; use crate::validator::context::ValidationContext;
use crate::validator::error::ValidationError; use crate::validator::error::ValidationError;
use crate::validator::result::ValidationResult; use crate::validator::result::ValidationResult;
use std::collections::HashMap; use indexmap::IndexMap;
impl<'a> ValidationContext<'a> { impl<'a> ValidationContext<'a> {
pub(crate) fn validate_type( pub(crate) fn validate_type(
@ -76,7 +76,7 @@ impl<'a> ValidationContext<'a> {
if !resolved { if !resolved {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "DYNAMIC_TYPE_RESOLUTION_FAILED".to_string(), code: "DYNAMIC_TYPE_RESOLUTION_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("pointer".to_string(), t.clone()), ("pointer".to_string(), t.clone()),
("discriminator".to_string(), var_name.to_string()), ("discriminator".to_string(), var_name.to_string()),
])), ])),
@ -109,7 +109,7 @@ impl<'a> ValidationContext<'a> {
if t.starts_with('$') { if t.starts_with('$') {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "DYNAMIC_TYPE_RESOLUTION_FAILED".to_string(), code: "DYNAMIC_TYPE_RESOLUTION_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("pointer".to_string(), target_id.to_string()), ("pointer".to_string(), target_id.to_string()),
])), ])),
path: self.path.to_string(), path: self.path.to_string(),
@ -117,7 +117,7 @@ impl<'a> ValidationContext<'a> {
} else if self.schema.is_proxy() { } else if self.schema.is_proxy() {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "PROXY_TYPE_RESOLUTION_FAILED".to_string(), code: "PROXY_TYPE_RESOLUTION_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("pointer".to_string(), target_id.to_string()), ("pointer".to_string(), target_id.to_string()),
])), ])),
path: self.path.to_string(), path: self.path.to_string(),
@ -125,7 +125,7 @@ impl<'a> ValidationContext<'a> {
} else { } else {
result.errors.push(ValidationError { result.errors.push(ValidationError {
code: "INHERITANCE_RESOLUTION_FAILED".to_string(), code: "INHERITANCE_RESOLUTION_FAILED".to_string(),
values: Some(HashMap::from([ values: Some(IndexMap::from([
("pointer".to_string(), target_id.to_string()), ("pointer".to_string(), target_id.to_string()),
])), ])),
path: self.path.to_string(), path: self.path.to_string(),