diff --git a/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/AnnotationsV2Writer.kt b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/AnnotationsV2Writer.kt new file mode 100644 index 0000000..a2a54e4 --- /dev/null +++ b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/AnnotationsV2Writer.kt @@ -0,0 +1,39 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ion.IonWriter +import com.amazon.ionschema.model.Constraint +import com.amazon.ionschema.model.Constraint.AnnotationsV2.Modifier.Closed +import com.amazon.ionschema.model.Constraint.AnnotationsV2.Modifier.Exact +import com.amazon.ionschema.model.Constraint.AnnotationsV2.Modifier.Required +import com.amazon.ionschema.model.ExperimentalIonSchemaModel +import com.amazon.ionschema.writer.internal.TypeWriter +import com.amazon.ionschema.writer.internal.writeToList + +@ExperimentalIonSchemaModel +internal class AnnotationsV2Writer(private val typeWriter: TypeWriter) : ConstraintWriter { + + override val supportedClasses = setOf( + Constraint.AnnotationsV2.Simplified::class, + Constraint.AnnotationsV2.Standard::class + ) + + override fun IonWriter.write(c: Constraint) { + check(c is Constraint.AnnotationsV2) + + setFieldName("annotations") + when (c) { + is Constraint.AnnotationsV2.Standard -> typeWriter.writeTypeArg(this, c.type) + is Constraint.AnnotationsV2.Simplified -> { + when (c.modifier) { + Closed -> setTypeAnnotations("closed") + Required -> setTypeAnnotations("required") + Exact -> setTypeAnnotations("closed", "required") + } + writeToList(c.annotations) { writeSymbol(it) } + } + } + } +} diff --git a/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/ContainsWriter.kt b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/ContainsWriter.kt new file mode 100644 index 0000000..dcf2261 --- /dev/null +++ b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/ContainsWriter.kt @@ -0,0 +1,21 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ion.IonWriter +import com.amazon.ionschema.model.Constraint +import com.amazon.ionschema.model.ExperimentalIonSchemaModel +import com.amazon.ionschema.writer.internal.writeIonValue +import com.amazon.ionschema.writer.internal.writeToList + +@ExperimentalIonSchemaModel +internal object ContainsWriter : ConstraintWriter { + override val supportedClasses = setOf(Constraint.Contains::class) + + override fun IonWriter.write(c: Constraint) { + check(c is Constraint.Contains) + setFieldName("contains") + writeToList(c.values) { writeIonValue(it) } + } +} diff --git a/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/ElementWriter.kt b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/ElementWriter.kt new file mode 100644 index 0000000..b506380 --- /dev/null +++ b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/ElementWriter.kt @@ -0,0 +1,30 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ion.IonWriter +import com.amazon.ionschema.IonSchemaException +import com.amazon.ionschema.IonSchemaVersion +import com.amazon.ionschema.model.Constraint +import com.amazon.ionschema.model.ExperimentalIonSchemaModel +import com.amazon.ionschema.writer.internal.TypeWriter + +@ExperimentalIonSchemaModel +internal class ElementWriter(private val typeWriter: TypeWriter, private val ionSchemaVersion: IonSchemaVersion) : ConstraintWriter { + override val supportedClasses = setOf(Constraint.Element::class) + + override fun IonWriter.write(c: Constraint) { + check(c is Constraint.Element) + + setFieldName("element") + if (c.distinct) { + if (ionSchemaVersion == IonSchemaVersion.v1_0) { + throw IonSchemaException("Ion Schema 1.0 does not support 'distinct' elements") + } else { + setTypeAnnotations("distinct") + } + } + typeWriter.writeTypeArg(this@write, c.type) + } +} diff --git a/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/FieldNamesWriter.kt b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/FieldNamesWriter.kt new file mode 100644 index 0000000..83e4e38 --- /dev/null +++ b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/FieldNamesWriter.kt @@ -0,0 +1,23 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ion.IonWriter +import com.amazon.ionschema.model.Constraint +import com.amazon.ionschema.model.ExperimentalIonSchemaModel +import com.amazon.ionschema.writer.internal.TypeWriter + +@ExperimentalIonSchemaModel +internal class FieldNamesWriter(private val typeWriter: TypeWriter) : ConstraintWriter { + override val supportedClasses = setOf(Constraint.FieldNames::class) + + override fun IonWriter.write(c: Constraint) { + check(c is Constraint.FieldNames) + setFieldName("field_names") + if (c.distinct) { + setTypeAnnotations("distinct") + } + typeWriter.writeTypeArg(this@write, c.type) + } +} diff --git a/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/Ieee754FloatWriter.kt b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/Ieee754FloatWriter.kt new file mode 100644 index 0000000..8db8a27 --- /dev/null +++ b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/Ieee754FloatWriter.kt @@ -0,0 +1,19 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ion.IonWriter +import com.amazon.ionschema.model.Constraint +import com.amazon.ionschema.model.ExperimentalIonSchemaModel + +@ExperimentalIonSchemaModel +object Ieee754FloatWriter : ConstraintWriter { + override val supportedClasses = setOf(Constraint.Ieee754Float::class) + + override fun IonWriter.write(c: Constraint) { + check(c is Constraint.Ieee754Float) + setFieldName("ieee754_float") + writeSymbol(c.format.symbolText) + } +} diff --git a/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/RegexWriter.kt b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/RegexWriter.kt new file mode 100644 index 0000000..24b4d84 --- /dev/null +++ b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/RegexWriter.kt @@ -0,0 +1,21 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ion.IonWriter +import com.amazon.ionschema.model.Constraint +import com.amazon.ionschema.model.ExperimentalIonSchemaModel + +@ExperimentalIonSchemaModel +internal object RegexWriter : ConstraintWriter { + override val supportedClasses = setOf(Constraint.Regex::class) + + override fun IonWriter.write(c: Constraint) { + check(c is Constraint.Regex) + setFieldName("regex") + if (c.caseInsensitive) addTypeAnnotation("i") + if (c.multiline) addTypeAnnotation("m") + writeString(c.pattern) + } +} diff --git a/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/TimestampOffsetWriter.kt b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/TimestampOffsetWriter.kt new file mode 100644 index 0000000..14e1fef --- /dev/null +++ b/ion-schema/src/main/kotlin/com/amazon/ionschema/writer/internal/constraints/TimestampOffsetWriter.kt @@ -0,0 +1,20 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ion.IonWriter +import com.amazon.ionschema.model.Constraint +import com.amazon.ionschema.model.ExperimentalIonSchemaModel +import com.amazon.ionschema.writer.internal.writeToList + +@ExperimentalIonSchemaModel +internal object TimestampOffsetWriter : ConstraintWriter { + override val supportedClasses = setOf(Constraint.TimestampOffset::class) + + override fun IonWriter.write(c: Constraint) { + check(c is Constraint.TimestampOffset) + setFieldName("timestamp_offset") + writeToList(c.offsets) { writeString(it.toString()) } + } +} diff --git a/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/AnnotationsV2WriterTest.kt b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/AnnotationsV2WriterTest.kt new file mode 100644 index 0000000..f484add --- /dev/null +++ b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/AnnotationsV2WriterTest.kt @@ -0,0 +1,24 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ionschema.model.Constraint.AnnotationsV2 +import com.amazon.ionschema.model.Constraint.AnnotationsV2.Modifier +import com.amazon.ionschema.model.ExperimentalIonSchemaModel +import com.amazon.ionschema.model.TypeArgument + +@OptIn(ExperimentalIonSchemaModel::class) +class AnnotationsV2WriterTest : ConstraintTestBase( + writer = AnnotationsV2Writer(stubTypeWriterWithRefs("foo_type")), + expectedConstraints = setOf( + AnnotationsV2.Simplified::class, + AnnotationsV2.Standard::class, + ), + writeTestCases = listOf( + AnnotationsV2.Standard(TypeArgument.Reference("foo_type")) to "annotations: foo_type", + AnnotationsV2.Simplified(Modifier.Closed, setOf("a")) to "annotations: closed::[a]", + AnnotationsV2.Simplified(Modifier.Required, setOf("b")) to "annotations: required::[b]", + AnnotationsV2.Simplified(Modifier.Exact, setOf("c")) to "annotations: closed::required::[c]", + ) +) diff --git a/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/ContainsWriterTest.kt b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/ContainsWriterTest.kt new file mode 100644 index 0000000..2717588 --- /dev/null +++ b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/ContainsWriterTest.kt @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ionschema.model.Constraint.Contains +import com.amazon.ionschema.model.ExperimentalIonSchemaModel + +@OptIn(ExperimentalIonSchemaModel::class) +class ContainsWriterTest : ConstraintTestBase( + writer = ContainsWriter, + expectedConstraints = setOf(Contains::class), + writeTestCases = listOf( + Contains(emptySet()) to "contains: []", + Contains(setOf(ion("[foo, true]"), ion("bar"))) to "contains: [[foo, true], bar]", + Contains(setOf(ion("me::2"), ion("null.timestamp"), ion("{a:b}"))) to "contains: [me::2, null.timestamp, {a:b}]", + ) +) diff --git a/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/ElementWriterTest.kt b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/ElementWriterTest.kt new file mode 100644 index 0000000..67f99a8 --- /dev/null +++ b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/ElementWriterTest.kt @@ -0,0 +1,32 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ionschema.IonSchemaException +import com.amazon.ionschema.IonSchemaVersion +import com.amazon.ionschema.model.Constraint +import com.amazon.ionschema.model.ExperimentalIonSchemaModel +import com.amazon.ionschema.model.TypeArgument +import io.mockk.mockk +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows + +@OptIn(ExperimentalIonSchemaModel::class) +class ElementWriterTest : ConstraintTestBase( + writer = ElementWriter(stubTypeWriterWithRefs("foo_type"), IonSchemaVersion.v2_0), + expectedConstraints = setOf(Constraint.Element::class), + writeTestCases = listOf( + Constraint.Element(TypeArgument.Reference("foo_type")) to "element: foo_type", + Constraint.Element(TypeArgument.Reference("foo_type"), distinct = true) to "element: distinct::foo_type", + ) +) { + @Test + fun `writer should throw exception when distinct = true and version = v1_0`() { + val writer = ElementWriter(stubTypeWriterWithRefs("foo_type"), IonSchemaVersion.v1_0) + val constraint = Constraint.Element(TypeArgument.Reference("foo_type"), distinct = true) + assertThrows { + writer.writeTo(mockk(relaxed = true), constraint) + } + } +} diff --git a/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/FieldNamesWriterTest.kt b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/FieldNamesWriterTest.kt new file mode 100644 index 0000000..6899043 --- /dev/null +++ b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/FieldNamesWriterTest.kt @@ -0,0 +1,18 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ionschema.model.Constraint +import com.amazon.ionschema.model.ExperimentalIonSchemaModel +import com.amazon.ionschema.model.TypeArgument + +@OptIn(ExperimentalIonSchemaModel::class) +class FieldNamesWriterTest : ConstraintTestBase( + writer = FieldNamesWriter(stubTypeWriterWithRefs("foo_type")), + expectedConstraints = setOf(Constraint.FieldNames::class), + writeTestCases = listOf( + Constraint.FieldNames(TypeArgument.Reference("foo_type")) to "field_names: foo_type", + Constraint.FieldNames(TypeArgument.Reference("foo_type"), distinct = true) to "field_names: distinct::foo_type", + ) +) diff --git a/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/Ieee754FloatWriterTest.kt b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/Ieee754FloatWriterTest.kt new file mode 100644 index 0000000..5139569 --- /dev/null +++ b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/Ieee754FloatWriterTest.kt @@ -0,0 +1,19 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ionschema.model.Constraint +import com.amazon.ionschema.model.ExperimentalIonSchemaModel +import com.amazon.ionschema.model.Ieee754InterchangeFormat + +@OptIn(ExperimentalIonSchemaModel::class) +class Ieee754FloatWriterTest : ConstraintTestBase( + writer = Ieee754FloatWriter, + expectedConstraints = setOf(Constraint.Ieee754Float::class), + writeTestCases = listOf( + Constraint.Ieee754Float(Ieee754InterchangeFormat.Binary16) to "ieee754_float: binary16", + Constraint.Ieee754Float(Ieee754InterchangeFormat.Binary32) to "ieee754_float: binary32", + Constraint.Ieee754Float(Ieee754InterchangeFormat.Binary64) to "ieee754_float: binary64", + ) +) diff --git a/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/RegexWriterTest.kt b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/RegexWriterTest.kt new file mode 100644 index 0000000..3037505 --- /dev/null +++ b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/RegexWriterTest.kt @@ -0,0 +1,19 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ionschema.model.Constraint +import com.amazon.ionschema.model.ExperimentalIonSchemaModel + +@OptIn(ExperimentalIonSchemaModel::class) +class RegexWriterTest : ConstraintTestBase( + writer = RegexWriter, + expectedConstraints = setOf(Constraint.Regex::class), + writeTestCases = listOf( + Constraint.Regex("abc") to """ regex: "abc" """, + Constraint.Regex("abc", multiline = true) to """ regex: m::"abc" """, + Constraint.Regex("abc", caseInsensitive = true) to """ regex: i::"abc" """, + Constraint.Regex("abc", true, true) to """ regex: i::m::"abc" """, + ) +) diff --git a/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/TimestampOffsetWriterTest.kt b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/TimestampOffsetWriterTest.kt new file mode 100644 index 0000000..c42200e --- /dev/null +++ b/ion-schema/src/test/kotlin/com/amazon/ionschema/writer/internal/constraints/TimestampOffsetWriterTest.kt @@ -0,0 +1,19 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.amazon.ionschema.writer.internal.constraints + +import com.amazon.ionschema.model.Constraint.TimestampOffset +import com.amazon.ionschema.model.ExperimentalIonSchemaModel +import com.amazon.ionschema.model.TimestampOffsetValue.Companion.parse + +@OptIn(ExperimentalIonSchemaModel::class) +class TimestampOffsetWriterTest : ConstraintTestBase( + writer = TimestampOffsetWriter, + expectedConstraints = setOf(TimestampOffset::class), + writeTestCases = listOf( + TimestampOffset(emptySet()) to "timestamp_offset: []", + TimestampOffset(setOf(parse("+01:23"))) to """ timestamp_offset: ["+01:23"] """, + TimestampOffset(setOf(parse("+01:23"), parse("-04:56"))) to """ timestamp_offset: ["+01:23", "-04:56"] """, + ) +)