use of com.linkedin.data.schema.DataSchema in project rest.li by linkedin.
the class TestFilteredSchemaDataTranslation method testFilteredDataSchemaDataTranslation.
/**
* Removed field from Pegasus schema.
*/
@Test
public void testFilteredDataSchemaDataTranslation() throws IOException {
Object[][] inputs = { { "{ " + " \"type\" : \"record\", " + " \"name\" : \"Foo\", " + " \"fields\" : [ " + " { \"name\" : \"a\", \"type\" : \"int\" }, " + " { \"name\" : \"b\", \"type\" : [ \"null\", \"int\" ], \"default\" : null }, " + " { \"name\" : \"removeMe\", \"type\" : \"int\" } " + " ] " + "}", Predicates.hasChildWithNameValue("name", "removeMe"), "{ " + " \"type\" : \"record\", " + " \"name\" : \"Foo\", " + " \"fields\" : [ " + " { \"name\" : \"a\", \"type\" : \"int\" }, " + " { \"name\" : \"b\", \"type\" : \"int\", \"optional\" : true } " + " ] " + "}", // "removeMe" is dropped from output because it is not in output schema
"{ \"a\" : 1, \"b\" : { \"int\" : 2 }, \"removeMe\" : 3 }", "{ \"a\" : 1, \"b\" : 2 }", // "b" has null value is dropped from output, "removeMe" is dropped from output because it is not in output schema
"{ \"a\" : 1, \"b\" : null, \"removeMe\" : 3 }", "{ \"a\" : 1 }" } };
for (Object[] row : inputs) {
int i = 0;
String avroSchemaText = (String) row[i++];
Predicate predicate = (Predicate) row[i++];
String schemaText = (String) row[i++];
Schema avroSchema = Schema.parse(avroSchemaText);
System.out.println(avroSchema);
RecordDataSchema schema = (RecordDataSchema) SchemaTranslator.avroToDataSchema(avroSchema);
RecordDataSchema filteredSchema = (RecordDataSchema) Filters.removeByPredicate(schema, predicate, new SchemaParser());
DataSchema expectedSchema = TestUtil.dataSchemaFromString(schemaText);
System.out.println(filteredSchema);
assertEquals(filteredSchema, expectedSchema);
while (i < row.length) {
String translationSourceJson = (String) row[i++];
String translationExpectedJson = (String) row[i++];
GenericRecord genericRecord = AvroUtil.genericRecordFromJson(translationSourceJson, avroSchema);
DataMap dataMap = DataTranslator.genericRecordToDataMap(genericRecord, filteredSchema, avroSchema);
assertEquals(dataMap, TestUtil.dataMapFromString(translationExpectedJson));
}
}
}
use of com.linkedin.data.schema.DataSchema in project rest.li by linkedin.
the class TestSchemaTranslator method testAvroUnionModeChaining.
@Test
public void testAvroUnionModeChaining() throws IOException {
String expectedSchema = "{ " + " \"type\" : \"record\", " + " \"name\" : \"A\", " + " \"namespace\" : \"com.linkedin.pegasus.test\", " + " \"fields\" : [ " + " { " + " \"name\" : \"someBorC\", " + " \"type\" : [ " + " { " + " \"type\" : \"record\", " + " \"name\" : \"B\", " + " \"fields\" : [ " + " { " + " \"name\" : \"someAorC\", " + " \"type\" : [ " + " \"A\", " + " { " + " \"type\" : \"record\", " + " \"name\" : \"C\", " + " \"fields\" : [ " + " { " + " \"name\" : \"something\", " + " \"type\" : \"int\", " + " \"optional\" : true, " + " \"default\" : 42" + " } " + " ] " + " } " + " ] " + " } " + " ] " + " }, " + " \"C\" " + " ] " + " } " + " ]" + "}";
String avroRootUrl = getClass().getClassLoader().getResource("avro").getFile();
String avroRootDir = new File(avroRootUrl).getAbsolutePath();
String avroFilePath = avroRootDir + FS + "com" + FS + "linkedin" + FS + "pegasus" + FS + "test" + FS + "A.avsc";
File avroFile = new File(avroFilePath);
String schema = readFile(avroFile);
AvroToDataSchemaTranslationOptions options = new AvroToDataSchemaTranslationOptions(AvroToDataSchemaTranslationMode.TRANSLATE).setFileResolutionPaths(avroRootDir);
DataSchema pdscSchema = SchemaTranslator.avroToDataSchema(schema, options);
DataMap actual = TestUtil.dataMapFromString(pdscSchema.toString());
DataMap expected = TestUtil.dataMapFromString(expectedSchema);
assertEquals(actual, expected);
}
use of com.linkedin.data.schema.DataSchema in project rest.li by linkedin.
the class TestSchemaTranslator method testToAvroSchema.
private void testToAvroSchema(String schemaText, Object[] row) throws IOException {
boolean debug = false;
if (debug)
System.out.println(schemaText);
for (int i = 1; i < row.length; i++) {
Object[] modeInputs = (Object[]) row[i];
OptionalDefaultMode[] optionalDefaultModes = (OptionalDefaultMode[]) modeInputs[0];
Object expected = modeInputs[1];
for (EmbedSchemaMode embedSchemaMode : EmbedSchemaMode.values()) {
for (OptionalDefaultMode optionalDefaultMode : optionalDefaultModes) {
DataSchema schema = TestUtil.dataSchemaFromString(schemaText);
String preTranslateSchemaText = schema.toString();
Exception exc = null;
String avroTextFromSchema = null;
try {
avroTextFromSchema = SchemaTranslator.dataToAvroSchemaJson(schema, new DataToAvroSchemaTranslationOptions(optionalDefaultMode, JsonBuilder.Pretty.SPACES, embedSchemaMode));
if (debug) {
System.out.println("EmbeddedSchema: " + embedSchemaMode + ", OptionalDefaultMode: " + optionalDefaultMode + ", Avro Schema: " + avroTextFromSchema);
}
} catch (Exception e) {
exc = e;
if (debug) {
e.printStackTrace();
}
}
if (expected instanceof String) {
assertNull(exc);
String expectedAvroText = (String) expected;
if (embedSchemaMode == EmbedSchemaMode.ROOT_ONLY && hasEmbeddedSchema(schema)) {
// when embeddedSchema is enabled
// for map, array, enums. and records, we embed the original Pegasus schema
DataMap expectedAvroDataMap = TestUtil.dataMapFromString(expectedAvroText);
DataMap resultAvroDataMap = TestUtil.dataMapFromString(avroTextFromSchema);
Object dataProperty = resultAvroDataMap.remove(SchemaTranslator.DATA_PROPERTY);
assertEquals(resultAvroDataMap, expectedAvroDataMap);
// look for embedded schema
assertNotNull(dataProperty);
assertTrue(dataProperty instanceof DataMap);
Object schemaProperty = ((DataMap) dataProperty).get(SchemaTranslator.SCHEMA_PROPERTY);
assertNotNull(schemaProperty);
assertTrue(schemaProperty instanceof DataMap);
// make sure embedded schema is same as the original schema
PegasusSchemaParser schemaParser = TestUtil.schemaParserFromObjects(Arrays.asList(schemaProperty));
DataSchema embeddedSchema = schemaParser.topLevelDataSchemas().get(0);
assertEquals(embeddedSchema, schema.getDereferencedDataSchema());
// look for optional default mode
Object optionalDefaultModeProperty = ((DataMap) dataProperty).get(SchemaTranslator.OPTIONAL_DEFAULT_MODE_PROPERTY);
assertNotNull(optionalDefaultMode);
assertEquals(optionalDefaultModeProperty, optionalDefaultMode.toString());
} else {
// for unions and primitives, we never embed the pegasus schema
if (embedSchemaMode == EmbedSchemaMode.NONE && hasEmbeddedSchema(schema)) {
// make sure no embedded schema when
DataMap resultAvroDataMap = TestUtil.dataMapFromString(avroTextFromSchema);
assertFalse(resultAvroDataMap.containsKey(SchemaTranslator.DATA_PROPERTY));
}
assertEquals(avroTextFromSchema, expectedAvroText);
}
String postTranslateSchemaText = schema.toString();
assertEquals(preTranslateSchemaText, postTranslateSchemaText);
// make sure Avro accepts it
Schema avroSchema = Schema.parse(avroTextFromSchema);
if (debug)
System.out.println("AvroSchema: " + avroSchema);
SchemaParser parser = new SchemaParser();
ValidationOptions options = new ValidationOptions();
options.setAvroUnionMode(true);
parser.setValidationOptions(options);
parser.parse(avroTextFromSchema);
assertFalse(parser.hasError(), parser.errorMessage());
if (optionalDefaultMode == DataToAvroSchemaTranslationOptions.DEFAULT_OPTIONAL_DEFAULT_MODE) {
// use other dataToAvroSchemaJson
String avroSchema2Json = SchemaTranslator.dataToAvroSchemaJson(TestUtil.dataSchemaFromString(schemaText));
String avroSchema2JsonCompact = SchemaTranslator.dataToAvroSchemaJson(TestUtil.dataSchemaFromString(schemaText), new DataToAvroSchemaTranslationOptions());
assertEquals(avroSchema2Json, avroSchema2JsonCompact);
Schema avroSchema2 = Schema.parse(avroSchema2Json);
assertEquals(avroSchema2, avroSchema);
// use dataToAvroSchema
Schema avroSchema3 = SchemaTranslator.dataToAvroSchema(TestUtil.dataSchemaFromString(schemaText));
assertEquals(avroSchema3, avroSchema2);
}
if (modeInputs.length >= 4) {
// check if the translated default value is good by using it.
// writer schema and Avro JSON value should not include fields with default values.
String writerSchemaText = (String) modeInputs[2];
String avroValueJson = (String) modeInputs[3];
Schema writerSchema = Schema.parse(writerSchemaText);
GenericRecord genericRecord = genericRecordFromString(avroValueJson, writerSchema, avroSchema);
if (modeInputs.length >= 5) {
String genericRecordJson = (String) modeInputs[4];
String genericRecordAsString = genericRecord.toString();
DataMap expectedGenericRecord = TestUtil.dataMapFromString(genericRecordJson);
DataMap resultGenericRecord = TestUtil.dataMapFromString(genericRecordAsString);
assertEquals(resultGenericRecord, expectedGenericRecord);
}
}
if (embedSchemaMode == EmbedSchemaMode.ROOT_ONLY && hasEmbeddedSchema(schema)) {
// if embedded schema is enabled, translate Avro back to Pegasus schema.
// the output Pegasus schema should be exactly same the input schema
// taking into account typeref.
AvroToDataSchemaTranslationOptions avroToDataSchemaMode = new AvroToDataSchemaTranslationOptions(AvroToDataSchemaTranslationMode.VERIFY_EMBEDDED_SCHEMA);
DataSchema embeddedSchema = SchemaTranslator.avroToDataSchema(avroTextFromSchema, avroToDataSchemaMode);
assertEquals(embeddedSchema, schema.getDereferencedDataSchema());
}
} else {
Class<?> expectedExceptionClass = (Class<?>) expected;
String expectedString = (String) modeInputs[2];
assertNotNull(exc);
assertNull(avroTextFromSchema);
assertTrue(expectedExceptionClass.isInstance(exc));
assertTrue(exc.getMessage().contains(expectedString), "\"" + exc.getMessage() + "\" does not contain \"" + expectedString + "\"");
}
}
}
}
}
use of com.linkedin.data.schema.DataSchema in project rest.li by linkedin.
the class TestPatchFilterValidator method testPatchFilterValidator.
@Test
public void testPatchFilterValidator() throws IOException {
String schemaText = "{\n" + " \"type\" : \"record\",\n" + " \"name\" : \"Foo\",\n" + " \"fields\" : [\n" + " { \"name\" : \"fooInt\", \"type\" : \"int\", \"optional\" : true },\n" + " { \"name\" : \"fooString\", \"type\" : \"string\", \"optional\" : true },\n" + " {\n" + " \"name\" : \"bar\",\n" + " \"type\" : {\n" + " \"type\" : \"record\",\n" + " \"name\" : \"Bar\",\n" + " \"fields\" : [\n" + " { \"name\" : \"barInt\", \"type\" : \"int\", \"optional\" : true },\n" + " { \"name\" : \"barString\", \"type\" : \"string\", \"optional\" : true },\n" + " {\n" + " \"name\" : \"baz\",\n" + " \"type\" : {\n" + " \"type\" : \"record\",\n" + " \"name\" : \"Baz\",\n" + " \"fields\" : [\n" + " { \"name\" : \"bazInt\", \"type\" : \"int\", \"optional\" : true },\n" + " { \"name\" : \"bazString\", \"type\" : \"string\", \"optional\" : true }\n" + " ]\n" + " },\n" + " \"optional\" : true\n" + " }\n" + " ]\n" + " },\n" + " \"optional\" : true\n" + " }\n" + " ]\n" + "}\n";
Object[][] inputs = { // }
{ // deleted /fooInt
"{ }", "{ \"$delete\" : [ \"fooInt\" ] }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, ""), asList(Mode.ANCESTOR_AND_SET, "") }, { // must not call validator for parents and ancestors not modified
"{ \"fooString\" : \"excluded\", \"bar\" : { \"barInt\" : -1 } }", "{ \"$delete\" : [ \"fooInt\" ] }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, ""), asList(Mode.ANCESTOR_AND_SET, "") }, { // deleted /bar/barInt
"{ \"bar\" : { } }", "{ \"bar\" : { \"$delete\" : [ \"barInt\" ] } }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, "/bar"), asList(Mode.ANCESTOR_AND_SET, "", "/bar") }, { // must not call validator for parents and ancestors not modified
"{ \"fooInt\" : -1, \"fooString\" : \"excluded\", \"bar\" : { } }", "{ \"bar\" : { \"$delete\" : [ \"barInt\" ] } }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, "/bar"), asList(Mode.ANCESTOR_AND_SET, "", "/bar") }, { // deleted /bar/baz/bazInt
"{ \"bar\" : { \"baz\" : { } } }", "{ \"bar\" : { \"baz\" : { \"$delete\" : [ \"bazInt\" ] } } }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, "/bar/baz"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz") }, { // must not call validator for parents and ancestors not modified
"{ \"fooInt\" : -1, \"fooString\" : \"excluded\", \"bar\" : { \"barInt\" : -1, \"baz\" : { } } }", "{ \"bar\" : { \"baz\" : { \"$delete\" : [ \"bazInt\" ] } } }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, "/bar/baz"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz") }, { // deleted /bar/baz
"{ \"bar\" : { } }", "{ \"bar\" : { \"$delete\" : [ \"baz\" ] } }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, "/bar"), asList(Mode.ANCESTOR_AND_SET, "", "/bar") }, { // must not call validator for parents and ancestors not modified
"{ \"fooInt\" : -1, \"fooString\" : \"excluded\", \"bar\" : { \"barInt\" : -1 } }", "{ \"bar\" : { \"$delete\" : [ \"baz\" ] } }", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET, "/bar"), asList(Mode.ANCESTOR_AND_SET, "", "/bar") }, { // set /fooInt (set field in root record)
"{ \"fooInt\" : 2 }", "{ \"$set\" : { \"fooInt\" : 2 } }", "", asList(Mode.SET_ONLY, "/fooInt"), asList(Mode.PARENT_AND_SET, "", "/fooInt"), asList(Mode.ANCESTOR_AND_SET, "", "/fooInt") }, { // must not call validator for parents and ancestors not modified
"{ \"fooInt\" : 2, \"fooString\" : \"excluded\", \"bar\" : { \"baz\" : { } } }", "{ \"$set\" : { \"fooInt\" : 2 } }", "", asList(Mode.SET_ONLY, "/fooInt"), asList(Mode.PARENT_AND_SET, "", "/fooInt"), asList(Mode.ANCESTOR_AND_SET, "", "/fooInt") }, { // must not call validator for parents and ancestors not modified
"{\n" + " \"fooInt\" : 2,\n" + " \"fooString\" : \"excluded\",\n" + " \"bar\" : {\n" + " \"barInt\" : 2,\n" + " \"barString\" : \"excluded\",\n" + " \"baz\" : {}\n" + " }\n" + "}", "{ \"bar\" : { \"$set\" : { \"barInt\" : 2 } } }", "", asList(Mode.SET_ONLY, "/bar/barInt"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/barInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/barInt") }, { // must not call validator for parents and ancestors not modified
"{\n" + " \"fooInt\" : -1,\n" + " \"fooString\" : \"excludes\",\n" + " \"bar\" : {\n" + " \"barInt\" : -1,\n" + " \"barString\" : \"x\",\n" + " \"baz\" : {\n" + " \"bazInt\" : 2,\n" + " \"bazString\" : \"excludes\"\n" + " }\n" + " }\n" + "}", "{ \"bar\" : { \"$set\" : { \"barString\" : \"x\" } } }", "", asList(Mode.SET_ONLY, "/bar/barString"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/barString"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/barString") }, { // set /bar/baz/bazInt (set field in nested grandchild record)
"{ \"bar\" : { \"baz\" : { \"bazInt\" : 2 } } }", "{ \"bar\" : { \"baz\" : { \"$set\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { // must not call validator for parents and ancestors not modified
"{\n" + " \"fooInt\" : 2,\n" + " \"fooString\" : \"excluded\",\n" + " \"bar\" : {\n" + " \"barInt\" : 2,\n" + " \"barString\" : \"excluded\",\n" + " \"baz\" : {\n" + " \"bazInt\" : 2,\n" + " \"bazString\" : \"excluded\"\n" + " }\n" + " }\n" + "}", "{ \"bar\" : { \"baz\" : { \"$set\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { // must not call validator for parents and ancestors not modified
"{\n" + " \"fooInt\" : -1,\n" + " \"fooString\" : \"excludes\",\n" + " \"bar\" : {\n" + " \"barInt\" : -1,\n" + " \"baz\" : {\n" + " \"bazInt\" : 2,\n" + " \"bazString\" : \"excludes\"\n" + " }\n" + " }\n" + "}", "{ \"bar\" : { \"baz\" : { \"$set\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { // set /bar (set record in root record)
"{ \"bar\" : { \"baz\" : { \"bazInt\" : 2 } } }", "{ \"$set\" : { \"bar\" : { \"baz\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar", "/bar/baz", "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { // must not call validator for parents and ancestors not modified
"{\n" + " \"fooInt\" : 2,\n" + " \"fooString\" : \"excluded\",\n" + " \"bar\" : {\n" + " \"baz\" : {\n" + " \"bazInt\" : 2\n" + " }\n" + " }\n" + "}", "{ \"bar\" : { \"baz\" : { \"$set\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { // set /bar/baz (set record in nested child record)
"{ \"bar\" : { \"baz\" : { \"bazInt\" : 2 } } }", "{ \"bar\" : { \"$set\" : { \"baz\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { // must not call validator for parents and ancestors not modified
"{\n" + " \"fooInt\" : 2,\n" + " \"fooString\" : \"excluded\",\n" + " \"bar\" : {\n" + " \"barInt\" : 2,\n" + " \"barString\" : \"excluded\",\n" + " \"baz\" : {\n" + " \"bazInt\" : 2\n" + " }\n" + " }\n" + "}", "{ \"bar\" : { \"$set\" : { \"baz\" : { \"bazInt\" : 2 } } } }", "", asList(Mode.SET_ONLY, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { // must not call validator for parents and ancestors not modified
"{\n" + " \"fooInt\" : -1,\n" + " \"fooString\" : \"excludes\",\n" + " \"bar\" : {\n" + " \"barInt\" : -1,\n" + " \"barString\" : \"excludes\",\n" + " \"baz\" : {\n" + " \"bazInt\" : 2,\n" + " \"bazString\" : \"x\"\n" + " }\n" + " }\n" + "}", "{ \"bar\" : { \"$set\" : { \"baz\" : { \"bazInt\" : 2, \"bazString\" : \"x\" } } } }", "", asList(Mode.SET_ONLY, "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString") }, { // set /fooInt, /fooString (set multiple fields in root record)
"{ \"fooInt\" : 2, \"fooString\" : \"x\" }", "{ \"$set\" : { \"fooInt\" : 2, \"fooString\" : \"x\" } }", "", asList(Mode.SET_ONLY, "/fooInt", "/fooString"), asList(Mode.PARENT_AND_SET, "", "/fooInt", "/fooString"), asList(Mode.ANCESTOR_AND_SET, "", "/fooInt", "/fooString") }, { // set /bar/barInt, /bar/barString (set multiple fields in nested child record)
"{ \"bar\" : { \"barInt\" : 2, \"barString\" : \"x\" } }", "{ \"bar\" : { \"$set\" : { \"barInt\" : 2, \"barString\" : \"x\" } } }", "", asList(Mode.SET_ONLY, "/bar/barInt", "/bar/barString"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/barInt", "/bar/barString"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/barInt", "/bar/barString") }, { // set /bar/baz/bazInt, /bar/baz/bazString (set multiple fields in nested grandchild record)
"{ \"bar\" : { \"baz\" : { \"bazInt\" : 2, \"bazString\" : \"x\" } } }", "{ \"bar\" : { \"baz\" : { \"$set\" : { \"bazInt\" : 2, \"bazString\" : \"x\" } } } }", "", asList(Mode.SET_ONLY, "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString") }, { // set /fooInt, /bar/barInt, /bar/baz/bazInt
"{\n" + " \"fooInt\" : 2,\n" + " \"bar\" : {\n" + " \"barInt\" : 2,\n" + " \"baz\" : {\n" + " \"bazInt\" : 2\n" + " }\n" + " }\n" + "}", "{\n" + " \"$set\" : { \"fooInt\" : 2 },\n" + " \"bar\" : {\n" + " \"$set\" : { \"barInt\" : 2 },\n" + " \"baz\" : {\n" + " \"$set\" : { \"bazInt\" : 2 }\n" + " }\n" + " }\n" + "}", "", asList(Mode.SET_ONLY, "/fooInt", "/bar/barInt", "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "", "/fooInt", "/bar", "/bar/barInt", "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/fooInt", "/bar", "/bar/barInt", "/bar/baz", "/bar/baz/bazInt") }, { // nothing set
"{\n" + " \"fooInt\" : -1,\n" + " \"fooString\" : \"excludes\",\n" + " \"bar\" : {\n" + " \"barInt\" : -1,\n" + " \"baz\" : {\n" + " \"bazInt\" : -1,\n" + " \"bazString\" : \"excludes\"\n" + " }\n" + " }\n" + "}", "{}", "", asList(Mode.SET_ONLY), asList(Mode.PARENT_AND_SET), asList(Mode.ANCESTOR_AND_SET) }, { // must not call next validator for /fooString, /bar/barInt
"{\n" + " \"fooInt\" : 2,\n" + " \"fooString\" : \"excludes\",\n" + " \"bar\" : {\n" + " \"barInt\" : -1,\n" + " \"baz\" : {\n" + " \"bazInt\" : 2,\n" + " \"bazString\" : \"x\"\n" + " }\n" + " }\n" + "}", "{\n" + " \"$set\" : { \"fooInt\" : 2 },\n" + " \"bar\" : {\n" + " \"$set\" : {\n" + " \"baz\" : { \"bazInt\" : 2, \"bazString\" : \"x\" }\n" + " }\n" + " }\n" + "}", "", asList(Mode.SET_ONLY, "/fooInt", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.PARENT_AND_SET, "", "/fooInt", "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.ANCESTOR_AND_SET, "", "/fooInt", "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString") }, { // must not call next validator for /fooInt, /fooString, /bar/barInt
"{\n" + " \"fooInt\" : 2,\n" + " \"fooString\" : \"excludes\",\n" + " \"bar\" : {\n" + " \"barInt\" : -1,\n" + " \"baz\" : {\n" + " \"bazInt\" : 2,\n" + " \"bazString\" : \"x\"\n" + " }\n" + " }\n" + "}", "{\n" + " \"$set\" : {\n" + " \"baz\" : {\n" + " \"bazInt\" : 2,\n" + " \"bazString\" : \"x\"\n" + " }\n" + " }\n" + "}", "/bar", asList(Mode.SET_ONLY, "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.PARENT_AND_SET, "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt", "/bar/baz/bazString") }, { // must not call next validator for /fooInt, /fooString, /bar/barInt
"{\n" + " \"fooInt\" : 2,\n" + " \"fooString\" : \"excludes\",\n" + " \"bar\" : {\n" + " \"barInt\" : -1,\n" + " \"baz\" : {\n" + " \"bazInt\" : 2,\n" + " \"bazString\" : \"x\"\n" + " }\n" + " }\n" + "}", "{\n" + " \"baz\" : {\n" + " \"$set\" : {\n" + " \"bazInt\" : 2\n" + " }\n" + " }\n" + "}", "/bar", asList(Mode.SET_ONLY, "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") }, { // must not call next validator for /fooInt, /fooString, /bar/barInt
"{\n" + " \"fooInt\" : 2,\n" + " \"fooString\" : \"excludes\",\n" + " \"bar\" : {\n" + " \"barInt\" : -1,\n" + " \"baz\" : {\n" + " \"bazInt\" : 2,\n" + " \"bazString\" : \"x\"\n" + " }\n" + " }\n" + "}", "{\n" + " \"$set\" : { \"bazInt\" : 2 }\n" + "}", "/bar/baz", asList(Mode.SET_ONLY, "/bar/baz/bazInt"), asList(Mode.PARENT_AND_SET, "/bar/baz", "/bar/baz/bazInt"), asList(Mode.ANCESTOR_AND_SET, "", "/bar", "/bar/baz", "/bar/baz/bazInt") } };
DataSchema schema = dataSchemaFromString(schemaText);
ValidationOptions options = new ValidationOptions(RequiredMode.CAN_BE_ABSENT_IF_HAS_DEFAULT, CoercionMode.NORMAL);
for (Object[] row : inputs) {
String value = (String) row[0];
String patch = (String) row[1];
String patchPath = (String) row[2];
DataMap valueMap = dataMapFromString(value);
DataMap opMap = dataMapFromString(patch);
if (debug) {
out.println("Value: " + value);
out.println("Patch: " + patch);
if (patchPath.isEmpty() == false)
out.println("PatchPath: " + patchPath);
}
for (int i = 3; i < row.length; i++) {
VisitedValidator visitedValidator = new VisitedValidator();
@SuppressWarnings("unchecked") List<Object> check = (List<Object>) row[i];
Mode mode = (Mode) check.get(0);
Validator validator;
if (patchPath.isEmpty()) {
validator = new PatchFilterValidator(visitedValidator, opMap, mode);
} else {
DataElement patchElement = DataElementUtil.element(valueMap, schema, patchPath);
assertNotSame(patchElement, null);
validator = new PatchFilterValidator(visitedValidator, opMap, mode, patchElement);
}
ValidationResult result = ValidateDataAgainstSchema.validate(valueMap, schema, options, validator);
if (debug) {
out.println("Mode: " + mode);
out.print("Result: " + result);
out.println("VisitedPaths: " + visitedValidator._visitedPaths);
}
assertTrue(result.isValid());
for (int j = 1; j < check.size(); j++) {
assertTrue(visitedValidator._visitedPaths.contains(check.get(j)));
}
assertEquals(visitedValidator._visitedPaths.size(), check.size() - 1);
}
}
}
use of com.linkedin.data.schema.DataSchema in project rest.li by linkedin.
the class SchemaToAvroJsonEncoder method encodeFieldType.
/**
* Encode a field's type to an Avro-compliant schema.
*
* Special handling is required for optional fields.
* An optional field is encoded as a union with null.
* If the optional field is not a union, then union
* the field's type with null.
* If the optional field is already a union, then
* include null as a member type if it is not already
* part of the union.
* If the resulting type is a union and resulting field
* has a default value, then the resulting union's list
* of member types are encoded such that the type of
* the translated default value is always the 1st type
* in this list (see Avro specification for more details.)
*
* For required and non-union fields, no special handling is required.
*
* @param field providing the type to encode.
* @throws IOException if there is an error while encoding.
*/
@Override
protected void encodeFieldType(RecordDataSchema.Field field) throws IOException {
boolean optional = field.getOptional();
DataSchema fieldSchema = field.getType();
UnionDataSchema unionDataSchema = (fieldSchema.getDereferencedType() == DataSchema.Type.UNION ? (UnionDataSchema) fieldSchema.getDereferencedDataSchema() : null);
_builder.writeFieldName(TYPE_KEY);
if (optional == false && unionDataSchema == null) {
encode(fieldSchema);
} else {
// special handling for unions
// output will be an union if the field is optional or its type is a union
// whether to add null to translated union,
// set to true for optional non-union type or optional union without null member
boolean addNullMemberType;
// DataSchema of default value, null if there is no default value.
DataSchema defaultValueSchema;
// members of the union (excluding null introduced by optional)
List<DataSchema> resultMemberTypes;
Object defaultValue = field.getDefault();
if (optional) {
if (unionDataSchema == null) {
addNullMemberType = true;
resultMemberTypes = new ArrayList<DataSchema>(1);
resultMemberTypes.add(fieldSchema);
defaultValueSchema = (defaultValue != null && _options.getOptionalDefaultMode() == OptionalDefaultMode.TRANSLATE_DEFAULT ? fieldSchema : DataSchemaConstants.NULL_DATA_SCHEMA);
} else {
addNullMemberType = unionDataSchema.getType(DataSchemaConstants.NULL_TYPE) == null;
resultMemberTypes = unionDataSchema.getTypes();
defaultValueSchema = (defaultValue != null && _options.getOptionalDefaultMode() == OptionalDefaultMode.TRANSLATE_DEFAULT ? unionValueDataSchema(unionDataSchema, defaultValue) : DataSchemaConstants.NULL_DATA_SCHEMA);
}
assert (_options.getOptionalDefaultMode() != OptionalDefaultMode.TRANSLATE_TO_NULL || defaultValueSchema == DataSchemaConstants.NULL_DATA_SCHEMA);
} else {
// must be union
addNullMemberType = false;
resultMemberTypes = unionDataSchema.getTypes();
defaultValueSchema = unionValueDataSchema(unionDataSchema, defaultValue);
}
// encode the member types
// add null member type if addNullMemberType is present
_builder.writeStartArray();
// this variable keeps track of whether null member type has been emitted
boolean emittedNull = false;
// if field has a default, defaultValueSchema != null, always encode it 1st
if (defaultValueSchema != null) {
emittedNull |= (defaultValueSchema.getDereferencedType() == DataSchema.Type.NULL);
encode(defaultValueSchema);
}
for (DataSchema type : resultMemberTypes) {
if (defaultValueSchema == type) {
continue;
}
if (type.getDereferencedType() == DataSchema.Type.NULL) {
if (emittedNull)
continue;
else
emittedNull = true;
}
encode(type);
}
// emit null member type if it is has to be added and has not already been emitted
if (addNullMemberType && emittedNull == false) {
_builder.writeString(DataSchemaConstants.NULL_TYPE);
emittedNull = true;
}
assert (addNullMemberType == false || emittedNull == true);
_builder.writeEndArray();
}
}
Aggregations