From 8838d757e73d6af9b97d2327fcaaae23992f8135 Mon Sep 17 00:00:00 2001 From: Tim Date: Mon, 19 Aug 2024 11:43:25 +1200 Subject: [PATCH] add Model.FieldOption & Model.Date --- .changeset/nice-otters-fry.md | 5 ++ .changeset/yellow-hotels-repair.md | 5 ++ packages/sql/src/Model.ts | 112 ++++++++++++++++++++++++++++- 3 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 .changeset/nice-otters-fry.md create mode 100644 .changeset/yellow-hotels-repair.md diff --git a/.changeset/nice-otters-fry.md b/.changeset/nice-otters-fry.md new file mode 100644 index 0000000000..ef7e67ef32 --- /dev/null +++ b/.changeset/nice-otters-fry.md @@ -0,0 +1,5 @@ +--- +"@effect/sql": patch +--- + +add Model.FieldOption, for optional fields that are nullable for the db diff --git a/.changeset/yellow-hotels-repair.md b/.changeset/yellow-hotels-repair.md new file mode 100644 index 0000000000..32d62879b1 --- /dev/null +++ b/.changeset/yellow-hotels-repair.md @@ -0,0 +1,5 @@ +--- +"@effect/sql": patch +--- + +add Model.Date, a schema which represents a DateTime.Utc without time diff --git a/packages/sql/src/Model.ts b/packages/sql/src/Model.ts index 92a43f6d4e..d8cf97b882 100644 --- a/packages/sql/src/Model.ts +++ b/packages/sql/src/Model.ts @@ -2,11 +2,13 @@ * @since 1.0.0 */ import * as VariantSchema from "@effect/experimental/VariantSchema" +import * as ParseResult from "@effect/schema/ParseResult" import * as Schema from "@effect/schema/Schema" import type { Brand } from "effect/Brand" import * as DateTime from "effect/DateTime" import * as Effect from "effect/Effect" import * as Option from "effect/Option" +import * as Record from "effect/Record" const { Class, @@ -19,6 +21,18 @@ const { defaultVariant: "select" }) +/** + * @since 1.0.0 + * @category models + */ +export type VariantsDatabase = "select" | "insert" | "update" + +/** + * @since 1.0.0 + * @category models + */ +export type VariantsJson = "json" | "jsonCreate" | "jsonUpdate" + export { /** * A base class used for creating domain model schemas. @@ -185,6 +199,58 @@ export const Sensitive = | Schema.Schema.Any>( + self: Field +): VariantSchema.Field< + Field extends Schema.Schema.Any ? { + readonly select: Schema.OptionFromNullOr + readonly insert: Schema.OptionFromNullOr + readonly update: Schema.OptionFromNullOr + readonly json: Schema.optionalWith + readonly jsonCreate: Schema.optionalWith + readonly jsonUpdate: Schema.optionalWith + } + : Field extends VariantSchema.Field ? { + readonly [K in keyof S]: S[K] extends Schema.Schema.Any + ? K extends VariantsDatabase ? Schema.OptionFromNullOr : + Schema.optionalWith + : never + } : + {} +> => { + if (Schema.isSchema(self)) { + return Field({ + select: Schema.OptionFromNullOr(self), + insert: Schema.OptionFromNullOr(self), + update: Schema.OptionFromNullOr(self), + json: Schema.optionalWith(self, { as: "Option" }), + jsonCreate: Schema.optionalWith(self, { as: "Option", nullable: true }), + jsonUpdate: Schema.optionalWith(self, { as: "Option", nullable: true }) + }) as any + } + return VariantSchema.Field(Record.map(self.schemas, (schema, variant) => { + switch (variant) { + case "select": + case "insert": + case "update": + return Schema.OptionFromNullOr(schema as any) + case "json": + return Schema.optionalWith(schema as any, { as: "Option" }) + default: + return Schema.optionalWith(schema as any, { as: "Option", nullable: true }) + } + }) as any) +} + /** * @since 1.0.0 * @category models @@ -209,6 +275,46 @@ export const DateTimeFromDate: DateTimeFromDate = Schema.transform( } ) +/** + * @since 1.0.0 + * @category models + */ +export interface Date extends Schema.transformOrFail {} + +/** + * A schema for a `DateTime.Utc` that is serialized as a date string in the + * format `YYYY-MM-DD`. + * + * @since 1.0.0 + * @category schemas + */ +export const Date = Schema.transformOrFail( + Schema.String, + Schema.DateTimeUtcFromSelf, + { + decode: (s, _, ast) => + DateTime.make(s).pipe( + Option.map(DateTime.removeTime), + Option.match({ + onNone: () => ParseResult.fail(new ParseResult.Type(ast, s)), + onSome: (dt) => ParseResult.succeed(dt) + }) + ), + encode: (dt) => ParseResult.succeed(DateTime.formatIsoDate(dt)) + } +) + +/** + * @since 1.0.0 + * @category schemas + */ +export const DateWithNow = VariantSchema.Overrideable(Date, Schema.DateTimeUtcFromSelf, { + generate: Option.match({ + onNone: () => Effect.map(DateTime.now, DateTime.removeTime), + onSome: (dt) => Effect.succeed(DateTime.removeTime(dt)) + }) +}) + /** * @since 1.0.0 * @category schemas @@ -276,7 +382,7 @@ export const DateTimeInsert: DateTimeInsert = Field({ export interface DateTimeInsertFromDate extends VariantSchema.Field<{ readonly select: DateTimeFromDate - readonly insert: VariantSchema.Overrideable + readonly insert: VariantSchema.Overrideable readonly json: typeof Schema.DateTimeUtc }> {} @@ -360,8 +466,8 @@ export const DateTimeUpdate: DateTimeUpdate = Field({ export interface DateTimeUpdateFromDate extends VariantSchema.Field<{ readonly select: DateTimeFromDate - readonly insert: VariantSchema.Overrideable - readonly update: VariantSchema.Overrideable + readonly insert: VariantSchema.Overrideable + readonly update: VariantSchema.Overrideable readonly json: typeof Schema.DateTimeUtc }> {}