This is an automated email from the ASF dual-hosted git repository.
mgrigorov pushed a commit to branch branch-1.11
in repository https://gitbox.apache.org/repos/asf/avro.git
The following commit(s) were added to refs/heads/branch-1.11 by this push:
new 93941e3 AVRO-3433: Rust: The canonical form should preserve schema
references (#1580)
93941e3 is described below
commit 93941e323c467b6381c4157c9ff9ebb02d64a5f8
Author: Martin Grigorov <[email protected]>
AuthorDate: Mon Mar 7 14:47:50 2022 +0200
AVRO-3433: Rust: The canonical form should preserve schema references
(#1580)
* AVRO-3433: Rust: The canonical form should preserve schema references
Do not resolve Schema::Ref when printing as JSON.
The Java SDK complains that a type is redefined if it is not a Ref the
second time
Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
* AVRO-3433: Use Name as a key for parsed/resolving/input schemata
This is needed to have the fullname (namespace + '.' + name) for lookups
Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
* AVRO-3433: Name::new("...") should parse the optional namespace
This is a breaking change but a bug fix to properly implement the Avro
specification
Signed-off-by: Martin Tzvetanov Grigorov <[email protected]>
(cherry picked from commit 44b8cd23756b752bf9d0976574453c712dcd44d9)
---
lang/rust/avro/src/schema.rs | 266 ++++++++++++++++++++++++++++++++---------
lang/rust/avro/tests/schema.rs | 158 ++++--------------------
2 files changed, 236 insertions(+), 188 deletions(-)
diff --git a/lang/rust/avro/src/schema.rs b/lang/rust/avro/src/schema.rs
index 28b34f8..4474ffa 100644
--- a/lang/rust/avro/src/schema.rs
+++ b/lang/rust/avro/src/schema.rs
@@ -30,6 +30,7 @@ use std::{
collections::{HashMap, HashSet},
convert::TryInto,
fmt,
+ hash::{Hash, Hasher},
str::FromStr,
};
use strum_macros::{EnumDiscriminants, EnumString};
@@ -175,7 +176,7 @@ impl SchemaKind {
pub fn is_named(self) -> bool {
matches!(
self,
- SchemaKind::Record | SchemaKind::Enum | SchemaKind::Fixed
+ SchemaKind::Record | SchemaKind::Enum | SchemaKind::Fixed |
SchemaKind::Ref
)
}
}
@@ -220,7 +221,7 @@ impl<'a> From<&'a types::Value> for SchemaKind {
///
/// More information about schema names can be found in the
/// [Avro specification](https://avro.apache.org/docs/current/spec.html#names)
-#[derive(Clone, Debug, PartialEq, Deserialize)]
+#[derive(Clone, Debug, Deserialize)]
pub struct Name {
pub name: String,
pub namespace: Option<String>,
@@ -232,26 +233,40 @@ pub type Documentation = Option<String>;
impl Name {
/// Create a new `Name`.
- /// No `namespace` nor `aliases` will be defined.
+ /// Parses the optional `namespace` from the `name` string.
+ /// `aliases` will not be defined.
pub fn new(name: &str) -> Name {
+ let (name, namespace) = Name::get_name_and_namespace(name);
Name {
- name: name.to_owned(),
- namespace: None,
+ name,
+ namespace,
aliases: None,
}
}
+ fn get_name_and_namespace(name: &str) -> (String, Option<String>) {
+ if let Some(idx) = name.rfind('.') {
+ let namespace_from_name = name[..idx].to_owned();
+ let name_from_name = name[idx + 1..].to_owned();
+ (name_from_name, Some(namespace_from_name))
+ } else {
+ (name.to_owned(), None)
+ }
+ }
+
/// Parse a `serde_json::Value` into a `Name`.
fn parse(complex: &Map<String, Value>) -> AvroResult<Self> {
- let name = complex.name().ok_or(Error::GetNameField)?;
+ let (name, namespace_from_name) = complex
+ .name()
+ .map(|name| Name::get_name_and_namespace(name.as_str()))
+ .ok_or(Error::GetNameField)?;
+ // FIXME Reading name from the type is wrong ! The name there is just
a metadata (AVRO-3430)
let type_name = match complex.get("type") {
Some(Value::Object(complex_type)) => complex_type.name().or(None),
_ => None,
};
- let namespace = complex.string("namespace");
-
let aliases: Option<Vec<String>> = complex
.get("aliases")
.and_then(|aliases| aliases.as_array())
@@ -265,7 +280,7 @@ impl Name {
Ok(Name {
name: type_name.unwrap_or(name),
- namespace,
+ namespace: namespace_from_name.or_else(||
complex.string("namespace")),
aliases,
})
}
@@ -292,6 +307,26 @@ impl Name {
}
}
+impl From<&str> for Name {
+ fn from(name: &str) -> Self {
+ Name::new(name)
+ }
+}
+
+impl Hash for Name {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.fullname(None).hash(state);
+ }
+}
+
+impl Eq for Name {}
+
+impl PartialEq for Name {
+ fn eq(&self, other: &Name) -> bool {
+ self.fullname(None).eq(&other.fullname(None))
+ }
+}
+
/// Represents a `field` in a `record` Avro schema.
#[derive(Clone, Debug, PartialEq)]
pub struct RecordField {
@@ -435,15 +470,15 @@ fn parse_json_integer_for_decimal(value:
&serde_json::Number) -> Result<DecimalM
#[derive(Default)]
struct Parser {
- input_schemas: HashMap<String, Value>,
+ input_schemas: HashMap<Name, Value>,
// A map of name -> Schema::Ref
// Used to resolve cyclic references, i.e. when a
// field's type is a reference to its record's type
- resolving_schemas: HashMap<String, Schema>,
- input_order: Vec<String>,
+ resolving_schemas: HashMap<Name, Schema>,
+ input_order: Vec<Name>,
// A map of name -> fully parsed Schema
// Used to avoid parsing the same schema twice
- parsed_schemas: HashMap<String, Schema>,
+ parsed_schemas: HashMap<Name, Schema>,
}
impl Schema {
@@ -485,17 +520,17 @@ impl Schema {
///
/// If two of the input schemas have the same fullname, an Error will be
returned.
pub fn parse_list(input: &[&str]) -> Result<Vec<Schema>, Error> {
- let mut input_schemas: HashMap<String, Value> =
HashMap::with_capacity(input.len());
- let mut input_order: Vec<String> = Vec::with_capacity(input.len());
+ let mut input_schemas: HashMap<Name, Value> =
HashMap::with_capacity(input.len());
+ let mut input_order: Vec<Name> = Vec::with_capacity(input.len());
for js in input {
let schema: Value =
serde_json::from_str(js).map_err(Error::ParseSchemaJson)?;
if let Value::Object(inner) = &schema {
- let fullname = Name::parse(inner)?.fullname(None);
- let previous_value = input_schemas.insert(fullname.clone(),
schema);
+ let name = Name::parse(inner)?;
+ let previous_value = input_schemas.insert(name.clone(),
schema);
if previous_value.is_some() {
- return Err(Error::NameCollision(fullname));
+ return Err(Error::NameCollision(name.fullname(None)));
}
- input_order.push(fullname);
+ input_order.push(name);
} else {
return Err(Error::GetNameField);
}
@@ -577,7 +612,7 @@ impl Parser {
"float" => Ok(Schema::Float),
"bytes" => Ok(Schema::Bytes),
"string" => Ok(Schema::String),
- _ => self.fetch_schema(name),
+ _ => self.fetch_schema_ref(name),
}
}
@@ -590,25 +625,35 @@ impl Parser {
///
/// This method allows schemas definitions that depend on other types to
/// parse their dependencies (or look them up if already parsed).
- fn fetch_schema(&mut self, name: &str) -> AvroResult<Schema> {
- if let Some(parsed) = self.parsed_schemas.get(name) {
- return Ok(parsed.clone());
+ fn fetch_schema_ref(&mut self, name: &str) -> AvroResult<Schema> {
+ fn get_schema_ref(parsed: &Schema) -> Schema {
+ match &parsed {
+ Schema::Record { ref name, .. }
+ | Schema::Enum { ref name, .. }
+ | Schema::Fixed { ref name, .. } => Schema::Ref { name:
name.clone() },
+ _ => parsed.clone(),
+ }
}
- if let Some(resolving_schema) = self.resolving_schemas.get(name) {
+
+ let name = Name::new(name);
+
+ if let Some(parsed) = self.parsed_schemas.get(&name) {
+ return Ok(get_schema_ref(parsed));
+ }
+ if let Some(resolving_schema) = self.resolving_schemas.get(&name) {
return Ok(resolving_schema.clone());
}
let value = self
.input_schemas
- .remove(name)
- .ok_or_else(|| Error::ParsePrimitive(name.into()))?;
+ .remove(&name)
+ .ok_or_else(|| Error::ParsePrimitive(name.fullname(None)))?;
let parsed = self.parse(&value)?;
- self.parsed_schemas.insert(
- get_schema_type_name(name.to_string(), value),
- parsed.clone(),
- );
- Ok(parsed)
+ self.parsed_schemas
+ .insert(get_schema_type_name(name, value), parsed.clone());
+
+ Ok(get_schema_ref(&parsed))
}
fn parse_precision_and_scale(
@@ -802,7 +847,7 @@ impl Parser {
fn register_resolving_schema(&mut self, name: &Name) {
let resolving_schema = Schema::Ref { name: name.clone() };
self.resolving_schemas
- .insert(name.fullname(None), resolving_schema.clone());
+ .insert(name.clone(), resolving_schema.clone());
let namespace = &name.namespace;
@@ -812,16 +857,16 @@ impl Parser {
Some(ref ns) => format!("{}.{}", ns, alias),
None => alias.clone(),
};
+ let alias_name = Name::new(alias_fullname.as_str());
self.resolving_schemas
- .insert(alias_fullname, resolving_schema.clone());
+ .insert(alias_name, resolving_schema.clone());
});
}
}
fn register_parsed_schema(&mut self, name: &Name, schema: &Schema) {
- self.parsed_schemas
- .insert(name.fullname(None), schema.clone());
- self.resolving_schemas.remove(name.fullname(None).as_str());
+ self.parsed_schemas.insert(name.clone(), schema.clone());
+ self.resolving_schemas.remove(name);
let namespace = &name.namespace;
@@ -831,9 +876,9 @@ impl Parser {
Some(ref ns) => format!("{}.{}", ns, alias),
None => alias.clone(),
};
- self.parsed_schemas
- .insert(alias_fullname.clone(), schema.clone());
- self.resolving_schemas.remove(alias_fullname.as_str());
+ let alias_name = Name::new(alias_fullname.as_str());
+ self.resolving_schemas.remove(&alias_name);
+ self.parsed_schemas.insert(alias_name, schema.clone());
});
}
}
@@ -841,10 +886,12 @@ impl Parser {
/// Returns already parsed schema or a schema that is currently being
resolved.
fn get_already_seen_schema(&self, complex: &Map<String, Value>) ->
Option<&Schema> {
match complex.get("type") {
- Some(Value::String(ref typ)) => self
- .resolving_schemas
- .get(typ)
- .or_else(|| self.parsed_schemas.get(typ)),
+ Some(Value::String(ref typ)) => {
+ let name = Name::new(typ.as_str());
+ self.resolving_schemas
+ .get(&name)
+ .or_else(|| self.parsed_schemas.get(&name))
+ }
_ => None,
}
}
@@ -1006,10 +1053,10 @@ impl Parser {
}
}
-fn get_schema_type_name(name: String, value: Value) -> String {
+fn get_schema_type_name(name: Name, value: Value) -> Name {
match value.get("type") {
Some(Value::Object(complex_type)) => match complex_type.name() {
- Some(name) => name,
+ Some(name) => Name::new(name.as_str()),
_ => name,
},
_ => name,
@@ -1022,7 +1069,7 @@ impl Serialize for Schema {
S: Serializer,
{
match *self {
- Schema::Ref { ref name } => serializer.serialize_str(&name.name),
+ Schema::Ref { ref name } =>
serializer.serialize_str(&name.fullname(None)),
Schema::Null => serializer.serialize_str("null"),
Schema::Boolean => serializer.serialize_str("boolean"),
Schema::Int => serializer.serialize_str("int"),
@@ -1393,9 +1440,6 @@ mod tests {
]
}"#;
- let schema_a = Schema::parse_str(schema_str_a).unwrap();
- let schema_b = Schema::parse_str(schema_str_b).unwrap();
-
let schema_c = Schema::parse_list(&[schema_str_a, schema_str_b,
schema_str_c])
.unwrap()
.last()
@@ -1409,7 +1453,17 @@ mod tests {
name: "field_one".to_string(),
doc: None,
default: None,
- schema: Schema::Union(UnionSchema::new(vec![schema_a,
schema_b]).unwrap()),
+ schema: Schema::Union(
+ UnionSchema::new(vec![
+ Schema::Ref {
+ name: Name::new("A"),
+ },
+ Schema::Ref {
+ name: Name::new("B"),
+ },
+ ])
+ .unwrap(),
+ ),
order: RecordFieldOrder::Ignore,
position: 0,
}],
@@ -1441,8 +1495,6 @@ mod tests {
]
}"#;
- let schema_a = Schema::parse_str(schema_str_a).unwrap();
-
let schema_option_a = Schema::parse_list(&[schema_str_a,
schema_str_option_a])
.unwrap()
.last()
@@ -1455,8 +1507,16 @@ mod tests {
fields: vec![RecordField {
name: "field_one".to_string(),
doc: None,
- default: Some(Value::Null),
- schema: Schema::Union(UnionSchema::new(vec![Schema::Null,
schema_a]).unwrap()),
+ default: Some(Value::String("null".to_string())),
+ schema: Schema::Union(
+ UnionSchema::new(vec![
+ Schema::Null,
+ Schema::Ref {
+ name: Name::new("A"),
+ },
+ ])
+ .unwrap(),
+ ),
order: RecordFieldOrder::Ignore,
position: 0,
}],
@@ -1636,7 +1696,7 @@ mod tests {
let schema = Schema::parse_str(schema).unwrap();
let schema_str = schema.canonical_form();
- let expected =
r#"{"name":"office.User","type":"record","fields":[{"name":"details","type":[{"name":"Employee","type":"record","fields":[{"name":"gender","type":{"name":"Gender","type":"enum","symbols":["male","female"]}}]},{"name":"Manager","type":"record","fields":[{"name":"gender","type":{"name":"Gender","type":"enum","symbols":["male","female"]}}]}]}]}"#;
+ let expected =
r#"{"name":"office.User","type":"record","fields":[{"name":"details","type":[{"name":"Employee","type":"record","fields":[{"name":"gender","type":{"name":"Gender","type":"enum","symbols":["male","female"]}}]},{"name":"Manager","type":"record","fields":[{"name":"gender","type":"Gender"}]}]}]}"#;
assert_eq!(schema_str, expected);
}
@@ -1684,7 +1744,7 @@ mod tests {
let schema = Schema::parse_str(schema).unwrap();
let schema_str = schema.canonical_form();
- let expected =
r#"{"name":"office.User","type":"record","fields":[{"name":"details","type":[{"name":"Employee","type":"record","fields":[{"name":"id","type":{"name":"EmployeeId","type":"fixed","size":16}}]},{"name":"Manager","type":"record","fields":[{"name":"id","type":{"name":"EmployeeId","type":"fixed","size":16}}]}]}]}"#;
+ let expected =
r#"{"name":"office.User","type":"record","fields":[{"name":"details","type":[{"name":"Employee","type":"record","fields":[{"name":"id","type":{"name":"EmployeeId","type":"fixed","size":16}}]},{"name":"Manager","type":"record","fields":[{"name":"id","type":"EmployeeId"}]}]}]}"#;
assert_eq!(schema_str, expected);
}
@@ -2180,4 +2240,98 @@ mod tests {
r#"{"name":"ns.int","type":"record","fields":[{"name":"value","type":"int"},{"name":"next","type":["null","ns.int"]}]}"#
);
}
+
+ #[test]
+ fn test_avro_3433_preserve_schema_refs_in_json() {
+ let schema = r#"
+ {
+ "name": "test.test",
+ "type": "record",
+ "fields": [
+ {
+ "name": "bar",
+ "type": { "name": "test.foo", "type": "record", "fields": [{ "name":
"id", "type": "long" }] }
+ },
+ { "name": "baz", "type": "test.foo" }
+ ]
+ }
+ "#;
+
+ let schema = Schema::parse_str(schema).unwrap();
+
+ let expected =
r#"{"name":"test.test","type":"record","fields":[{"name":"bar","type":{"name":"test.foo","type":"record","fields":[{"name":"id","type":"long"}]}},{"name":"baz","type":"test.foo"}]}"#;
+ assert_eq!(schema.canonical_form(), expected);
+ }
+
+ #[test]
+ fn test_read_namespace_from_name() {
+ let schema = r#"
+ {
+ "name": "space.name",
+ "type": "record",
+ "fields": [
+ {
+ "name": "num",
+ "type": "int"
+ }
+ ]
+ }
+ "#;
+
+ let schema = Schema::parse_str(schema).unwrap();
+ if let Schema::Record { name, .. } = schema {
+ assert_eq!(name.name, "name");
+ assert_eq!(name.namespace, Some("space".to_string()));
+ } else {
+ panic!("Expected a record schema!");
+ }
+ }
+
+ #[test]
+ fn test_namespace_from_name_has_priority_over_from_field() {
+ let schema = r#"
+ {
+ "name": "space1.name",
+ "namespace": "space2",
+ "type": "record",
+ "fields": [
+ {
+ "name": "num",
+ "type": "int"
+ }
+ ]
+ }
+ "#;
+
+ let schema = Schema::parse_str(schema).unwrap();
+ if let Schema::Record { name, .. } = schema {
+ assert_eq!(name.namespace, Some("space1".to_string()));
+ } else {
+ panic!("Expected a record schema!");
+ }
+ }
+
+ #[test]
+ fn test_namespace_from_field() {
+ let schema = r#"
+ {
+ "name": "name",
+ "namespace": "space2",
+ "type": "record",
+ "fields": [
+ {
+ "name": "num",
+ "type": "int"
+ }
+ ]
+ }
+ "#;
+
+ let schema = Schema::parse_str(schema).unwrap();
+ if let Schema::Record { name, .. } = schema {
+ assert_eq!(name.namespace, Some("space2".to_string()));
+ } else {
+ panic!("Expected a record schema!");
+ }
+ }
}
diff --git a/lang/rust/avro/tests/schema.rs b/lang/rust/avro/tests/schema.rs
index d7ff3e4..be2d9a8 100644
--- a/lang/rust/avro/tests/schema.rs
+++ b/lang/rust/avro/tests/schema.rs
@@ -699,45 +699,28 @@ fn test_parse_list_without_cross_deps() {
/// However, the output order is guaranteed to be the same as the input order.
fn test_parse_list_with_cross_deps_basic() {
init();
- let schema_str_1 = r#"{
+ let schema_a_str = r#"{
"name": "A",
"type": "record",
"fields": [
{"name": "field_one", "type": "float"}
]
}"#;
- let schema_str_2 = r#"{
+ let schema_b_str = r#"{
"name": "B",
"type": "record",
"fields": [
{"name": "field_one", "type": "A"}
]
}"#;
- let schema_composite = r#"{
- "name": "B",
- "type": "record",
- "fields": [
- { "name": "field_one",
- "type": {
- "name": "A",
- "type": "record",
- "fields": [
- {"name": "field_one", "type": "float"}
- ]
- }
- }
- ]
- }"#;
- let schema_strs_first = [schema_str_1, schema_str_2];
- let schema_strs_second = [schema_str_2, schema_str_1];
+ let schema_strs_first = [schema_a_str, schema_b_str];
+ let schema_strs_second = [schema_b_str, schema_a_str];
let schemas_first = Schema::parse_list(&schema_strs_first).expect("Test
failed");
let schemas_second = Schema::parse_list(&schema_strs_second).expect("Test
failed");
- let parsed_1 = Schema::parse_str(schema_str_1).expect("Test failed");
- let parsed_2 = Schema::parse_str(schema_composite).expect("Test failed");
- assert_eq!(schemas_first, vec!(parsed_1.clone(), parsed_2.clone()));
- assert_eq!(schemas_second, vec!(parsed_2, parsed_1));
+ assert_eq!(schemas_first[0], schemas_second[1]);
+ assert_eq!(schemas_first[1], schemas_second[0]);
}
#[test]
@@ -769,7 +752,7 @@ fn test_parse_list_recursive_type() {
/// Test that schema composition resolves namespaces.
fn test_parse_list_with_cross_deps_and_namespaces() {
init();
- let schema_str_1 = r#"{
+ let schema_a_str = r#"{
"name": "A",
"type": "record",
"namespace": "namespace",
@@ -777,38 +760,19 @@ fn test_parse_list_with_cross_deps_and_namespaces() {
{"name": "field_one", "type": "float"}
]
}"#;
- let schema_str_2 = r#"{
+ let schema_b_str = r#"{
"name": "B",
"type": "record",
"fields": [
{"name": "field_one", "type": "namespace.A"}
]
}"#;
- let schema_composite = r#"{
- "name": "B",
- "type": "record",
- "fields": [
- { "name": "field_one",
- "type": {
- "name": "A",
- "type": "record",
- "namespace": "namespace",
- "fields": [
- {"name": "field_one", "type": "float"}
- ]
- }
- }
- ]
- }"#;
- let schema_strs_first = [schema_str_1, schema_str_2];
- let schema_strs_second = [schema_str_2, schema_str_1];
- let schemas_first = Schema::parse_list(&schema_strs_first).expect("Test
failed");
- let schemas_second = Schema::parse_list(&schema_strs_second).expect("Test
failed");
- let parsed_1 = Schema::parse_str(schema_str_1).expect("Test failed");
- let parsed_2 = Schema::parse_str(schema_composite).expect("Test failed");
- assert_eq!(schemas_first, vec!(parsed_1.clone(), parsed_2.clone()));
- assert_eq!(schemas_second, vec!(parsed_2, parsed_1));
+ let schemas_first = Schema::parse_list(&[schema_a_str,
schema_b_str]).expect("Test failed");
+ let schemas_second = Schema::parse_list(&[schema_b_str,
schema_a_str]).expect("Test failed");
+
+ assert_eq!(schemas_first[0], schemas_second[1]);
+ assert_eq!(schemas_first[1], schemas_second[0]);
}
#[test]
@@ -901,14 +865,8 @@ fn test_parse_reused_record_schema_by_fullname() {
assert_eq!(name, "min_temp");
match schema {
- Schema::Record {
- ref name,
- doc: _,
- ref fields,
- lookup: _,
- } => {
+ Schema::Ref { ref name } => {
assert_eq!(name.fullname(None), "prefix.Temp", "Name does
not match!");
- assert_eq!(fields.len(), 1, "The number of the fields is
not correct!");
}
unexpected => unreachable!("Unexpected schema type: {:?}",
unexpected),
}
@@ -959,56 +917,29 @@ fn permutation_indices(indices: Vec<usize>) ->
Vec<Vec<usize>> {
/// definitions are passed in as a list. This should work regardless of the
ordering of the list.
fn test_parse_list_multiple_dependencies() {
init();
- let schema_str_1 = r#"{
+ let schema_a_str = r#"{
"name": "A",
"type": "record",
"fields": [
{"name": "field_one", "type": ["null", "B", "C"]}
]
}"#;
- let schema_str_2 = r#"{
+ let schema_b_str = r#"{
"name": "B",
"type": "fixed",
"size": 16
}"#;
- let schema_str_3 = r#"{
+ let schema_c_str = r#"{
"name": "C",
"type": "record",
"fields": [
{"name": "field_one", "type": "string"}
]
}"#;
- let schema_composite = r#"{
- "name": "A",
- "type": "record",
- "fields": [
- {
- "name": "field_one",
- "type": [
- "null",
- {
- "name": "B",
- "type": "fixed",
- "size": 16
- },
- {
- "name": "C",
- "type": "record",
- "fields": [
- {"name": "field_one", "type": "string"}
- ]
- }
- ]
- }
- ]
- }"#;
- let parsed = vec![
- Schema::parse_str(schema_str_2).expect("Test failed"),
- Schema::parse_str(schema_str_3).expect("Test failed"),
- Schema::parse_str(schema_composite).expect("Test failed"),
- ];
- let schema_strs = vec![schema_str_1, schema_str_2, schema_str_3];
+ let parsed =
+ Schema::parse_list(&[schema_a_str, schema_b_str,
schema_c_str]).expect("Test failed");
+ let schema_strs = vec![schema_a_str, schema_b_str, schema_c_str];
for schema_str_perm in permutations(&schema_strs) {
let schema_str_perm: Vec<&str> = schema_str_perm.iter().map(|s|
**s).collect();
let schemas = Schema::parse_list(&schema_str_perm).expect("Test
failed");
@@ -1024,68 +955,31 @@ fn test_parse_list_multiple_dependencies() {
/// definitions are passed in as a list. This should work regardless of the
ordering of the list.
fn test_parse_list_shared_dependency() {
init();
- let schema_str_1 = r#"{
+ let schema_a_str = r#"{
"name": "A",
"type": "record",
"fields": [
{"name": "field_one", "type": {"type": "array", "items": "C"}}
]
}"#;
- let schema_str_2 = r#"{
+ let schema_b_str = r#"{
"name": "B",
"type": "record",
"fields": [
{"name": "field_one", "type": {"type": "map", "values": "C"}}
]
}"#;
- let schema_str_3 = r#"{
+ let schema_c_str = r#"{
"name": "C",
"type": "record",
"fields": [
{"name": "field_one", "type": "string"}
]
}"#;
- let schema_composite_1 = r#"{
- "name": "A",
- "type": "record",
- "fields": [
- { "name": "field_one",
- "type": {"type": "array",
- "items": {
- "name": "C",
- "type": "record",
- "fields": [
- {"name": "field_one", "type": "string"}
- ]
- }
- }
- }
- ]
- }"#;
- let schema_composite_2 = r#"{
- "name": "B",
- "type": "record",
- "fields": [
- { "name": "field_one",
- "type": {"type": "map",
- "values": {
- "name": "C",
- "type": "record",
- "fields": [
- {"name": "field_one", "type": "string"}
- ]
- }
- }
- }
- ]
- }"#;
- let parsed = vec![
- Schema::parse_str(schema_str_3).expect("Test failed"),
- Schema::parse_str(schema_composite_1).expect("Test failed"),
- Schema::parse_str(schema_composite_2).expect("Test failed"),
- ];
- let schema_strs = vec![schema_str_1, schema_str_2, schema_str_3];
+ let parsed =
+ Schema::parse_list(&[schema_a_str, schema_b_str,
schema_c_str]).expect("Test failed");
+ let schema_strs = vec![schema_a_str, schema_b_str, schema_c_str];
for schema_str_perm in permutations(&schema_strs) {
let schema_str_perm: Vec<&str> = schema_str_perm.iter().map(|s|
**s).collect();
let schemas = Schema::parse_list(&schema_str_perm).expect("Test
failed");