From 9b746b85ce068343b342de28f5838046274d24a5 Mon Sep 17 00:00:00 2001 From: igalklebanov Date: Mon, 2 Sep 2024 12:09:29 +0300 Subject: [PATCH] call the new type `Json` instead, to not introduce a breaking change. --- site/docs/getting-started/_types.mdx | 12 +++++------ src/expression/expression-builder.ts | 10 +++++----- src/util/column-type.ts | 30 +++++++++++++++++++++------- test/node/src/json-traversal.test.ts | 12 +++++------ test/typings/shared.d.ts | 21 ++++++++----------- 5 files changed, 47 insertions(+), 38 deletions(-) diff --git a/site/docs/getting-started/_types.mdx b/site/docs/getting-started/_types.mdx index 42cf066be..1f4b98b58 100644 --- a/site/docs/getting-started/_types.mdx +++ b/site/docs/getting-started/_types.mdx @@ -10,7 +10,7 @@ import { ColumnType, Generated, Insertable, - JSONColumnType, + Json, Selectable, Updateable, } from 'kysely' @@ -45,12 +45,10 @@ export interface PersonTable { // can never be updated: created_at: ColumnType - // You can specify JSON columns using the `JSONColumnType` wrapper. - // It is a shorthand for `ColumnType`, where T - // is the type of the JSON object/array retrieved from the database, - // and the insert and update types are always `string` since you're - // always stringifying insert/update values. - metadata: JSONColumnType<{ + // You can specify JSON columns using the `Json` wrapper. + // When inserting/updating values of such columns, you're required to wrap the + // values with `eb.valJson` or `sql.valJson`. + metadata: Json<{ login_at: string ip: string | null agent: string | null diff --git a/src/expression/expression-builder.ts b/src/expression/expression-builder.ts index fc4efc233..856f16426 100644 --- a/src/expression/expression-builder.ts +++ b/src/expression/expression-builder.ts @@ -516,22 +516,22 @@ export interface ExpressionBuilder { * Returns a value expression that will be serialized before being passed to the database. * * This can be used to pass in an object/array value when inserting/updating a - * value to a column defined with `JSONColumnType`. + * value to a column defined with `Json`. * * Default serializer function is `JSON.stringify`. * * ### Example * * ```ts - * import { GeneratedAlways, JSONColumnType } from 'kysely' + * import { GeneratedAlways, Json } from 'kysely' * * interface Database { * person: { * id: GeneratedAlways * name: string - * experience: JSONColumnType<{ title: string; company: string }[]> - * preferences: JSONColumnType<{ locale: string; timezone: string }> - * profile: JSONColumnType<{ email_verified: boolean }> + * experience: Json<{ title: string; company: string }[]> + * preferences: Json<{ locale: string; timezone: string }> + * profile: Json<{ email_verified: boolean }> * } * } * diff --git a/src/util/column-type.ts b/src/util/column-type.ts index 9398efd9e..98727ee0a 100644 --- a/src/util/column-type.ts +++ b/src/util/column-type.ts @@ -68,13 +68,18 @@ export type Generated = ColumnType export type GeneratedAlways = ColumnType /** - * A shortcut for defining type-safe JSON columns. + * A shortcut for defining type-safe JSON columns. Inserts/updates require passing + * values that are wrapped with `eb.valJson` or `sql.valJson` instead of `JSON.stringify`. */ -export type JSONColumnType = ColumnType< - SelectType, - Serialized | Extract, - Serialized | Extract -> +export type Json< + SelectType extends object | null, + InsertType extends Serialized | Extract = + | Serialized + | Extract, + UpdateType extends Serialized | Extract = + | Serialized + | Extract, +> = ColumnType /** * A symbol that is used to brand serialized objects/arrays. @@ -86,9 +91,20 @@ declare const SerializedBrand: unique symbol * A type that is used to brand serialized objects/arrays. */ export type Serialized = O & { - [SerializedBrand]: '⚠️ When you insert into or update columns of type `JSONColumnType` (or similar), you should wrap your JSON value with `eb.valJson` or `sql.valJson`, instead of `JSON.stringify`. ⚠️' + readonly [SerializedBrand]: '⚠️ When you insert into or update columns of type `Json` (or similar), you should wrap your JSON value with `eb.valJson` or `sql.valJson`, instead of `JSON.stringify`. ⚠️' } +/** + * A shortcut for defining JSON columns, which are by default inserted/updated + * as stringified JSON strings. + * @deprecated Use {@link Json} instead. + */ +export type JSONColumnType< + SelectType extends object | null, + InsertType = string, + UpdateType = string, +> = ColumnType + /** * Evaluates to `K` if `T` can be `null` or `undefined`. */ diff --git a/test/node/src/json-traversal.test.ts b/test/node/src/json-traversal.test.ts index c7d17091a..8ae957282 100644 --- a/test/node/src/json-traversal.test.ts +++ b/test/node/src/json-traversal.test.ts @@ -1,6 +1,6 @@ import { ColumnDefinitionBuilder, - JSONColumnType, + Json, ParseJSONResultsPlugin, SqlBool, sql, @@ -732,9 +732,9 @@ async function initJSONTest( let db = testContext.db.withTables<{ person_metadata: { person_id: number - website: JSONColumnType<{ url: string }> - nicknames: JSONColumnType - profile: JSONColumnType<{ + website: Json<{ url: string }> + nicknames: Json + profile: Json<{ auth: { roles: string[] last_login?: { device: string } @@ -744,12 +744,12 @@ async function initJSONTest( avatar: string | null tags: string[] }> - experience: JSONColumnType< + experience: Json< { establishment: string }[] > - schedule: JSONColumnType<{ name: string; time: string }[][][]> + schedule: Json<{ name: string; time: string }[][][]> } }>() diff --git a/test/typings/shared.d.ts b/test/typings/shared.d.ts index 97cc35dc8..741453df2 100644 --- a/test/typings/shared.d.ts +++ b/test/typings/shared.d.ts @@ -1,9 +1,4 @@ -import { - ColumnType, - Generated, - GeneratedAlways, - JSONColumnType, -} from '../../dist/cjs' +import { ColumnType, Generated, GeneratedAlways, Json } from '../../dist/cjs' export interface Pet { id: Generated @@ -71,21 +66,21 @@ export interface Person { export interface PersonMetadata { id: Generated person_id: number - website: JSONColumnType<{ url: string }> - nicknames: JSONColumnType - profile: JSONColumnType<{ + website: Json<{ url: string }> + nicknames: Json + profile: Json<{ auth: { roles: string[] last_login?: { device: string } } tags: string[] }> - experience: JSONColumnType< + experience: Json< { establishment: string }[] > - schedule: JSONColumnType<{ name: string; time: string }[][][]> - record: JSONColumnType> - array: JSONColumnType | null> + schedule: Json<{ name: string; time: string }[][][]> + record: Json> + array: Json | null> }