francis
francis
Explore posts from servers
DTDrizzle Team
Created by francis on 2/12/2025 in #help
Is there a valid use case for being able to specify a relation name that points to a "wrong" table?
Example:
export const firstTable = pgTable('first', {
id: text('id').primaryKey(),
});

export const secondTable = pgTable('second', {
id: uuid('id').primaryKey(),
});

export const referencingTable = pgTable('referencing', {
id: serial('id').primaryKey(),
firstId: text('first_id').references(() => firstTable.id),
secondId: uuid('second_id').references(() => secondTable.id),
});

const referencingRelations = relations(referencingTable, ({ one }) => ({
first: one(firstTable, { fields: [referencingTable.firstId], references: [firstTable.id], relationName: 'first_relation' }),
second: one(secondTable, { fields: [referencingTable.firstId], references: [secondTable.id], relationName: 'second_relation' })
}));

const firstRelations = relations(firstTable, ({ many }) => ({
referencing: many(referencingTable, { relationName: 'second_relation' }), // why can I do this??
}));
export const firstTable = pgTable('first', {
id: text('id').primaryKey(),
});

export const secondTable = pgTable('second', {
id: uuid('id').primaryKey(),
});

export const referencingTable = pgTable('referencing', {
id: serial('id').primaryKey(),
firstId: text('first_id').references(() => firstTable.id),
secondId: uuid('second_id').references(() => secondTable.id),
});

const referencingRelations = relations(referencingTable, ({ one }) => ({
first: one(firstTable, { fields: [referencingTable.firstId], references: [firstTable.id], relationName: 'first_relation' }),
second: one(secondTable, { fields: [referencingTable.firstId], references: [secondTable.id], relationName: 'second_relation' })
}));

const firstRelations = relations(firstTable, ({ many }) => ({
referencing: many(referencingTable, { relationName: 'second_relation' }), // why can I do this??
}));
As far as I can tell, unlike specifying a relation name which doesn't exist, or not specifying a relation name in case of ambiguity, which error in drizzle, this dies with a database driver error at runtime when the generated query references the wrong table in case of a type mismatch, or potentially continues to operate with undefined behavior resulting from selecting a row from the wrong table. With the above configuration, with the types deliberately incompatible, I receive PostgresError: operator does not exist: text = uuid when attempting to select using the wrong name.
2 replies
Aarktype
Created by francis on 1/28/2025 in #questions
Is there a way to have defaults apply when a key is undefined, in addition to when a key is missing?
example:
let objWithDefault = a.type({nameWithDefault: 'string = "foo"'});
objWithDefault({}); // this works
objWithDefault({ nameWithDefault: undefined }); // this doesn't
let objWithDefault = a.type({nameWithDefault: 'string = "foo"'});
objWithDefault({}); // this works
objWithDefault({ nameWithDefault: undefined }); // this doesn't
1 replies
Aarktype
Created by francis on 1/27/2025 in #questions
very silly question, is there an easier way to validate the length of a trimmed string?
type("string.trim > 2")
type("string.trim > 2")
errors with Uncaught ParseError: MinLength operand must be a string or an array (was never)
type("string.trim").pipe(type("string > 3"))
type("string.trim").pipe(type("string > 3"))
appears to work, but this seems unergonomic when most other string keywords allow length specifiers. I know that this is a morph rather than a simple narrowing, but it is surprising!
15 replies
Aarktype
Created by francis on 12/23/2024 in #questions
How can we describe a string with a length restriction?
e.g.:
type("5 < string.numeric < 7").describe("valid otp")
type("5 < string.numeric < 7").describe("valid otp")
gives the following error message: otp must be valid otp (was 3) I would expect the description to override the insertion of the current length. Is there a way to do this? Similarly, is there an easy way to remove the field name from the error, for use in inline form error display?
14 replies
DTDrizzle Team
Created by francis on 11/29/2024 in #help
Disambiguate optional one-to-one relationship
This is a similar problem to https://discord.com/channels/1043890932593987624/1084576896039260202/threads/1254869164607143998 - but instead involves two tables, one of which has a non-nullable foreign key to the other. https://drizzle.run/my887gq5kvpp1ogl3xpoe0zh I have table A that has an id column, and table B that has a nullable reference to table A on a unique column. This is an optional one-to-one relationship, however, there is another column on table B that is not unique and should have a many-to-one relationship to table A. It's possible to disambiguate many-to-one relationships, but I'm not sure how to disambiguate a one-to-one without including fields and references on the ambiguous one() on table A which makes the one-to-one relationship incorrectly non-nullable.
12 replies
Aarktype
Created by francis on 11/25/2024 in #questions
Is there a recommended way to create a Record using a type as a key?
None of these seem to work:
const stringKeys = type(
"===",
"CAR",
"ENDO",
"REP",
"DEV",
"GEN",
"NEU",
"ORG",
"IMM",
"RES",
"IRR",
"ECO",
);

const explicit = type.Record(stringKeys, type("number | null"));

const stringSyntax = type(
'Record<"CAR" | "ENDO" | "REP" | "DEV" | "GEN" | "NEU" | "ORG" | "IMM" | "RES" | "IRR" | "ECO", number | null>',
);
const stringKeys = type(
"===",
"CAR",
"ENDO",
"REP",
"DEV",
"GEN",
"NEU",
"ORG",
"IMM",
"RES",
"IRR",
"ECO",
);

const explicit = type.Record(stringKeys, type("number | null"));

const stringSyntax = type(
'Record<"CAR" | "ENDO" | "REP" | "DEV" | "GEN" | "NEU" | "ORG" | "IMM" | "RES" | "IRR" | "ECO", number | null>',
);
3 replies
Aarktype
Created by francis on 11/18/2024 in #questions
Are there docs on how to do non-trivial self reference?
I can't seem to find them. I'm aware of the this keyword, but I'm looking to do something like:
const example = type({
name: "string",
selves: "this[]",
});
const example = type({
name: "string",
selves: "this[]",
});
5 replies
Aarktype
Created by francis on 11/14/2024 in #questions
Is there a way to set a default value that is not valid?
This is due to svelte 5 - where you have to provide a meaningful non-undefined prop for bound values. e.g. for radio buttons, you need to default to "", not undefined. I am not sure how to define an Arktype type that accepts only an enum of values from the radio button, but defaults to empty-string. When I do the obvious inputType.default("") I get errors: ParseError: Default value is not assignable: must be "enum_option" (was "")
166 replies
Aarktype
Created by francis on 9/23/2024 in #questions
Is there currently a known issue with arktype + trpc compatibility?
This is with latest RC.12
TypeError: Cannot read properties of undefined (reading 'traverse')
at assert (/node_modules/@ark/schema/out/roots/root.js:80:29)
at inputMiddleware (/node_modules/@trpc/server/dist/index.mjs:278:33)
at callRecursive (/node_modules/@trpc/server/dist/index.mjs:452:38)
at Object.next (/node_modules/@trpc/server/dist/index.mjs:461:32)
at eval (/src/lib/trpc/middleware.ts:21:15)
at callRecursive (/node_modules/@trpc/server/dist/index.mjs:452:38)
at resolve (/node_modules/@trpc/server/dist/index.mjs:482:30)
at callProcedure (/node_modules/@trpc/server/dist/config-d5fdbd39.mjs:155:12)
at inputToProcedureCall (/node_modules/@trpc/server/dist/resolveHTTPResponse-2fc435bb.mjs:46:28)`
TypeError: Cannot read properties of undefined (reading 'traverse')
at assert (/node_modules/@ark/schema/out/roots/root.js:80:29)
at inputMiddleware (/node_modules/@trpc/server/dist/index.mjs:278:33)
at callRecursive (/node_modules/@trpc/server/dist/index.mjs:452:38)
at Object.next (/node_modules/@trpc/server/dist/index.mjs:461:32)
at eval (/src/lib/trpc/middleware.ts:21:15)
at callRecursive (/node_modules/@trpc/server/dist/index.mjs:452:38)
at resolve (/node_modules/@trpc/server/dist/index.mjs:482:30)
at callProcedure (/node_modules/@trpc/server/dist/config-d5fdbd39.mjs:155:12)
at inputToProcedureCall (/node_modules/@trpc/server/dist/resolveHTTPResponse-2fc435bb.mjs:46:28)`
This occurs when I do .input(type(anything).assert). If I do something such as .input((i) => type(anything).assert(i)), it works fine. How on earth is it ending up with this being undefined when it is run this way?
4 replies
Aarktype
Created by francis on 9/23/2024 in #questions
How would you define an object with optional keys, but require at least one of the keys to be filled
An example of a very basic schema:
const schema = type({ a: type.string.optional(), b: type.string.optional() });
const schema = type({ a: type.string.optional(), b: type.string.optional() });
I'd like this to accept values {a: 'foo'}, { b: 'foo' }, and { a: 'foo', b: 'bar' }, but fail on {}. It would be a lovely bonus for the type to be inferred as { a: string, b?: string } | { a?: string, b: string } as well. Is there a way to do this without explicitly specifying that inferred type as an arktype union using .or?
15 replies
Aarktype
Created by francis on 9/21/2024 in #questions
Is there a recommended way to transform a type union into a discriminated union by adding a tag?
I'm not sure I'm describing this well, but I have a situation with two types that I am .or-ing together. It all works, but I'm interacting with a library that needs a discriminated union to function properly for type narrowing, and I am not sure how to add a discriminated union tag based on which type in the Or resolved (if that makes sense?) Here's a simple example to demonstrate:
const first = type({ key: "string" });
const second = type({ key: "number" });
const combined = first.or(second);
const first = type({ key: "string" });
const second = type({ key: "number" });
const combined = first.or(second);
I'd like to have this be resolve to e.g. { key: string, tag: 'first' } | { key: number, tag: 'second' } based on which branch in the union was followed. I've tried it with this:
const first = type({ key: "string" }).pipe((o) => ({ ...o, _tag: "first" }) as const);
const second = type({ key: "number" }).pipe((o) => ({ ...o, _tag: "second" }) as const);
const combined = first.or(second);
const first = type({ key: "string" }).pipe((o) => ({ ...o, _tag: "first" }) as const);
const second = type({ key: "number" }).pipe((o) => ({ ...o, _tag: "second" }) as const);
const combined = first.or(second);
and it works - but seems inelegant. Is there a more idiomatic solution?
13 replies
Aarktype
Created by francis on 9/21/2024 in #questions
Is there a way to do a case insensitive literal match?
I can pipe a string.lower to a lower-case literal but that seems complicated for this.
27 replies
Aarktype
Created by francis on 9/21/2024 in #questions
Is there a way to perform schema parsing generically?
My reasoning is to integrate Arktype with https://effect.website/ This most simple example fails:
function genericDemo<T>(schema: Type<T>, u: unknown): T {
return schema.assert(u);
}
function genericDemo<T>(schema: Type<T>, u: unknown): T {
return schema.assert(u);
}
This fails as the return type of .assert is finalizeDistillation<T, _distill<T, { endpoint: "out"; }>> Is there a way to coerce this back to a T? Or is there some constraint I need to put on the T input to make this work?
31 replies
DTDrizzle Team
Created by francis on 9/20/2024 in #help
How do you define two tables that have foreign keys to each other? drizzle-kit introspect fails
Drizzle-kit now generates a schema file with type errors - it was previously working prior to 0.24.0. In addition, the generated foreign key entry for multicolumn foreign keys has the columns in the incorrect order. (code below due to length limit)
5 replies
Aarktype
Created by francis on 8/25/2024 in #questions
vscode intellisense errors on the same type definition in some files, but not others
e.g. the following type:
const exampleType = type({
email: "string.email",
});
const exampleType = type({
email: "string.email",
});
In some files, this works fine. In others, in the exact same project, this causes the following error:
Type '"string.email"' is not assignable to type '"'string' must reference a module to be accessed using dot syntax "'.
The expected type comes from property 'email' which is declared here on type 'validateObjectLiteral<{ readonly email: "string.email"; }, {}, bindThis<{ readonly email: "string.email"; }>>'
Type '"string.email"' is not assignable to type '"'string' must reference a module to be accessed using dot syntax "'.
The expected type comes from property 'email' which is declared here on type 'validateObjectLiteral<{ readonly email: "string.email"; }, {}, bindThis<{ readonly email: "string.email"; }>>'
Any ideas for what might be going on?
14 replies
DTDrizzle Team
Created by francis on 8/8/2024 in #help
What's the recommended way to do a basic filter by a boolean column's value?
I can't figure out how to use a non-filter expression for filtering. e.g., I would expect db.select().from(appointment).where(appointment.canceled) to generate the equivalent sql select * from appointment where appointment.canceled, which works exactly how I expect. .where(() => appointment.canceled) or .where((a) => a.canceled) don't work either. I can use
.where(sql`${appointment.canceled}`)
.where(sql`${appointment.canceled}`)
but surely there must be a simpler way? I can provide this column as an argument to a filter, so why can't I use this column itself as a filter?
3 replies
Aarktype
Created by francis on 8/7/2024 in #questions
Are there examples of how to create mapped types?
e.g. a { [K in <SomeOtherType>]: SomeValueType } type, where SomeValueType is either a static type or is computed from K. I currently have a very basic setup where I have:
type MappedEnum<T extends string> = { readonly [K in T]: T };

const kitTypes = ["test_only", "test_self_serve", "test_guided_audit"];
const kitTypeValidator = type("===", ...kitTypes);
export type KitType = typeof kitTypeValidator.infer;
export const KitType = {
test_only: "test_only",
test_self_serve: "test_self_serve",
test_guided_audit: "test_guided_audit",
} as const satisfies MappedEnum<KitType>;
type MappedEnum<T extends string> = { readonly [K in T]: T };

const kitTypes = ["test_only", "test_self_serve", "test_guided_audit"];
const kitTypeValidator = type("===", ...kitTypes);
export type KitType = typeof kitTypeValidator.infer;
export const KitType = {
test_only: "test_only",
test_self_serve: "test_self_serve",
test_guided_audit: "test_guided_audit",
} as const satisfies MappedEnum<KitType>;
This pattern allows me to generate, from a string array, a validator for an element in that array, a type for an element of the resulting string union type, and a type for a runtime object that lets me access the values analogous to an enum. And it's great! My question is, I have the following type definition:
type KitCounts = { [K in KitType]?: number };
type KitCounts = { [K in KitType]?: number };
Is there a way to write an ArkType function that will generate a validator for this type (and the type definition itself), given the kitTypes array? My initial attempt is:
const kitCountsValidator = type(
Object.fromEntries(kitType.enumValues.map((k) => [`${k}?`, "number"])),
);
const kitCountsValidator = type(
Object.fromEntries(kitType.enumValues.map((k) => [`${k}?`, "number"])),
);
Obviously, this doesn't work, since the type information is completely lost. It actually works fine at runtime but the type is useless. Is there a way to do this without writing it out explicitly? (I have 5+ other enums that I'd like to process in a similar way)
22 replies
Aarktype
Created by francis on 8/2/2024 in #questions
How to accept a generic non-empty const string array for use in `type`?
Note: this may be a TS question, feel free to send me there instead. I have the following type: PgEnum<TValues extends [string, ...string[]]> { enumValues: TValues; } I'm attempting to create a function which accepts this object and returns an arktype instance of the union of the strings in the array, which is const with well-known values. If I call it directly from the const signature, e.g. type('===', obj.enumValues), it works fine. But I can't figure out how to accept this as a generic function parameter and use it in the body. I have tried:
function arktypeUnionFromEnum<A extends string, B extends string[]>(pgEnum: {
enumValues: [A, ...B];
}) {
return type("===", ...pgEnum.enumValues);
}
function arktypeUnionFromEnum<A extends string, B extends string[]>(pgEnum: {
enumValues: [A, ...B];
}) {
return type("===", ...pgEnum.enumValues);
}
This fails on the spread argument with
Argument of type 'A' is not assignable to parameter of type 'conform<A, unknown>'.
Type 'string' is not assignable to type 'conform<A, unknown>'.ts(2345)
Argument of type 'A' is not assignable to parameter of type 'conform<A, unknown>'.
Type 'string' is not assignable to type 'conform<A, unknown>'.ts(2345)
Unwinding the generic produces different errors:
function arktypeUnionFromEnum<T extends string[]>(pgEnum: { enumValues: T }) {
return type("===", ...pgEnum.enumValues);
}
function arktypeUnionFromEnum<T extends string[]>(pgEnum: { enumValues: T }) {
return type("===", ...pgEnum.enumValues);
}
leads to A spread argument must either have a tuple type or be passed to a rest parameter. Replacing string[] with [string, ...string[]] leads to the same issue. I suspect the two generic parameters is the closer approach, but I have no idea what this conform<> error is, or how to begin to address it.
3 replies
DTDrizzle Team
Created by francis on 3/7/2024 in #help
New string mode date handling for postgres in 0.30.0 is potentially inconsistent
When selecting a value from a column of type timestamp with time zone, I receive the following string format: 2024-01-19 16:54:36.74526+00 When selecting a value from a column of type date, I receive the following string format: 1990-01-01T00:00:00.000Z It appears the serialization changes for the postgres driver may not be working - the ones here https://github.com/drizzle-team/drizzle-orm/blob/main/drizzle-orm/src/postgres-js/driver.ts#L27 If I define my own custom type as:
types: {
date_temp: {
to: 1082,
from: [1082],
serialize: (val: any) => val,
parse: (val: any) => val,
}
}
types: {
date_temp: {
to: 1082,
from: [1082],
serialize: (val: any) => val,
parse: (val: any) => val,
}
}
in the postgres-js options, then suddenly I receive the raw sql values I expect: 1990-01-01
2 replies
DTDrizzle Team
Created by francis on 1/28/2024 in #help
Issuing multiple sql queries in order, but without waiting for round trips?
I need to run several commands to set up transaction variables for my use case. They need to be run in order, but I don't need the result of any of them. Is there a way to issue e.g. 3 sequential commands in a single query to the database so I don't have to wait for the round trip for each one, like happens now with await tx.execute(.....) 3 times in a row?
21 replies