Skip to content

Commit

Permalink
Update reader APIs
Browse files Browse the repository at this point in the history
  • Loading branch information
popematt committed Oct 26, 2023
1 parent db871db commit b62c044
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 58 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
package com.amazon.ionschema.reader

import com.amazon.ion.IonSymbol
import com.amazon.ion.IonValue
import com.amazon.ionschema.IonSchemaVersion
import com.amazon.ionschema.model.ExperimentalIonSchemaModel
import com.amazon.ionschema.model.NamedTypeDefinition
import com.amazon.ionschema.model.SchemaDocument
import com.amazon.ionschema.model.TypeDefinition
import com.amazon.ionschema.reader.internal.IonSchemaReaderV2_0
import com.amazon.ionschema.reader.internal.ReadError
import com.amazon.ionschema.reader.internal.VersionedIonSchemaReader
import com.amazon.ionschema.util.IonSchemaResult

/**
* Reads IonValues into the Ion Schema model.
*/
@ExperimentalIonSchemaModel
interface IonSchemaReader {
object IonSchemaReader {
/**
* Attempts to read a [SchemaDocument]. Returns an [IonSchemaResult] containing either a [SchemaDocument] or a list
* of [ReadError]s that were encountered.
Expand All @@ -21,44 +23,31 @@ interface IonSchemaReader {
* the given Ion. Reporting all errors is a best-effort attempt because the presence of one error can mask other
* errors.
*/
fun readSchema(document: Iterable<IonValue>, failFast: Boolean = false): IonSchemaResult<SchemaDocument, List<ReadError>>
@JvmStatic
@JvmOverloads
fun readSchema(document: Iterable<IonValue>, failFast: Boolean = false): IonSchemaResult<SchemaDocument, List<ReadError>> {
val maybeVersion = document
.firstOrNull {

Check warning on line 30 in ion-schema/src/main/kotlin/com/amazon/ionschema/reader/IonSchemaReader.kt

View check run for this annotation

Codecov / codecov/patch

ion-schema/src/main/kotlin/com/amazon/ionschema/reader/IonSchemaReader.kt#L28-L30

Added lines #L28 - L30 were not covered by tests
(it is IonSymbol && !it.isNullValue && IonSchemaVersion.fromIonSymbolOrNull(it) != null) ||
it.hasTypeAnnotation("schema_header") ||
it.hasTypeAnnotation("schema_footer") ||
it.hasTypeAnnotation("type")
}

val version = maybeVersion

Check warning on line 37 in ion-schema/src/main/kotlin/com/amazon/ionschema/reader/IonSchemaReader.kt

View check run for this annotation

Codecov / codecov/patch

ion-schema/src/main/kotlin/com/amazon/ionschema/reader/IonSchemaReader.kt#L37

Added line #L37 was not covered by tests
?.let { if (it is IonSymbol) IonSchemaVersion.fromIonSymbolOrNull(it) else null }
?: IonSchemaVersion.v1_0

Check warning on line 39 in ion-schema/src/main/kotlin/com/amazon/ionschema/reader/IonSchemaReader.kt

View check run for this annotation

Codecov / codecov/patch

ion-schema/src/main/kotlin/com/amazon/ionschema/reader/IonSchemaReader.kt#L39

Added line #L39 was not covered by tests

val delegate: VersionedIonSchemaReader = when (version) {
IonSchemaVersion.v1_0 -> TODO("IonSchemaReader does not support Ion Schema 1.0 yet.")
IonSchemaVersion.v2_0 -> IonSchemaReaderV2_0

Check warning on line 43 in ion-schema/src/main/kotlin/com/amazon/ionschema/reader/IonSchemaReader.kt

View check run for this annotation

Codecov / codecov/patch

ion-schema/src/main/kotlin/com/amazon/ionschema/reader/IonSchemaReader.kt#L42-L43

Added lines #L42 - L43 were not covered by tests
}
return delegate.readSchema(document, failFast)

Check warning on line 45 in ion-schema/src/main/kotlin/com/amazon/ionschema/reader/IonSchemaReader.kt

View check run for this annotation

Codecov / codecov/patch

ion-schema/src/main/kotlin/com/amazon/ionschema/reader/IonSchemaReader.kt#L45

Added line #L45 was not covered by tests
}

/**
* Reads a [SchemaDocument], throwing an [InvalidSchemaException][com.amazon.ionschema.InvalidSchemaException]
* if the Ion value is not a valid Ion Schema Language schema document.
*/
fun readSchemaOrThrow(document: List<IonValue>) = readSchema(document, true).unwrap()

/**
* Reads an orphaned [TypeDefinition]—that is an anonymous type definition that does not belong to any schema.
* Returns an [IonSchemaResult] containing either a [TypeDefinition] or a list of [ReadError]s that were encountered.
*
* If [failFast] is true, returns once a single error has been detected. Otherwise, attempts to report all errors in
* the given Ion. Reporting all errors is a best-effort attempt because the presence of one error can mask other
* errors.
*/
fun readType(ion: IonValue, failFast: Boolean = false): IonSchemaResult<TypeDefinition, List<ReadError>>

/**
* Reads an orphaned [TypeDefinition]—that is an anonymous type definition that does not belong to any schema—
* throwing an [InvalidSchemaException][com.amazon.ionschema.InvalidSchemaException] if the Ion value is not a valid
* Ion Schema type definition.
*/
fun readTypeOrThrow(ion: IonValue) = readType(ion, true).unwrap()

/**
* Reads a [NamedTypeDefinition]. Returns an [IonSchemaResult] containing either a [NamedTypeDefinition] or a list
* of [ReadError]s that were encountered.
*
* If [failFast] is true, returns once a single error has been detected. Otherwise, attempts to report all errors in
* the given Ion. Reporting all errors is a best-effort attempt because the presence of one error can mask other
* errors.
*/
fun readNamedType(ion: IonValue, failFast: Boolean = false): IonSchemaResult<NamedTypeDefinition, List<ReadError>>

/**
* Reads a [NamedTypeDefinition], throwing an [InvalidSchemaException][com.amazon.ionschema.InvalidSchemaException]
* if the Ion value is not a valid Ion Schema named type definition.
*/
fun readNamedTypeOrThrow(ion: IonValue) = readNamedType(ion, true).unwrap()
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
package com.amazon.ionschema.reader
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package com.amazon.ionschema.reader.internal

import com.amazon.ion.IonValue
import com.amazon.ionschema.InvalidSchemaException
Expand All @@ -9,20 +12,10 @@ import com.amazon.ionschema.model.ExperimentalIonSchemaModel
import com.amazon.ionschema.model.NamedTypeDefinition
import com.amazon.ionschema.model.SchemaDocument
import com.amazon.ionschema.model.TypeDefinition
import com.amazon.ionschema.reader.internal.FooterReader
import com.amazon.ionschema.reader.internal.HeaderReader
import com.amazon.ionschema.reader.internal.ReadError
import com.amazon.ionschema.reader.internal.ReaderContext
import com.amazon.ionschema.reader.internal.TypeReaderV2_0
import com.amazon.ionschema.reader.internal.isFooter
import com.amazon.ionschema.reader.internal.isHeader
import com.amazon.ionschema.reader.internal.isTopLevelOpenContent
import com.amazon.ionschema.reader.internal.isType
import com.amazon.ionschema.reader.internal.readCatching
import com.amazon.ionschema.util.IonSchemaResult

@OptIn(ExperimentalIonSchemaModel::class)
class IonSchemaReaderV2_0 : IonSchemaReader {
internal object IonSchemaReaderV2_0 : VersionedIonSchemaReader {
private val typeReader = TypeReaderV2_0()
private val headerReader = HeaderReader(IonSchemaVersion.v2_0)
private val footerReader = FooterReader { it in userReservedFields.footer || !IonSchema_2_0.RESERVED_WORDS_REGEX.matches(it) }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

package com.amazon.ionschema.reader.internal

import com.amazon.ion.IonValue
import com.amazon.ionschema.model.ExperimentalIonSchemaModel
import com.amazon.ionschema.model.NamedTypeDefinition
import com.amazon.ionschema.model.SchemaDocument
import com.amazon.ionschema.model.TypeDefinition
import com.amazon.ionschema.util.IonSchemaResult

/**
* Reads IonValues into the Ion Schema model.
*/
@ExperimentalIonSchemaModel
interface VersionedIonSchemaReader {
/**
* Attempts to read a [SchemaDocument]. Returns an [IonSchemaResult] containing either a [SchemaDocument] or a list
* of [ReadError]s that were encountered.
*
* If [failFast] is true, returns once a single error has been detected. Otherwise, attempts to report all errors in
* the given Ion. Reporting all errors is a best-effort attempt because the presence of one error can mask other
* errors.
*/
fun readSchema(document: Iterable<IonValue>, failFast: Boolean = false): IonSchemaResult<SchemaDocument, List<ReadError>>

/**
* Reads a [SchemaDocument], throwing an [InvalidSchemaException][com.amazon.ionschema.InvalidSchemaException]
* if the Ion value is not a valid Ion Schema Language schema document.
*/
fun readSchemaOrThrow(document: List<IonValue>) = readSchema(document, true).unwrap()

/**
* Reads an orphaned [TypeDefinition]—that is an anonymous type definition that does not belong to any schema.
* Returns an [IonSchemaResult] containing either a [TypeDefinition] or a list of [ReadError]s that were encountered.
*
* If [failFast] is true, returns once a single error has been detected. Otherwise, attempts to report all errors in
* the given Ion. Reporting all errors is a best-effort attempt because the presence of one error can mask other
* errors.
*/
fun readType(ion: IonValue, failFast: Boolean = false): IonSchemaResult<TypeDefinition, List<ReadError>>

/**
* Reads an orphaned [TypeDefinition]—that is an anonymous type definition that does not belong to any schema—
* throwing an [InvalidSchemaException][com.amazon.ionschema.InvalidSchemaException] if the Ion value is not a valid
* Ion Schema type definition.
*/
fun readTypeOrThrow(ion: IonValue) = readType(ion, true).unwrap()

/**
* Reads a [NamedTypeDefinition]. Returns an [IonSchemaResult] containing either a [NamedTypeDefinition] or a list
* of [ReadError]s that were encountered.
*
* If [failFast] is true, returns once a single error has been detected. Otherwise, attempts to report all errors in
* the given Ion. Reporting all errors is a best-effort attempt because the presence of one error can mask other
* errors.
*/
fun readNamedType(ion: IonValue, failFast: Boolean = false): IonSchemaResult<NamedTypeDefinition, List<ReadError>>

/**
* Reads a [NamedTypeDefinition], throwing an [InvalidSchemaException][com.amazon.ionschema.InvalidSchemaException]
* if the Ion value is not a valid Ion Schema named type definition.
*/
fun readNamedTypeOrThrow(ion: IonValue) = readNamedType(ion, true).unwrap()
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import com.amazon.ionschema.model.SchemaDocument
import com.amazon.ionschema.model.TypeArgument
import com.amazon.ionschema.model.TypeDefinition
import com.amazon.ionschema.model.ValidValue
import com.amazon.ionschema.reader.IonSchemaReaderV2_0
import com.amazon.ionschema.reader.internal.IonSchemaReaderV2_0
import java.io.File

/**
Expand Down Expand Up @@ -66,7 +66,7 @@ object SchemaSymbolsUtil {
@JvmStatic
@OptIn(ExperimentalIonSchemaModel::class)
fun getSymbolsTextForSchema(schema: Schema): Set<String> {
return IonSchemaReaderV2_0().readSchemaOrThrow(schema.isl).getAllSymbolsText()
return IonSchemaReaderV2_0.readSchemaOrThrow(schema.isl).getAllSymbolsText()
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.amazon.ionschema.model.SchemaHeader
import com.amazon.ionschema.model.TypeArgument
import com.amazon.ionschema.model.TypeDefinition
import com.amazon.ionschema.model.UserReservedFields
import com.amazon.ionschema.reader.internal.IonSchemaReaderV2_0
import com.amazon.ionschema.util.emptyBag
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
Expand All @@ -24,7 +25,7 @@ import kotlin.test.assertEquals
class IonSchemaReaderV2_0Tests {

val ION = IonSystemBuilder.standard().build()
val reader = IonSchemaReaderV2_0()
private val reader = IonSchemaReaderV2_0
val typeTextWithMultipleErrors = """
type::{
valid_values: until_recently::["Ni!"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import com.amazon.ionschema.TestFactory
import com.amazon.ionschema.asDocument
import com.amazon.ionschema.getTextField
import com.amazon.ionschema.model.ExperimentalIonSchemaModel
import com.amazon.ionschema.reader.internal.IonSchemaReaderV2_0
import com.amazon.ionschema.reader.internal.VersionedIonSchemaReader
import org.junit.jupiter.api.DynamicContainer
import org.junit.jupiter.api.DynamicNode
import org.junit.jupiter.api.DynamicTest
Expand Down Expand Up @@ -44,15 +46,15 @@ class ReaderTests {
@Nested
inner class IonSchema_2_0 : TestFactory by ReaderTestsRunner(
version = IonSchemaVersion.v2_0,
reader = IonSchemaReaderV2_0(),
reader = IonSchemaReaderV2_0,
testNameFilter = { it !in ISL_2_0_EXPECTED_TO_NOT_PASS }
)
}

@ExperimentalIonSchemaModel
class ReaderTestsRunner(
val version: IonSchemaVersion,
val reader: IonSchemaReader,
val reader: VersionedIonSchemaReader,
additionalFileFilter: (File) -> Boolean = { true },
private val testNameFilter: (String) -> Boolean = { true },
) : TestFactory {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import com.amazon.ionschema.TestFactory
import com.amazon.ionschema.asDocument
import com.amazon.ionschema.getTextField
import com.amazon.ionschema.model.ExperimentalIonSchemaModel
import com.amazon.ionschema.reader.IonSchemaReader
import com.amazon.ionschema.reader.IonSchemaReaderV2_0
import com.amazon.ionschema.reader.internal.IonSchemaReaderV2_0
import com.amazon.ionschema.reader.internal.VersionedIonSchemaReader
import com.amazon.ionschema.writer.internal.IonSchemaWriterV2_0
import com.amazon.ionschema.writer.internal.VersionedIonSchemaWriter
import org.junit.jupiter.api.Assertions.assertEquals
Expand All @@ -32,15 +32,15 @@ class WriterTests {
@Nested
inner class IonSchema_2_0 : TestFactory by WriterTestsRunner(
version = IonSchemaVersion.v2_0,
reader = IonSchemaReaderV2_0(),
reader = IonSchemaReaderV2_0,
writer = IonSchemaWriterV2_0,
)
}

@ExperimentalIonSchemaModel
class WriterTestsRunner(
val version: IonSchemaVersion,
val reader: IonSchemaReader,
val reader: VersionedIonSchemaReader,
val writer: VersionedIonSchemaWriter,
additionalFileFilter: (File) -> Boolean = { true },
private val testNameFilter: (String) -> Boolean = { true },
Expand Down

0 comments on commit b62c044

Please sign in to comment.