-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Reworked mapping management and validation (#608)
* Reworked mapping management and validation + The collection of type mappings has moved to a new first class TypeMappings container type. There is an implicit conversion from List[TypeMapping] to TypeMappings, so this is a source compatible change (this will probably be deprecated in a later release). Most mapping validtion logic has been moved to TypeMappings, apart from mapping-specific rules (eg. for SqlMapping) which are delegated to the relevant Mapping subtype at the granularity of validity for individual type and field mappings. + Added MappingPredicate as an extensible mechanism for matching mappings to paths. TypeMatch replaces the existing Type linked association, PrefixedTypeMatch replaces the PrefixedMapping wrapper, and PathMatch corresponds to the the SwitchTypeMapping used by Gemini/Aura. + Mapping validation is now performed by default unless explicitly disabled. Validation is deferred until the mappings compiler is first referenced (to avoid init-order issues, object initialization errors and poor interatactions of the latter with munit-cats-effect) and is performed exactly once. Applications which have at least one guery unit test will trigger validation failures automatically at test time. + The validation algorithm has been reworked to start from the GraphQL schema and generate an exhaustive set of paths which are used to determine the relevant mappings to check against GraphQL and DB schema types. The support both traversal through mappings which are partly implicit (eg. the Circe and GenericMappings) and also accomodate mappings which are guarded by MappingPredicates. + The base mapping validator now also reports unused (ie. not reachable via any valid path in the GraphQL schema) type and field mappings. + The SQL mapping validator tests for, + Consistency of nullability and Scala type between GraphQL and SQL. + Leaf/ObjectMapping consistency with GraphQL leaf or non-leaf types. + Objects, interfaces and unions being nested within single a single DB table. + Associative fields also being keys. + Union field mappings must be hidden and leaf. + Embedded subobjects must be nested in their parent object table. + Joins must have at least one join condition. + Parallel joins must relate the same tables. + Serial joins must chain correctly. + Type mappings with non-trivial predicates are now indexed. + LeafMapping now supports MappingPrediates and are indexed along with ObjectMappings. + Built-in Scalar types now have explicit LeafMappings and can now be specialized for particular contexts via MappingPredicates. + Added a subtree Boolean attribute to FieldMapping to signal that a field value can represent structured result subtrees which are not explicitly mapped at all levels. This allows mapping validation to include the Circe and Generic mappings which implicitly map subtrees. + The ValueObjectMapping has a new on constructor and the withParent initializer method, which was present on all mappings has been removed and replaced by the ValueFieldMapping specific unwrap. + The IntrospectionMapping now uses the new mapping API. + All tests have been updated so validate under the new scheme. + The Doobie and Skunk test suites now have typed codecs which can capture the metadata needed for validation. + The tutorial and demo and profile projects have been updated to the new API. + Added schema validation checks to ensure interfaces are non-cyclic. + Added forUnderlyingNamed convenience method to Context. + ValidationFailure split out to a separate file. + The sql classifier has been moved from ValidationFailure to a SqlValidationFailure subtype. + GraphQL types menioned in ValidationFailure error messages are now correctly rendered uing GraphQL syntax. + ComposedMapping has been split out to a separate file. + Various signatures previously using List now use Seq. * Factored factored out MappingPredicate logic * Added missing implicit SourcePos argument * Tone down the severity indicators * Fixed typos * fix pathmatch * Typeref#withSchema * Compute base Scala type name for opt Skunk Codecs * Remove TypeRef#withSchema, use Schema#uncheckedRef instead * Add support for narrowing interfaces and unions along Paths * Added Path-based type mapping constructors * Report ambiguous mappings --------- Co-authored-by: Rob Norris <rob_norris@mac.com>
- Loading branch information
1 parent
e4b64a5
commit 61941a7
Showing
57 changed files
with
3,539 additions
and
1,061 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// Copyright (c) 2016-2023 Association of Universities for Research in Astronomy, Inc. (AURA) | ||
// Copyright (c) 2016-2023 Grackle Contributors | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package grackle | ||
|
||
import cats.MonadThrow | ||
|
||
import Cursor.AbstractCursor | ||
import syntax._ | ||
|
||
abstract class ComposedMapping[F[_]](implicit val M: MonadThrow[F]) extends Mapping[F] { | ||
override def mkCursorForField(parent: Cursor, fieldName: String, resultName: Option[String]): Result[Cursor] = { | ||
val context = parent.context | ||
val fieldContext = context.forFieldOrAttribute(fieldName, resultName) | ||
typeMappings.fieldMapping(context, fieldName) match { | ||
case Some(_) => | ||
ComposedCursor(fieldContext, parent.env).success | ||
case _ => | ||
super.mkCursorForField(parent, fieldName, resultName) | ||
} | ||
} | ||
|
||
case class ComposedCursor(context: Context, env: Env) extends AbstractCursor { | ||
val focus = null | ||
val parent = None | ||
|
||
def withEnv(env0: Env): Cursor = copy(env = env.add(env0)) | ||
|
||
override def hasField(fieldName: String): Boolean = | ||
typeMappings.fieldMapping(context, fieldName).isDefined | ||
|
||
override def field(fieldName: String, resultName: Option[String]): Result[Cursor] = | ||
mkCursorForField(this, fieldName, resultName) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.