Closed daniel-gato closed 2 months ago
Thanks for the issue!
This has been requested before, and it seems like a feature that needs to exist. I'm not sure how to best achieve this though.
I'm not sure, but perhaps it would be possible to (until it has been added) use a workaround with something like:
import { DB as CodegenDB } from 'kysely-codegen';
import { MyEnum } from './enums';
export type MyTable = Omit<CodegenDB[K], 'myEnum'> & {
myEnum: MyEnum;
};
export type DB = {
[K in keyof CodegenDB]: K extends 'myTable' ? MyTable : CodegenDB[K];
};
But I'm open to ideas on how to implement this in a proper way!
First of all, if you're explicitly using user-defined Postgres enums or MySQL enums, it should be solved in this issue that I'm working on: #21.
Some users have reported having text columns that they want to generate as enums however, or want to override built-in types (e.g. if they have a custom parser), such as #31. So some solution may be necessary.
One idea on how to achieve this:
I haven't explicitly tried this, but it should already be possible to override adapter settings programmatically:
import {
ColumnType,
IdentifierNode,
PostgresAdapter,
UnionExpressionNode,
} from 'kysely-codegen';
class CustomAdapter extends PostgresAdapter {
constructor() {
super();
this.definitions.Int8 = new ColumnType(
new IdentifierNode('number'),
new UnionExpressionNode([
new IdentifierNode('number'),
new IdentifierNode('bigint'),
]),
)
}
}
So we could use this to allow overrides using a JS or JSON file. .kysely-codegen.js
const { ColumnType, IdentifierNode, UnionExpressionNode } = require('kysely-codegen');
module.exports = {
extends: {
definitions: {
Int8: new ColumnType(
new IdentifierNode('number'),
new UnionExpressionNode([
new IdentifierNode('number'),
new IdentifierNode('bigint'),
]),
),
},
},
};
.kysely-codegen.json
{
"extend": {
"definitions": {
"Int8": {
"type": "GenericExpression",
"name": "ColumnType",
"args": [
{
"type": "Identifier",
"name": "number"
},
{
"type": "UnionExpressionNode",
"args": [
{
"type": "Identifier",
"name": "number"
},
{
"type": "Identifier",
"name": "bigint"
}
]
}
]
}
}
}
}
Of course, this would be a difficult API to use, so one further idea would be to implement a very simple TypeScript parser (which would also make it easier to contribute to the code in general):
{
"extend": {
"definitions": {
"Int8": "ColumnType<number, number, bigint>"
}
}
}
And some column-level overrides may be necessary:
{
"columnOverrides": {
"users.user_status": "\"CONFIRMED\" | \"NOT_CONFIRMED\""
}
}
Added a separate issue for this: #34
I'm still trying to figure it out on my side - I'll answer here as soon as I understand the scope of each tool (kysely, kysely-codegen, sst, dataapi)
Did you get anywhere with this @daniel-gato ?
Any workaround for this?
My workaround, in this example I'm converting tinyints to SqlBool:
import {
Generator,
MysqlDialect,
MysqlAdapter,
IdentifierNode
} from 'kysely-codegen'
import { createDbClient } from '../helpers/createDBClient'
import { SCHEMAS } from '../helpers/schemas'
const adapter = new MysqlAdapter()
class _MysqlAdapter extends MysqlAdapter {
override readonly scalars = {
...adapter.scalars,
tinyint: new IdentifierNode('boolean | 0 | 1')
}
}
class _MysqlDialect extends MysqlDialect {
override readonly adapter = new _MysqlAdapter()
}
export const execute = async () => {
for (const schema of SCHEMAS) {
const gen = new Generator()
const db = createDbClient(schema)
await gen.generate({
camelCase: false,
outFile: 'schema.ts',
schema: schema,
db,
dialect: new _MysqlDialect()
})
await db.destroy()
}
console.log('Kysely types generated.')
}
Why not the other way around? Why not use the types generated by Kysely Codegen and use them in your codebase instead? This way, you have one source of truth (your database) without having to sync enum values between your application code and database?
Anyway this should have room for customization, c'mon. I did something to replace kysely-codegen generated types with branded types wherever I needed
Should be released in kysely-codegen@0.16.0! 🚀
How this works if I want to override the primitive type with my own like a branded type?
@thelinuxlich It should be doable like so:
--overrides='{ "columns": { "table_name.column_name": "string & { __brand?: \"MyBrand\" }" } }'
This hasn't been tested too much, so it's possible that I might need to add support for multi-schema databases for example. There are also plans to support JSON/JS configuration files to make this easier. Feel free to try out the existing solution!
What if it's a type that needs to be imported?
@thelinuxlich probably you can use dynamic imports like import('mymodule').MyType
@RobinBlomberg great work, but as you said, for multi-schema databases it just seems to do nothing for me (using Postgres). Doesn't even issue a warning that it couldn't find the table/column or anything.
We have many enums columns for which we already have a type defined in our code base.
We are fine with a database column of string type but we would like to be able to force the enum type on our generated sql schema.
Is this doable? Do you see a work around for now?
Upvote & Fund