-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.ionschema.writer.internal | ||
|
||
import com.amazon.ion.IonWriter | ||
import com.amazon.ionschema.IonSchemaVersion | ||
import com.amazon.ionschema.internal.util.islRequire | ||
import com.amazon.ionschema.model.ExperimentalIonSchemaModel | ||
import com.amazon.ionschema.model.NamedTypeDefinition | ||
import com.amazon.ionschema.model.SchemaDocument | ||
import com.amazon.ionschema.model.SchemaFooter | ||
import com.amazon.ionschema.model.SchemaHeader | ||
import com.amazon.ionschema.model.TypeDefinition | ||
|
||
@ExperimentalIonSchemaModel | ||
internal object IonSchemaWriterV2_0 : VersionedIonSchemaWriter { | ||
|
||
private val headerWriter = HeaderWriter | ||
private val typeWriter = TypeWriterV2_0 | ||
private val footerWriter = FooterWriter | ||
|
||
override fun writeSchema(ionWriter: IonWriter, schemaDocument: SchemaDocument) { | ||
islRequire(schemaDocument.ionSchemaVersion == IonSchemaVersion.v2_0) { "IonSchemaWriterV2_0 only supports ISL 2.0" } | ||
ionWriter.writeSymbol("\$ion_schema_2_0") | ||
for (item in schemaDocument.items) { | ||
when (item) { | ||
is SchemaHeader -> headerWriter.writeHeader(ionWriter, item) | ||
is NamedTypeDefinition -> writeNamedType(ionWriter, item) | ||
is SchemaFooter -> footerWriter.writeFooter(ionWriter, item) | ||
is SchemaDocument.OpenContent -> item.value.writeTo(ionWriter) | ||
} | ||
Check warning on line 32 in ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/IonSchemaWriterV2_0.kt Codecov / codecov/patchion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/IonSchemaWriterV2_0.kt#L32
|
||
} | ||
} | ||
|
||
override fun writeType(ionWriter: IonWriter, typeDefinition: TypeDefinition) { | ||
typeWriter.writeOrphanedTypeDefinition(ionWriter, typeDefinition) | ||
Check warning on line 37 in ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/IonSchemaWriterV2_0.kt Codecov / codecov/patchion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/IonSchemaWriterV2_0.kt#L37
|
||
} | ||
|
||
override fun writeNamedType(ionWriter: IonWriter, namedTypeDefinition: NamedTypeDefinition) { | ||
typeWriter.writeNamedTypeDefinition(ionWriter, namedTypeDefinition) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.ionschema.writer.internal | ||
|
||
import com.amazon.ion.IonWriter | ||
import com.amazon.ionschema.IonSchemaVersion | ||
import com.amazon.ionschema.model.Constraint | ||
import com.amazon.ionschema.model.DiscreteIntRange | ||
import com.amazon.ionschema.model.ExperimentalIonSchemaModel | ||
import com.amazon.ionschema.model.NamedTypeDefinition | ||
import com.amazon.ionschema.model.OpenContentFields | ||
import com.amazon.ionschema.model.TypeArgument | ||
import com.amazon.ionschema.model.TypeDefinition | ||
import com.amazon.ionschema.model.VariablyOccurringTypeArgument | ||
import com.amazon.ionschema.writer.internal.constraints.AnnotationsV2Writer | ||
import com.amazon.ionschema.writer.internal.constraints.ContainsWriter | ||
import com.amazon.ionschema.writer.internal.constraints.ElementWriter | ||
import com.amazon.ionschema.writer.internal.constraints.ExponentWriter | ||
import com.amazon.ionschema.writer.internal.constraints.FieldNamesWriter | ||
import com.amazon.ionschema.writer.internal.constraints.FieldsWriter | ||
import com.amazon.ionschema.writer.internal.constraints.Ieee754FloatWriter | ||
import com.amazon.ionschema.writer.internal.constraints.LengthConstraintsWriter | ||
import com.amazon.ionschema.writer.internal.constraints.LogicConstraintsWriter | ||
import com.amazon.ionschema.writer.internal.constraints.OrderedElementsWriter | ||
import com.amazon.ionschema.writer.internal.constraints.PrecisionWriter | ||
import com.amazon.ionschema.writer.internal.constraints.RegexWriter | ||
import com.amazon.ionschema.writer.internal.constraints.TimestampOffsetWriter | ||
import com.amazon.ionschema.writer.internal.constraints.TimestampPrecisionWriter | ||
import com.amazon.ionschema.writer.internal.constraints.ValidValuesWriter | ||
|
||
@ExperimentalIonSchemaModel | ||
internal object TypeWriterV2_0 : TypeWriter { | ||
private val constraintWriters = listOf( | ||
AnnotationsV2Writer(this), | ||
ContainsWriter, | ||
ElementWriter(this, IonSchemaVersion.v2_0), | ||
ExponentWriter, | ||
FieldNamesWriter(this), | ||
FieldsWriter(this, IonSchemaVersion.v2_0), | ||
Ieee754FloatWriter, | ||
LengthConstraintsWriter, | ||
LogicConstraintsWriter(this), | ||
OrderedElementsWriter(this), | ||
PrecisionWriter, | ||
RegexWriter, | ||
TimestampOffsetWriter, | ||
TimestampPrecisionWriter, | ||
ValidValuesWriter, | ||
).flatMap { w -> w.supportedClasses.map { it to w } } | ||
.toMap() | ||
|
||
override fun writeNamedTypeDefinition(ionWriter: IonWriter, namedTypeDefinition: NamedTypeDefinition) { | ||
ionWriter.setTypeAnnotations("type") | ||
ionWriter.writeStruct { | ||
ionWriter.setFieldName("name") | ||
ionWriter.writeSymbol(namedTypeDefinition.typeName) | ||
writeConstraints(ionWriter, namedTypeDefinition.typeDefinition.constraints) | ||
writeOpenContent(ionWriter, namedTypeDefinition.typeDefinition.openContent) | ||
} | ||
} | ||
|
||
override fun writeTypeArg(ionWriter: IonWriter, typeArg: TypeArgument) { | ||
if (typeArg.nullability == TypeArgument.Nullability.OrNull) { | ||
ionWriter.addTypeAnnotation("\$null_or") | ||
} | ||
|
||
when (typeArg) { | ||
is TypeArgument.Import -> ionWriter.writeStruct { | ||
ionWriter.setFieldName("id") | ||
ionWriter.writeString(typeArg.schemaId) | ||
ionWriter.setFieldName("type") | ||
ionWriter.writeSymbol(typeArg.typeName) | ||
} | ||
is TypeArgument.InlineType -> ionWriter.writeStruct { | ||
writeConstraints(ionWriter, typeArg.typeDefinition.constraints) | ||
writeOpenContent(ionWriter, typeArg.typeDefinition.openContent) | ||
} | ||
is TypeArgument.Reference -> ionWriter.writeSymbol(typeArg.typeName) | ||
} | ||
} | ||
|
||
override fun writeVariablyOccurringTypeArg(ionWriter: IonWriter, varTypeArg: VariablyOccurringTypeArgument, elideOccursValue: DiscreteIntRange) { | ||
if (varTypeArg.occurs == elideOccursValue) { | ||
writeTypeArg(ionWriter, varTypeArg.typeArg) | ||
} else { | ||
ionWriter.writeStruct { | ||
setFieldName("occurs") | ||
writeRange(varTypeArg.occurs) | ||
if (varTypeArg.typeArg.nullability == TypeArgument.Nullability.None && varTypeArg.typeArg is TypeArgument.InlineType) { | ||
writeConstraints(ionWriter, varTypeArg.typeArg.typeDefinition.constraints) | ||
writeOpenContent(ionWriter, varTypeArg.typeArg.typeDefinition.openContent) | ||
} else { | ||
setFieldName("type") | ||
writeTypeArg(ionWriter, varTypeArg.typeArg) | ||
} | ||
Check warning on line 96 in ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/TypeWriterV2_0.kt Codecov / codecov/patchion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/TypeWriterV2_0.kt#L94-L96
|
||
} | ||
} | ||
} | ||
|
||
/** | ||
* Writes a type that exists outside the context of any schema. | ||
*/ | ||
fun writeOrphanedTypeDefinition(ionWriter: IonWriter, typeDefinition: TypeDefinition) { | ||
ionWriter.setTypeAnnotations("type") | ||
ionWriter.writeStruct { | ||
writeConstraints(ionWriter, typeDefinition.constraints) | ||
writeOpenContent(ionWriter, typeDefinition.openContent) | ||
} | ||
Check warning on line 109 in ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/TypeWriterV2_0.kt Codecov / codecov/patchion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/TypeWriterV2_0.kt#L105-L109
|
||
} | ||
|
||
private fun writeOpenContent(ionWriter: IonWriter, openContentFields: OpenContentFields) { | ||
for ((fieldName, fieldValue) in openContentFields) { | ||
ionWriter.setFieldName(fieldName) | ||
fieldValue.writeTo(ionWriter) | ||
} | ||
} | ||
|
||
private fun writeConstraints(ionWriter: IonWriter, constraints: Set<Constraint>) { | ||
for (c in constraints) { | ||
constraintWriters[c::class]?.writeTo(ionWriter, c) | ||
?: TODO("Constraint not supported in Ion Schema 2.0: ${c::class}") | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.ionschema.writer.internal | ||
|
||
import com.amazon.ion.IonWriter | ||
import com.amazon.ionschema.model.ExperimentalIonSchemaModel | ||
import com.amazon.ionschema.model.NamedTypeDefinition | ||
import com.amazon.ionschema.model.SchemaDocument | ||
import com.amazon.ionschema.model.TypeDefinition | ||
|
||
@OptIn(ExperimentalIonSchemaModel::class) | ||
interface VersionedIonSchemaWriter { | ||
/** | ||
* Writes a [SchemaDocument]. | ||
*/ | ||
fun writeSchema(ionWriter: IonWriter, schemaDocument: SchemaDocument) | ||
|
||
/** | ||
* Writes an orphaned [TypeDefinition]—that is an anonymous type definition that does not belong to any schema. | ||
*/ | ||
fun writeType(ionWriter: IonWriter, typeDefinition: TypeDefinition) | ||
|
||
/** | ||
* Writes a [NamedTypeDefinition]. | ||
*/ | ||
fun writeNamedType(ionWriter: IonWriter, namedTypeDefinition: NamedTypeDefinition) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.amazon.ionschema.writer | ||
|
||
import com.amazon.ionschema.ION | ||
import com.amazon.ionschema.IonSchemaVersion | ||
import com.amazon.ionschema.assertEqualIon | ||
import com.amazon.ionschema.model.ExperimentalIonSchemaModel | ||
import com.amazon.ionschema.model.SchemaDocument | ||
import org.junit.jupiter.api.Test | ||
import org.junit.jupiter.api.assertThrows | ||
|
||
@OptIn(ExperimentalIonSchemaModel::class) | ||
class IonSchemaWriterTest { | ||
// The purpose of these tests is just to check that it delegates to the correct writer implementation. | ||
// Testing the actual serialization is done in WriterTests.kt | ||
|
||
@Test | ||
fun `IonSchemaWriter throw UnsupportedOperationException for ISL 1 0`() { | ||
val writer = ION.newTextWriter(StringBuilder()) | ||
val schema = SchemaDocument("schema.isl", IonSchemaVersion.v1_0, emptyList()) | ||
assertThrows<NotImplementedError> { | ||
IonSchemaWriter.writeSchema(writer, schema) | ||
} | ||
} | ||
|
||
@Test | ||
fun `IonSchemaWriter writes a schema document for ISL 2 0`() { | ||
val schema = SchemaDocument("schema.isl", IonSchemaVersion.v2_0, emptyList()) | ||
// Since there's no content added to the schema, we expect just a version marker | ||
assertEqualIon("\$ion_schema_2_0 ") { | ||
IonSchemaWriter.writeSchema(it, schema) | ||
} | ||
} | ||
} |