Search in sources :

Example 1 with DataSchema

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));
        }
    }
}
Also used : DataSchema(com.linkedin.data.schema.DataSchema) RecordDataSchema(com.linkedin.data.schema.RecordDataSchema) NamedDataSchema(com.linkedin.data.schema.NamedDataSchema) Schema(org.apache.avro.Schema) DataSchema(com.linkedin.data.schema.DataSchema) RecordDataSchema(com.linkedin.data.schema.RecordDataSchema) NamedDataSchema(com.linkedin.data.schema.NamedDataSchema) RecordDataSchema(com.linkedin.data.schema.RecordDataSchema) SchemaParser(com.linkedin.data.schema.SchemaParser) GenericRecord(org.apache.avro.generic.GenericRecord) Predicate(com.linkedin.data.it.Predicate) DataMap(com.linkedin.data.DataMap) Test(org.testng.annotations.Test)

Example 2 with DataSchema

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);
}
Also used : DataSchema(com.linkedin.data.schema.DataSchema) File(java.io.File) DataMap(com.linkedin.data.DataMap) Test(org.testng.annotations.Test)

Example 3 with DataSchema

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 + "\"");
                }
            }
        }
    }
}
Also used : PegasusSchemaParser(com.linkedin.data.schema.PegasusSchemaParser) DataSchema(com.linkedin.data.schema.DataSchema) Schema(org.apache.avro.Schema) SchemaParser(com.linkedin.data.schema.SchemaParser) PegasusSchemaParser(com.linkedin.data.schema.PegasusSchemaParser) ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) IOException(java.io.IOException) DataMap(com.linkedin.data.DataMap) DataSchema(com.linkedin.data.schema.DataSchema) GenericRecord(org.apache.avro.generic.GenericRecord)

Example 4 with DataSchema

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);
        }
    }
}
Also used : Mode(com.linkedin.data.transform.patch.validator.PatchFilterValidator.Mode) RequiredMode(com.linkedin.data.schema.validation.RequiredMode) CoercionMode(com.linkedin.data.schema.validation.CoercionMode) TestUtil.dataMapFromString(com.linkedin.data.TestUtil.dataMapFromString) TestUtil.dataSchemaFromString(com.linkedin.data.TestUtil.dataSchemaFromString) ValidationOptions(com.linkedin.data.schema.validation.ValidationOptions) ValidationResult(com.linkedin.data.schema.validation.ValidationResult) DataMap(com.linkedin.data.DataMap) DataSchema(com.linkedin.data.schema.DataSchema) DataElement(com.linkedin.data.element.DataElement) TestUtil.asList(com.linkedin.data.TestUtil.asList) ArrayList(java.util.ArrayList) List(java.util.List) Validator(com.linkedin.data.schema.validator.Validator) Test(org.testng.annotations.Test)

Example 5 with DataSchema

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();
    }
}
Also used : DataSchema(com.linkedin.data.schema.DataSchema) RecordDataSchema(com.linkedin.data.schema.RecordDataSchema) UnionDataSchema(com.linkedin.data.schema.UnionDataSchema) UnionDataSchema(com.linkedin.data.schema.UnionDataSchema)

Aggregations

DataSchema (com.linkedin.data.schema.DataSchema)131 RecordDataSchema (com.linkedin.data.schema.RecordDataSchema)82 NamedDataSchema (com.linkedin.data.schema.NamedDataSchema)53 ArrayDataSchema (com.linkedin.data.schema.ArrayDataSchema)48 TyperefDataSchema (com.linkedin.data.schema.TyperefDataSchema)44 DataMap (com.linkedin.data.DataMap)43 UnionDataSchema (com.linkedin.data.schema.UnionDataSchema)41 MapDataSchema (com.linkedin.data.schema.MapDataSchema)40 Test (org.testng.annotations.Test)37 EnumDataSchema (com.linkedin.data.schema.EnumDataSchema)36 FixedDataSchema (com.linkedin.data.schema.FixedDataSchema)24 ByteString (com.linkedin.data.ByteString)15 TestUtil.dataMapFromString (com.linkedin.data.TestUtil.dataMapFromString)15 TestUtil.dataSchemaFromString (com.linkedin.data.TestUtil.dataSchemaFromString)14 PrimitiveDataSchema (com.linkedin.data.schema.PrimitiveDataSchema)14 ArrayList (java.util.ArrayList)12 DataList (com.linkedin.data.DataList)11 ComplexDataSchema (com.linkedin.data.schema.ComplexDataSchema)9 SchemaParser (com.linkedin.data.schema.SchemaParser)9 ValidationOptions (com.linkedin.data.schema.validation.ValidationOptions)9