-
Notifications
You must be signed in to change notification settings - Fork 154
Preview: Introduce Result, Record and Graph types mapping #1248
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
MaxAake
wants to merge
59
commits into
6.x
Choose a base branch
from
5.x-high-level-hydration
base: 6.x
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains hidden or 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
5ac8467
to
2e2295a
Compare
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Continues work by @bigmontz in #1159
⚠️ This a preview feature
Getting Started
Let's say we have the following Cypher query:
and we are going to load each of the records into Typescript objects like these:
Each record in the results will result in an instance of
ActingJob
with the properties populated from the query results and type validation.To do this at present, you would write something like the following:
Using the new mapping functionality, the same result will be achieved using the following code:
The mapping will be done by combining rules definition and object properties created by the constructors. It's not necessary to use both (constructor and rules), but the usage of one of them is needed if you need a filled object since properties not present in instantiated object or rules are ignored by the method.
For example, if values present in the
Movie
andPerson
objects are never null and no validation is needed. The code to process the result can be changed to:Another possible scenario is
Movie
,Person
andActingJobs
be just typescript interfaces. The code to process the result can be changed to:Note: In this scenario, the
ActingJobs
interface is set to the transformer for auto-complete and code validation, however this is not treated as an object constructor.Mapping from
Result
methodResult.as
is introduced to the result for enable the mapping occur in the result.Same rules of usage of constructor and rules are share with the
hydrated
result transformer`.Direct mapping from an
Record
,Node
andRelationship
instance.Record.as
,Node.as
andRelationship.as
are introduced to enable the mapping of these types only.Same rules of usage of constructor and rules are share with the
hydrated
result transformer`.Note: In
Node
andRelationship
only properties are mapped._Note: Properties not present in the
Record
will throw error sinceRecord.get
is used under the hood. However, properties which present and with value equals tonull
orundefined
will only throw error when property is not defined as optional in the rules.Rules and Built-in Rules Factory
The driver provides Rule Factories for all data types which can be returned form a query.
There is no need for creating custom rules in most of cases.
However, all the built-in rules are extensible.
The Rule interface is defined as:
where
optional
(default: false): indicates with value accept undefined/null as value.In this case, the
convert
method will not be called.from
(default: property name on the Rules object): indicates from which field on the Record, Node or Relationship the value will came from.Used for cases where the property name in domain object is different to the one present in the database.
convert
: called to convert value to the domain value.Called after value be validated.
If optional is true and the value is null or undefined, the method is not called.
validate
: called to validate if values is valid.Called before convert and after check if the value is optional.
If optional is true and the value is null or undefined, the method is not called.
This feature also includes a rules registry, allowing types to be linked to rules so that they do not need to be provided every time a result is transformed. The rules registry is stored in global memory, and not linked to a specific instance of the driver.
Running the query:
An alternative to manually writing rules for a type is also available for typescript 5.2+ users: Decorators with metadata.
NOTE: Many runtimes do not yet fully support decorator metadata. For users of Node.js the following line:
(Symbol as { metadata: symbol }).metadata ??= Symbol('Symbol.metadata');
will polyfill theSymbol.metadata
property. Without this polyfill or a runtime that otherwise supports symbol metadata, these decorators will not function.The above code will both define classes and register rules for them in the rules registry. The order of the decorators is important, with the type expected closest to the property, optional/conversion above that, and the listProperty() decorator on top if the property is a list.