Files
evento/node_modules/kysely/dist/esm/helpers/postgres.js
2026-03-18 14:55:56 -03:00

204 lines
6.3 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/// <reference types="./postgres.d.ts" />
import { sql } from '../raw-builder/sql.js';
/**
* A postgres helper for aggregating a subquery (or other expression) into a JSONB array.
*
* ### Examples
*
* <!-- siteExample("select", "Nested array", 110) -->
*
* While kysely is not an ORM and it doesn't have the concept of relations, we do provide
* helpers for fetching nested objects and arrays in a single query. In this example we
* use the `jsonArrayFrom` helper to fetch person's pets along with the person's id.
*
* Please keep in mind that the helpers under the `kysely/helpers` folder, including
* `jsonArrayFrom`, are not guaranteed to work with third party dialects. In order for
* them to work, the dialect must automatically parse the `json` data type into
* JavaScript JSON values like objects and arrays. Some dialects might simply return
* the data as a JSON string. In these cases you can use the built in `ParseJSONResultsPlugin`
* to parse the results.
*
* ```ts
* import { jsonArrayFrom } from 'kysely/helpers/postgres'
*
* const result = await db
* .selectFrom('person')
* .select((eb) => [
* 'id',
* jsonArrayFrom(
* eb.selectFrom('pet')
* .select(['pet.id as pet_id', 'pet.name'])
* .whereRef('pet.owner_id', '=', 'person.id')
* .orderBy('pet.name')
* ).as('pets')
* ])
* .execute()
* ```
*
* The generated SQL (PostgreSQL):
*
* ```sql
* select "id", (
* select coalesce(json_agg(agg), '[]') from (
* select "pet"."id" as "pet_id", "pet"."name"
* from "pet"
* where "pet"."owner_id" = "person"."id"
* order by "pet"."name"
* ) as agg
* ) as "pets"
* from "person"
* ```
*/
export function jsonArrayFrom(expr) {
return sql `(select coalesce(json_agg(agg), '[]') from ${expr} as agg)`;
}
/**
* A postgres helper for turning a subquery (or other expression) into a JSON object.
*
* The subquery must only return one row.
*
* ### Examples
*
* <!-- siteExample("select", "Nested object", 120) -->
*
* While kysely is not an ORM and it doesn't have the concept of relations, we do provide
* helpers for fetching nested objects and arrays in a single query. In this example we
* use the `jsonObjectFrom` helper to fetch person's favorite pet along with the person's id.
*
* Please keep in mind that the helpers under the `kysely/helpers` folder, including
* `jsonObjectFrom`, are not guaranteed to work with third-party dialects. In order for
* them to work, the dialect must automatically parse the `json` data type into
* JavaScript JSON values like objects and arrays. Some dialects might simply return
* the data as a JSON string. In these cases you can use the built in `ParseJSONResultsPlugin`
* to parse the results.
*
* ```ts
* import { jsonObjectFrom } from 'kysely/helpers/postgres'
*
* const result = await db
* .selectFrom('person')
* .select((eb) => [
* 'id',
* jsonObjectFrom(
* eb.selectFrom('pet')
* .select(['pet.id as pet_id', 'pet.name'])
* .whereRef('pet.owner_id', '=', 'person.id')
* .where('pet.is_favorite', '=', true)
* ).as('favorite_pet')
* ])
* .execute()
* ```
*
* The generated SQL (PostgreSQL):
*
* ```sql
* select "id", (
* select to_json(obj) from (
* select "pet"."id" as "pet_id", "pet"."name"
* from "pet"
* where "pet"."owner_id" = "person"."id"
* and "pet"."is_favorite" = $1
* ) as obj
* ) as "favorite_pet"
* from "person"
* ```
*/
export function jsonObjectFrom(expr) {
return sql `(select to_json(obj) from ${expr} as obj)`;
}
/**
* The PostgreSQL `json_build_object` function.
*
* NOTE: This helper is only guaranteed to fully work with the built-in `PostgresDialect`.
* While the produced SQL is compatible with all PostgreSQL databases, some third-party dialects
* may not parse the nested JSON into objects. In these cases you can use the built in
* `ParseJSONResultsPlugin` to parse the results.
*
* ### Examples
*
* ```ts
* import { sql } from 'kysely'
* import { jsonBuildObject } from 'kysely/helpers/postgres'
*
* const result = await db
* .selectFrom('person')
* .select((eb) => [
* 'id',
* jsonBuildObject({
* first: eb.ref('first_name'),
* last: eb.ref('last_name'),
* full: sql<string>`first_name || ' ' || last_name`
* }).as('name')
* ])
* .execute()
*
* result[0]?.id
* result[0]?.name.first
* result[0]?.name.last
* result[0]?.name.full
* ```
*
* The generated SQL (PostgreSQL):
*
* ```sql
* select "id", json_build_object(
* 'first', first_name,
* 'last', last_name,
* 'full', first_name || ' ' || last_name
* ) as "name"
* from "person"
* ```
*/
export function jsonBuildObject(obj) {
return sql `json_build_object(${sql.join(Object.keys(obj).flatMap((k) => [sql.lit(k), obj[k]]))})`;
}
/**
* The PostgreSQL `merge_action` function.
*
* This function can be used in a `returning` clause to get the action that was
* performed in a `mergeInto` query. The function returns one of the following
* strings: `'INSERT'`, `'UPDATE'`, or `'DELETE'`.
*
* ### Examples
*
* ```ts
* import { mergeAction } from 'kysely/helpers/postgres'
*
* const result = await db
* .mergeInto('person as p')
* .using('person_backup as pb', 'p.id', 'pb.id')
* .whenMatched()
* .thenUpdateSet(({ ref }) => ({
* first_name: ref('pb.first_name'),
* updated_at: ref('pb.updated_at').$castTo<string | null>(),
* }))
* .whenNotMatched()
* .thenInsertValues(({ ref}) => ({
* id: ref('pb.id'),
* first_name: ref('pb.first_name'),
* created_at: ref('pb.updated_at'),
* updated_at: ref('pb.updated_at').$castTo<string | null>(),
* }))
* .returning([mergeAction().as('action'), 'p.id', 'p.updated_at'])
* .execute()
*
* result[0].action
* ```
*
* The generated SQL (PostgreSQL):
*
* ```sql
* merge into "person" as "p"
* using "person_backup" as "pb" on "p"."id" = "pb"."id"
* when matched then update set
* "first_name" = "pb"."first_name",
* "updated_at" = "pb"."updated_at"::text
* when not matched then insert values ("id", "first_name", "created_at", "updated_at")
* values ("pb"."id", "pb"."first_name", "pb"."updated_at", "pb"."updated_at")
* returning merge_action() as "action", "p"."id", "p"."updated_at"
* ```
*/
export function mergeAction() {
return sql `merge_action()`;
}