One of the best things about Schema is how it is the central definition of all models throughout the system.
By centralising all information for a model schema, property metadata, jsonschema metadata, and more, while deriving variations and views from them, there is a single source of truth and the distance between related information is very short, making it easy to get an overview quickly.
A great example is that you can access aTag.tag, aLiteral.literals, or aUnion.members, or aStruct.fields, instead of maintaining separate lists, possibly located at different ends of the application, making it harder to keep things in sync.
For Repositories we separately define the primary key and defaultValues/jitM from the Schema,
I would like to explore if and how we could centralise this too, as they are in fact kind of properties of the Model,
even though interpreted/executed by the Repositories/storage layer.
When type information is not required, one can simply use Schema annotations.
But in case of type information required, we should either wrap PropertySignature or Schemas, similar to how effect model in sql does.
Suggested helpers (WIP names):
PrimaryKey, so that we don't need to manually setup decoded: X, encoded: id, nor track idKey option in Repositories. It also helps the reader.
example: isin: PrimaryKey(ISIN)
a more detailed suggestion for this is available in https://github.com/effect-ts-app/libs/issues/92
a preliminary implementation is available in GS Security - but it does not enhance the metadata to say this is a Primary Key yet, so the Repository does not pick it up, and has to be configured manually.
we could consider dropping find and get and removeById, but then also byIdAndSaveWithPure, from the repo interface, and we no longer would need type level information. Because they could be expressed instead with Q.where("id", x), Q.one. Then again, most db adapters, ORMs etc, provide the convenience "find", "one" etc helpers..
withMigrationDefault, so that we don't need to specify defaultValues or perhaps even jitM at repositories.
example: createdAt: S.Date.withDefault.pipe(S.withMigrationDefault(() => new Date(...some static date...)).
this is preferred over S.optional etc, because those leak into the Encoded shape, and affect decoding from all sources, instead of just storage.
One of the best things about Schema is how it is the central definition of all models throughout the system. By centralising all information for a model schema, property metadata, jsonschema metadata, and more, while deriving variations and views from them, there is a single source of truth and the distance between related information is very short, making it easy to get an overview quickly.
A great example is that you can access
aTag.tag
,aLiteral.literals
, oraUnion.members
, oraStruct.fields
, instead of maintaining separate lists, possibly located at different ends of the application, making it harder to keep things in sync.For Repositories we separately define the primary key and defaultValues/jitM from the Schema, I would like to explore if and how we could centralise this too, as they are in fact kind of properties of the Model, even though interpreted/executed by the Repositories/storage layer.
When type information is not required, one can simply use Schema annotations. But in case of type information required, we should either wrap PropertySignature or Schemas, similar to how effect model in sql does.
Suggested helpers (WIP names):
PrimaryKey
, so that we don't need to manually setupdecoded: X, encoded: id
, nor trackidKey
option in Repositories. It also helps the reader. example:isin: PrimaryKey(ISIN)
a more detailed suggestion for this is available in https://github.com/effect-ts-app/libs/issues/92 a preliminary implementation is available in GS Security - but it does not enhance the metadata to say this is a Primary Key yet, so the Repository does not pick it up, and has to be configured manually.we could consider droppingThen again, most db adapters, ORMs etc, provide the convenience "find", "one" etc helpers..find
andget
andremoveById
, but then alsobyIdAndSaveWithPure
, from the repo interface, and we no longer would need type level information. Because they could be expressed instead withQ.where("id", x), Q.one
.withMigrationDefault
, so that we don't need to specifydefaultValues
or perhaps evenjitM
at repositories. example:createdAt: S.Date.withDefault.pipe(S.withMigrationDefault(() => new Date(...some static date...))
. this is preferred overS.optional
etc, because those leak into theEncoded
shape, and affect decoding from all sources, instead of just storage.99
Some inspiration in Effect sql Model:
Not saying we should go that level, to expose more SQLesque stuff into our model though. We should remain abstract enough and not "infect".
Schema annotations: https://effect.website/docs/guides/schema/annotations which power all kinds of things like https://effect.website/docs/guides/schema/schema-to-x/json-schema