-
Notifications
You must be signed in to change notification settings - Fork 20
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
Rework of the Shape type system #102
Merged
Merged
Conversation
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
… of recursive applications
sam-goodwin
commented
Jan 30, 2020
[K in keyof T]: Value.Of<T[K]>; | ||
}) { | ||
for (const [name, value] of Object.entries(values)) { | ||
(this as any)[name] = value; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should only copy values for this class's properties and also validate them for optional/required/constraints etc.
sam-goodwin
changed the title
Rework of the Shape type System
Rework of the Shape type system
Jan 30, 2020
… all DDB APIs. Add .stack utility to Core.App. fix pet-store API GW bugs.
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.
This is nearing completion and I'm super excited about it!
Classes instead of Values
Closes: #87
It used to be that a shape was just a value:
But this made it awkward to create and use values, as the type of a value was:
Now, developers dynamically create classes by extending the result of a function call:
This kills two birds with one stone:
This effectively emulates java's runtime reflection (
Type.class
orinstance.getClass()
) while also supporting awesome TypeScript type-magic for DSLs/ORMs.Traits and Decorators
TypeScript decorators can be put on a class as normal:
But, decorators must be put a redundant declaration of a member:
This is a bummer, but at least they're supported now.
To remove this redundancy, we also introduce the concept of "Traits" - type-safe "decorators" that can be applied to shapes. Not only do they support adding metadata to members in a record, but they also support augmenting the type-signature of that member - adding type-level properties that can influence the type-mappings used throughout shape DSLs.
An example:
This is analogous with an ordinary class definition:
Except the type-signature of the
string
shape is augmented, adding metadata from the traits to it (available at compile-time):This information is then utilized at runtime to perform the validation, but also enables some interesting type-level machinery. For example, those literal values are preserved when mapping a Shape to its corresponding JSON schema:
The type-signature is the exact same as the value (literals and all) - I think that is pretty cool!
This machinery will enable a bunch of customizability features for DSLs derived from Shapes.
Supporting an ecosystem of ORMs and DSLs
Closes: #12
Emulates missing behavior in TypeScript critical for ORMs: microsoft/TypeScript#7169
This change also extracts Shapes into its own package,
@punchcard/shape
, and fractures individual DSL/ORM implementations into their own package:@punchcard/shape-dynamodb
- DynamoDB ser/de and Condition/Filter/Query Expression DSL@punchcard/shape-json
- JSON ser/de@punchcard/shape-jsonschema
- Create a JSON schema from a Shape@punchcard/shape-jsonpath
- Type-Safe DSL for generating JSON path expressions over a ShapeBy fracturing the implementations, it is now possible to implement third-party DSLs for various domains using Shapes - hopefully this will enable an ecosystem to grow!
It is achieved with module augmentation and ad-hoc polymorphism -
@punchcard/shape
provides the primitive shape implementations which libraries augment to add their own mappings.Example:
Take a look at how DynamoDB is built for more detail:
https://github.com/punchcard/punchcard/blob/c9341abcec06105e70c1645ba007b7a526a77894/packages/%40punchcard/shape-dynamodb/lib/collection.ts#L6-L26
Developers then implement a
ShapeVisitor
to map from the Shape Abstract Syntax Tree (AST) to a new AST that represents their domain. Again, here is how that is achieved in DynamoDB:https://github.com/punchcard/punchcard/blob/c9341abcec06105e70c1645ba007b7a526a77894/packages/%40punchcard/shape-dynamodb/lib/dsl.ts#L38-L98
TODO
Example usages
Check out the tests to see the new DSLs in action. Or as always, check out the Stream Processing example:
https://github.com/punchcard/punchcard/blob/c9341abcec06105e70c1645ba007b7a526a77894/examples/lib/stream-processing.ts#L22-L176
Derive a JSON schema from a Record type:
DynamoDB Attribute Types also have a fully-preserved type-mapping
DynamoDB DSL:
DynamoDB Put If:
DynamoDB Update:
DynamoDB Query and Filter:
JSON Path has a similar DSL:
https://github.com/punchcard/punchcard/blob/c9341abcec06105e70c1645ba007b7a526a77894/packages/%40punchcard/shape-jsonpath/test/json-path.test.ts#L17-L65