Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/infra-sentry-node-dep.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
---
"@effect-app/infra": patch
---

Declare `@sentry/node` as a runtime dependency of `@effect-app/infra`. `errorReporter.ts` imports it statically, so `pnpm install --prod` of linked source (Docker) must install it next to the package, not only as a peer of the app.
9 changes: 9 additions & 0 deletions .changeset/native-encoded-query-json.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
---
"effect-app": minor
"@effect-app/infra": minor
"@effect-app/vue-components": minor
---

Stop forcing Date/Map/Set Encoded shapes to JSON.

`Schema.Date` / `ReadonlySet` / `ReadonlyMap` now keep native Encoded types (`Date`, `Set`, `Map`). Use `DateFromString`, `ReadonlySetFromArray`, and `ReadonlyMapFromArray` when the Encoded form must be JSON. The query DSL accepts those native values, including array ops (`includes` / `in` / `includes-any`) on `Date[]` and `ReadonlySet` fields. Memory, Disk, SQL, and Cosmos convert Encoded Date/Map/Set through `Schema.toCodecJson` on write/read; query parameters are lowered the same way. App schemas (DateOnly, …) register the same way via `JsonValues` / `StoreConfig.jsonValues`.
8 changes: 8 additions & 0 deletions .changeset/query-map-has-ops.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
---
"effect-app": minor
"@effect-app/infra": minor
---

Query maps as JSON arrays of `[key, value]` tuples.

`where("meta", "hasKey" | "hasValue" | "hasKeyValue", ...)` (and `not*` / `*-any` / `*-all` variants) filter `ReadonlyMap` fields. Memory, Disk, SQLite, Postgres, and Cosmos compile those ops against the encoded tuple array.
8 changes: 8 additions & 0 deletions .changeset/store-json-values.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
---
"effect-app": minor
"@effect-app/infra": minor
---

App schemas can plug native Encoded values into JSON stores without baking them into effect-app.

`StoreConfig.jsonValues` and `JsonValues` (a Context service) take schemas whose Encoded form is a native value (DateOnly, branded money, …). Query params and schemaless documents lower through `Schema.toCodecJson(toEncoded(schema))`. Date/Map/Set stay built in. Use `registerJsonSchema` for process-wide registration.
Original file line numberDiff line numberDiff line change
Expand Up@@ -581,7 +581,7 @@ export function makeRepoInternal<
.pipe(
Effect.andThen(
(items) =>
S.decodeEffectConcurrently(S.Array(a.schema ?? schema))(items).pipe(
S.decodeEffectConcurrently(S.Array(S.toCodecJson(a.schema ?? schema)))(items).pipe(
provideRctx,
timeSchema("decode", name, "aggregate", items.length)
)
Expand All@@ -593,7 +593,7 @@ export function makeRepoInternal<
.pipe(
Effect.andThen(
(items) =>
S.decodeEffectConcurrently(S.Array(a.schema ?? schema))(items).pipe(
S.decodeEffectConcurrently(S.Array(S.toCodecJson(a.schema ?? schema)))(items).pipe(
provideRctx,
timeSchema("decode", name, "project", items.length)
)
Expand All@@ -604,7 +604,7 @@ export function makeRepoInternal<
// TODO: mapFrom but need to support per field and dependencies
.pipe(
Effect.flatMap((items) =>
S.decodeEffectConcurrently(S.Array(a.schema))(items).pipe(
S.decodeEffectConcurrently(S.Array(S.toCodecJson(a.schema)))(items).pipe(
Effect.map(Array.getSomes),
provideRctx,
timeSchema("decode", name, "collect", items.length)
Expand DownExpand Up@@ -737,7 +737,7 @@ export function makeRepoInternal<
queryRaw<A, Out, QR>(schema: S.Codec<A, Out, QR>, q: Q.RawQuery<Encoded, Out>) {
return store.queryRaw(q).pipe(
Effect.flatMap((items) =>
S.decodeEffectConcurrently(S.Array(schema))(items).pipe(
S.decodeEffectConcurrently(S.Array(S.toCodecJson(schema)))(items as readonly S.Json[]).pipe(
timeSchema("decode", name, undefined, items.length)
)
),
Expand DownExpand Up@@ -887,6 +887,7 @@ export function makeStore<Encoded extends FieldValues>() {
: undefined,
{
...config,
schema,
partitionValue: config?.partitionValue
?? ((_) => "primary") /*(isIntegrationEvent(r) ? r.companyId : r.id*/
}
Expand Down
20 changes: 19 additions & 1 deletion packages/effect-app/src/Model/filter/filterApi.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,6 +17,24 @@ export type OtherOps =
| "notIncludes-any"
| "includes-all"
| "notIncludes-all"
| "hasKey"
| "notHasKey"
| "hasValue"
| "notHasValue"
| "hasKeyValue"
| "notHasKeyValue"
| "hasKey-any"
| "notHasKey-any"
| "hasKey-all"
| "notHasKey-all"
| "hasValue-any"
| "notHasValue-any"
| "hasValue-all"
| "notHasValue-all"
| "hasKeyValue-any"
| "notHasKeyValue-any"
| "hasKeyValue-all"
| "notHasKeyValue-all"
| "eq"
| "neq"
| "gt"
Expand DownExpand Up@@ -44,7 +62,7 @@ export type FilterR = {
op: Ops

path: string
value: string // ToDO: Value[]
value: unknown
}

export type FilterResult =
Expand Down
195 changes: 188 additions & 7 deletions packages/effect-app/src/Model/query/dsl.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -1157,7 +1157,15 @@ export const aggregate: {
return new Project({ current, schema, mode: "aggregate", aggregateMap } as any)
}

type GetArV<T> = T extends readonly (infer R)[] ? R : never
type GetArV<T> = T extends ReadonlySet<infer R> ? R
: T extends readonly (infer R)[] ? R
: never

type GetMapK<T> = T extends ReadonlyMap<infer K, infer _V> ? K : never
type GetMapV<T> = T extends ReadonlyMap<infer _K, infer V> ? V : never
type GetMapEntry<T> = T extends ReadonlyMap<infer K, infer V> ? readonly [K, V] : never

type InValues<T> = readonly T[] | ReadonlySet<T>

export type FilterContinuations<IsCurrentInitial extends boolean = false> = {
<
Expand DownExpand Up@@ -1207,13 +1215,12 @@ export type FilterContinuations<IsCurrentInitial extends boolean = false> = {
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
const V extends readonly FieldPathValue<TFieldValues, TFieldName>[],
TFieldValuesRefined extends TFieldValues = TFieldValues,
E extends boolean = false
>(
path: TFieldName,
op: "in" | "notIn",
value: V
value: InValues<FieldPathValue<TFieldValues, TFieldName>>
): (
current: IsCurrentInitial extends true ? Query<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
Expand DownExpand Up@@ -1249,7 +1256,97 @@ export type FilterContinuations<IsCurrentInitial extends boolean = false> = {
| "notIncludes-any"
| "includes-all"
| "notIncludes-all",
value: readonly GetArV<V>[]
value: InValues<GetArV<V>>
): (
current: IsCurrentInitial extends true ? Query<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
) => IsCurrentInitial extends true ? QueryWhere<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
V extends FieldPathValue<TFieldValues, TFieldName>,
TFieldValuesRefined extends TFieldValues = TFieldValues,
E extends boolean = false
>(
path: TFieldName,
op: "hasKey" | "notHasKey",
value: GetMapK<V>
): (
current: IsCurrentInitial extends true ? Query<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
) => IsCurrentInitial extends true ? QueryWhere<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
V extends FieldPathValue<TFieldValues, TFieldName>,
TFieldValuesRefined extends TFieldValues = TFieldValues,
E extends boolean = false
>(
path: TFieldName,
op: "hasValue" | "notHasValue",
value: GetMapV<V>
): (
current: IsCurrentInitial extends true ? Query<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
) => IsCurrentInitial extends true ? QueryWhere<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
V extends FieldPathValue<TFieldValues, TFieldName>,
TFieldValuesRefined extends TFieldValues = TFieldValues,
E extends boolean = false
>(
path: TFieldName,
op: "hasKeyValue" | "notHasKeyValue",
value: GetMapEntry<V>
): (
current: IsCurrentInitial extends true ? Query<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
) => IsCurrentInitial extends true ? QueryWhere<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
V extends FieldPathValue<TFieldValues, TFieldName>,
TFieldValuesRefined extends TFieldValues = TFieldValues,
E extends boolean = false
>(
path: TFieldName,
op: "hasKey-any" | "notHasKey-any" | "hasKey-all" | "notHasKey-all",
value: InValues<GetMapK<V>>
): (
current: IsCurrentInitial extends true ? Query<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
) => IsCurrentInitial extends true ? QueryWhere<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
V extends FieldPathValue<TFieldValues, TFieldName>,
TFieldValuesRefined extends TFieldValues = TFieldValues,
E extends boolean = false
>(
path: TFieldName,
op: "hasValue-any" | "notHasValue-any" | "hasValue-all" | "notHasValue-all",
value: InValues<GetMapV<V>>
): (
current: IsCurrentInitial extends true ? Query<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
) => IsCurrentInitial extends true ? QueryWhere<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
V extends FieldPathValue<TFieldValues, TFieldName>,
TFieldValuesRefined extends TFieldValues = TFieldValues,
E extends boolean = false
>(
path: TFieldName,
op: "hasKeyValue-any" | "notHasKeyValue-any" | "hasKeyValue-all" | "notHasKeyValue-all",
value: InValues<GetMapEntry<V>>
): (
current: IsCurrentInitial extends true ? Query<TFieldValues>
: QueryWhere<TFieldValues, TFieldValuesRefined, E>
Expand DownExpand Up@@ -1318,12 +1415,12 @@ export type FilterContinuationsWithSubpath = {
TFieldName extends FieldPath<TFieldValues>,
TFieldValuesSub extends TFieldValues[TFieldName][number],
TFieldNameSub extends FieldPath<TFieldValuesSub>,
const V extends readonly FieldPathValue<TFieldValuesSub, TFieldNameSub>[]
V extends FieldPathValue<TFieldValuesSub, TFieldNameSub>
>(
subPath: TFieldName,
restPath: TFieldNameSub,
op: "in" | "notIn",
value: V
value: InValues<V>
): (
current: Query<TFieldValues>
) => QueryWhere<TFieldValues>
Expand DownExpand Up@@ -1357,7 +1454,91 @@ export type FilterContinuationsWithSubpath = {
| "notIncludes-any"
| "includes-all"
| "notIncludes-all",
value: readonly GetArV<V>[]
value: InValues<GetArV<V>>
): (
current: Query<TFieldValues>
) => QueryWhere<TFieldValues>
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
TFieldValuesSub extends TFieldValues[TFieldName][number],
TFieldNameSub extends FieldPath<TFieldValuesSub>,
V extends FieldPathValue<TFieldValuesSub, TFieldNameSub>
>(
subPath: TFieldName,
restPath: TFieldNameSub,
op: "hasKey" | "notHasKey",
value: GetMapK<V>
): (
current: Query<TFieldValues>
) => QueryWhere<TFieldValues>
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
TFieldValuesSub extends TFieldValues[TFieldName][number],
TFieldNameSub extends FieldPath<TFieldValuesSub>,
V extends FieldPathValue<TFieldValuesSub, TFieldNameSub>
>(
subPath: TFieldName,
restPath: TFieldNameSub,
op: "hasValue" | "notHasValue",
value: GetMapV<V>
): (
current: Query<TFieldValues>
) => QueryWhere<TFieldValues>
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
TFieldValuesSub extends TFieldValues[TFieldName][number],
TFieldNameSub extends FieldPath<TFieldValuesSub>,
V extends FieldPathValue<TFieldValuesSub, TFieldNameSub>
>(
subPath: TFieldName,
restPath: TFieldNameSub,
op: "hasKeyValue" | "notHasKeyValue",
value: GetMapEntry<V>
): (
current: Query<TFieldValues>
) => QueryWhere<TFieldValues>
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
TFieldValuesSub extends TFieldValues[TFieldName][number],
TFieldNameSub extends FieldPath<TFieldValuesSub>,
V extends FieldPathValue<TFieldValuesSub, TFieldNameSub>
>(
subPath: TFieldName,
restPath: TFieldNameSub,
op: "hasKey-any" | "notHasKey-any" | "hasKey-all" | "notHasKey-all",
value: InValues<GetMapK<V>>
): (
current: Query<TFieldValues>
) => QueryWhere<TFieldValues>
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
TFieldValuesSub extends TFieldValues[TFieldName][number],
TFieldNameSub extends FieldPath<TFieldValuesSub>,
V extends FieldPathValue<TFieldValuesSub, TFieldNameSub>
>(
subPath: TFieldName,
restPath: TFieldNameSub,
op: "hasValue-any" | "notHasValue-any" | "hasValue-all" | "notHasValue-all",
value: InValues<GetMapV<V>>
): (
current: Query<TFieldValues>
) => QueryWhere<TFieldValues>
<
TFieldValues extends FieldValues,
TFieldName extends FieldPath<TFieldValues>,
TFieldValuesSub extends TFieldValues[TFieldName][number],
TFieldNameSub extends FieldPath<TFieldValuesSub>,
V extends FieldPathValue<TFieldValuesSub, TFieldNameSub>
>(
subPath: TFieldName,
restPath: TFieldNameSub,
op: "hasKeyValue-any" | "notHasKeyValue-any" | "hasKeyValue-all" | "notHasKeyValue-all",
value: InValues<GetMapEntry<V>>
): (
current: Query<TFieldValues>
) => QueryWhere<TFieldValues>
Expand Down
Loading
Loading