kysely
kysely copied to clipboard
[FEATURE REQUEST]: Camel case plugin - option to disable transformations on selected columns or data types
Hello,
The CamelCasePlugin options allow disabling conversion to camel case on all nested objects https://kysely-org.github.io/kysely-apidoc/interfaces/CamelCasePluginOptions.html#maintainNestedObjectKeys, however i don't find this quite useful as for example we might want to keep conversion on nested objects e.q. included by jsonArrayFrom, jsonObjectFrom helpers but we might not want to convert some jsonb column data.
For example we could have a custom_fields jsonb column where object keys are actual values (in this case, related entity ids)
{
"field_9npl6g7wqazcdgjz":{
"name":"Name 1",
"type":"TYPE_1",
},
"field_mvj5nwggpmyxwbj6":{
"name":"Name 2",
"type":"TYPE_2"
}
}
I would want to be able to disable conversion for this selected column or data type e.q. jsonb either on the pluguin level, or ideally on the query level if it would be possible.
new CamelCasePlugin({ skipDataTypes: ["json", "jsonb"] })
// or
new CamelCasePlugin({ skipColumns: ["customFields"] })
db.selectFrom("Table")
.select(["col1", "col2"])
.skipCamelCase(["col2"])
.executeTakeFirst();
Kysely doesn't know about data types. We don't know something's json or jsonb. Skipping by column name would be possible, but only if you don't alias the column.
Apologies for reopening this issue, but is there still no workaround to address this problem?
Here’s my current situation:
I’m using Kysely with the CamelCasePlugin, but I also have JSON/JSONB columns that store data where the structure and keys must remain 100% intact.
It makes perfect sense to apply camel case transformations to actual column keys, but the values within these columns should never be altered. At the same time, I still want to retain the benefit of camel-cased columns in nested queries.
I recently spent two days refactoring my entire codebase, only to encounter this limitation, and I’m feeling a bit stuck and frustrated.
Thanks!
+1
My quick solution
// camel-case-plugin.ts
import { CamelCasePlugin, CamelCasePluginOptions, UnknownRow } from 'kysely';
import isPlainObject from 'lodash/isPlainObject';
export class MyCamelCasePlugin extends CamelCasePlugin {
private _excludedColumns: string[];
constructor({ excludeColumns = [], ...opt }: CamelCasePluginOptions & { excludeColumns?: string[] } = {}) {
super(opt);
this._excludedColumns = excludeColumns;
}
protected mapRow(row: UnknownRow): UnknownRow {
return Object.keys(row).reduce((obj: Record<string, any>, key) => {
let value = row[key];
if (this._excludedColumns.includes(key)) {
obj[key] = value;
} else if (Array.isArray(value)) {
value = value.map((it) => (this.canMap(it, this.opt) ? this.mapRow(it) : it));
}
else if (this.canMap(value, this.opt)) {
value = this.mapRow(value as UnknownRow);
}
obj[this.camelCase(key)] = value;
return obj;
}, {});
}
private canMap(obj: any, opt: any) {
return isPlainObject(obj) && !opt?.maintainNestedObjectKeys;
}
}
// database.ts
new Database({
dialect: new PostgresDialect({
pool: new Pool({
...
}),
}),
plugins: [
new MyCamelCasePlugin({
excludeColumns: ['jsonb_column'],
}),
],
});
I really think this should be an option. I don't think you should be touching JSONB objects unless the user explicitly says so.