kysely
Version:
Type safe SQL query builder
152 lines (151 loc) • 4.79 kB
JavaScript
/// <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 3rd 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 3rd 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
* 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]]))})`;
}