@tealbase/postgres-js
Version:
Isomorphic PostgREST client
514 lines • 17.5 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import fetch from 'isomorphic-unfetch';
import { URL } from 'url';
/**
* Base builder
*/
export class PostgrestBuilder {
constructor(builder) {
Object.assign(this, builder);
}
then(onfulfilled, onrejected) {
// https://postgrest.org/en/stable/api.html#switching-schemas
if (typeof this.schema === 'undefined') {
// skip
}
else if (['GET', 'HEAD'].includes(this.method)) {
this.headers['Accept-Profile'] = this.schema;
}
else {
this.headers['Content-Profile'] = this.schema;
}
if (this.method !== 'GET' && this.method !== 'HEAD') {
this.headers['Content-Type'] = 'application/json';
}
return fetch(this.url.toString(), {
method: this.method,
headers: this.headers,
body: JSON.stringify(this.body),
})
.then((res) => __awaiter(this, void 0, void 0, function* () {
let error, data;
if (res.ok) {
error = null;
data = yield res.json();
}
else {
error = yield res.json();
data = null;
}
return {
error,
data,
status: res.status,
statusText: res.statusText,
body: data,
};
}))
.then(onfulfilled, onrejected);
}
}
/**
* CRUD
*/
export class PostgrestQueryBuilder extends PostgrestBuilder {
constructor(url, { headers = {}, schema } = {}) {
super({});
this.url = new URL(url);
this.headers = headers;
this.schema = schema;
}
/**
* Performs horizontal filtering with SELECT.
*
* @param columns The columns to retrieve, separated by commas.
*/
select(columns = '*') {
this.method = 'GET';
// Remove whitespaces except when quoted
let quoted = false;
const cleanedColumns = columns
.split('')
.map((c) => {
if (/\s/.test(c) && !quoted) {
return '';
}
if (c === '"') {
quoted = !quoted;
}
return c;
})
.join('');
this.url.searchParams.set('select', cleanedColumns);
return new PostgrestFilterBuilder(this);
}
/**
* Performs an INSERT into the table.
*
* @param values The values to insert.
* @param upsert If `true`, performs an UPSERT.
*/
insert(values, { upsert = false } = {}) {
this.method = 'POST';
this.headers['Prefer'] = upsert
? 'return=representation,resolution=merge-duplicates'
: 'return=representation';
this.body = values;
return this;
}
/**
* Performs an UPDATE on the table.
*
* @param values The values to update.
*/
update(values) {
this.method = 'PATCH';
this.headers['Prefer'] = 'return=representation';
this.body = values;
return new PostgrestFilterBuilder(this);
}
/**
* Performs a DELETE on the table.
*/
delete() {
this.method = 'DELETE';
this.headers['Prefer'] = 'return=representation';
return new PostgrestFilterBuilder(this);
}
/** @internal */
rpc(params) {
this.method = 'POST';
this.body = params;
return this;
}
}
/**
* Post-filters (transforms)
*/
class PostgrestTransformBuilder extends PostgrestBuilder {
/**
* Orders the result with the specified `column`.
*
* @param column The column to order on.
* @param ascending If `true`, the result will be in ascending order.
* @param nullsFirst If `true`, `null`s appear first.
* @param foreignTable The foreign table to use (if `column` is a foreign column).
*/
order(column, { ascending = true, nullsFirst = false, foreignTable, } = {}) {
const key = typeof foreignTable === 'undefined' ? 'order' : `"${foreignTable}".order`;
this.url.searchParams.set(key, `"${column}".${ascending ? 'asc' : 'desc'}.${nullsFirst ? 'nullsfirst' : 'nullslast'}`);
return this;
}
/**
* Limits the result with the specified `count`.
*
* @param count The maximum no. of rows to limit to.
* @param foreignTable The foreign table to use (for foreign columns).
*/
limit(count, { foreignTable } = {}) {
const key = typeof foreignTable === 'undefined' ? 'limit' : `"${foreignTable}".limit`;
this.url.searchParams.set(key, `${count}`);
return this;
}
/**
* Limits the result to rows within the specified range, inclusive.
*
* @param from The starting index from which to limit the result, inclusive.
* @param to The last index to which to limit the result, inclusive.
* @param foreignTable The foreign table to use (for foreign columns).
*/
range(from, to, { foreignTable } = {}) {
const keyOffset = typeof foreignTable === 'undefined' ? 'offset' : `"${foreignTable}".offset`;
const keyLimit = typeof foreignTable === 'undefined' ? 'limit' : `"${foreignTable}".limit`;
this.url.searchParams.set(keyOffset, `${from}`);
// Range is inclusive, so add 1
this.url.searchParams.set(keyLimit, `${to - from + 1}`);
return this;
}
/**
* Retrieves only one row from the result. Result must be one row (e.g. using
* `limit`), otherwise this will result in an error.
*/
single() {
this.headers['Accept'] = 'application/vnd.pgrst.object+json';
return this;
}
}
/**
* Filters
*/
const cleanFilterArray = (filter) => filter.map((s) => `"${s}"`).join(',');
class PostgrestFilterBuilder extends PostgrestTransformBuilder {
/**
* Finds all rows which doesn't satisfy the filter.
*
* @param column The column to filter on.
* @param operator The operator to filter with.
* @param value The value to filter with.
*/
not(column, operator, value) {
this.url.searchParams.append(`${column}`, `not.${operator}.${value}`);
return this;
}
/**
* Finds all rows satisfying at least one of the filters.
*
* @param filters The filters to use, separated by commas.
*/
or(filters) {
this.url.searchParams.append('or', `(${filters})`);
return this;
}
/**
* Finds all rows whose value on the stated `column` exactly matches the
* specified `value`.
*
* @param column The column to filter on.
* @param value The value to filter with.
*/
eq(column, value) {
this.url.searchParams.append(`${column}`, `eq.${value}`);
return this;
}
/**
* Finds all rows whose value on the stated `column` doesn't match the
* specified `value`.
*
* @param column The column to filter on.
* @param value The value to filter with.
*/
neq(column, value) {
this.url.searchParams.append(`${column}`, `neq.${value}`);
return this;
}
/**
* Finds all rows whose value on the stated `column` is greater than the
* specified `value`.
*
* @param column The column to filter on.
* @param value The value to filter with.
*/
gt(column, value) {
this.url.searchParams.append(`${column}`, `gt.${value}`);
return this;
}
/**
* Finds all rows whose value on the stated `column` is greater than or
* equal to the specified `value`.
*
* @param column The column to filter on.
* @param value The value to filter with.
*/
gte(column, value) {
this.url.searchParams.append(`${column}`, `gte.${value}`);
return this;
}
/**
* Finds all rows whose value on the stated `column` is less than the
* specified `value`.
*
* @param column The column to filter on.
* @param value The value to filter with.
*/
lt(column, value) {
this.url.searchParams.append(`${column}`, `lt.${value}`);
return this;
}
/**
* Finds all rows whose value on the stated `column` is less than or equal
* to the specified `value`.
*
* @param column The column to filter on.
* @param value The value to filter with.
*/
lte(column, value) {
this.url.searchParams.append(`${column}`, `lte.${value}`);
return this;
}
/**
* Finds all rows whose value in the stated `column` matches the supplied
* `pattern` (case sensitive).
*
* @param column The column to filter on.
* @param pattern The pattern to filter with.
*/
like(column, pattern) {
this.url.searchParams.append(`${column}`, `like.${pattern}`);
return this;
}
/**
* Finds all rows whose value in the stated `column` matches the supplied
* `pattern` (case insensitive).
*
* @param column The column to filter on.
* @param pattern The pattern to filter with.
*/
ilike(column, pattern) {
this.url.searchParams.append(`${column}`, `ilike.${pattern}`);
return this;
}
/**
* A check for exact equality (null, true, false), finds all rows whose
* value on the stated `column` exactly match the specified `value`.
*
* @param column The column to filter on.
* @param value The value to filter with.
*/
is(column, value) {
this.url.searchParams.append(`${column}`, `is.${value}`);
return this;
}
/**
* Finds all rows whose value on the stated `column` is found on the
* specified `values`.
*
* @param column The column to filter on.
* @param values The values to filter with.
*/
in(column, values) {
this.url.searchParams.append(`${column}`, `in.(${cleanFilterArray(values)})`);
return this;
}
/**
* Finds all rows whose json, array, or range value on the stated `column`
* contains the values specified in `value`.
*
* @param column The column to filter on.
* @param value The value to filter with.
*/
cs(column, value) {
if (typeof value === 'string') {
// range types can be inclusive '[', ']' or exclusive '(', ')' so just
// keep it simple and accept a string
this.url.searchParams.append(`${column}`, `cs.${value}`);
}
else if (Array.isArray(value)) {
// array
this.url.searchParams.append(`${column}`, `cs.{${cleanFilterArray(value)}}`);
}
else {
// json
this.url.searchParams.append(`${column}`, `cs.${JSON.stringify(value)}`);
}
return this;
}
/**
* Finds all rows whose json, array, or range value on the stated `column` is
* contained by the specified `value`.
*
* @param column The column to filter on.
* @param value The value to filter with.
*/
cd(column, value) {
if (typeof value === 'string') {
// range
this.url.searchParams.append(`${column}`, `cd.${value}`);
}
else if (Array.isArray(value)) {
// array
this.url.searchParams.append(`${column}`, `cd.{${cleanFilterArray(value)}}`);
}
else {
// json
this.url.searchParams.append(`${column}`, `cd.${JSON.stringify(value)}`);
}
return this;
}
/**
* Finds all rows whose range value on the stated `column` is strictly to the
* left of the specified `range`.
*
* @param column The column to filter on.
* @param range The range to filter with.
*/
sl(column, range) {
this.url.searchParams.append(`${column}`, `sl.${range}`);
return this;
}
/**
* Finds all rows whose range value on the stated `column` is strictly to
* the right of the specified `range`.
*
* @param column The column to filter on.
* @param range The range to filter with.
*/
sr(column, range) {
this.url.searchParams.append(`${column}`, `sr.${range}`);
return this;
}
/**
* Finds all rows whose range value on the stated `column` does not extend
* to the left of the specified `range`.
*
* @param column The column to filter on.
* @param range The range to filter with.
*/
nxl(column, range) {
this.url.searchParams.append(`${column}`, `nxl.${range}`);
return this;
}
/**
* Finds all rows whose range value on the stated `column` does not extend
* to the right of the specified `range`.
*
* @param column The column to filter on.
* @param range The range to filter with.
*/
nxr(column, range) {
this.url.searchParams.append(`${column}`, `nxr.${range}`);
return this;
}
/**
* Finds all rows whose range value on the stated `column` is adjacent to
* the specified `range`.
*
* @param column The column to filter on.
* @param range The range to filter with.
*/
adj(column, range) {
this.url.searchParams.append(`${column}`, `adj.${range}`);
return this;
}
/**
* Finds all rows whose array or range value on the stated `column` is
* contained by the specified `value`.
*
* @param column The column to filter on.
* @param value The value to filter with.
*/
ov(column, value) {
if (typeof value === 'string') {
// range
this.url.searchParams.append(`${column}`, `ov.${value}`);
}
else {
// array
this.url.searchParams.append(`${column}`, `ov.{${cleanFilterArray(value)}}`);
}
return this;
}
/**
* Finds all rows whose tsvector value on the stated `column` matches
* to_tsquery(`query`).
*
* @param column The column to filter on.
* @param query The Postgres tsquery string to filter with.
* @param config The text search configuration to use.
*/
fts(column, query, { config } = {}) {
const configPart = typeof config === 'undefined' ? '' : `(${config})`;
this.url.searchParams.append(`${column}`, `fts${configPart}.${query}`);
return this;
}
/**
* Finds all rows whose tsvector value on the stated `column` matches
* plainto_tsquery(`query`).
*
* @param column The column to filter on.
* @param query The Postgres tsquery string to filter with.
* @param config The text search configuration to use.
*/
plfts(column, query, { config } = {}) {
const configPart = typeof config === 'undefined' ? '' : `(${config})`;
this.url.searchParams.append(`${column}`, `plfts${configPart}.${query}`);
return this;
}
/**
* Finds all rows whose tsvector value on the stated `column` matches
* phraseto_tsquery(`query`).
*
* @param column The column to filter on.
* @param query The Postgres tsquery string to filter with.
* @param config The text search configuration to use.
*/
phfts(column, query, { config } = {}) {
const configPart = typeof config === 'undefined' ? '' : `(${config})`;
this.url.searchParams.append(`${column}`, `phfts${configPart}.${query}`);
return this;
}
/**
* Finds all rows whose tsvector value on the stated `column` matches
* websearch_to_tsquery(`query`).
*
* @param column The column to filter on.
* @param query The Postgres tsquery string to filter with.
* @param config The text search configuration to use.
*/
wfts(column, query, { config } = {}) {
const configPart = typeof config === 'undefined' ? '' : `(${config})`;
this.url.searchParams.append(`${column}`, `wfts${configPart}.${query}`);
return this;
}
/**
* Finds all rows whose `column` satisfies the filter.
*
* @param column The column to filter on.
* @param operator The operator to filter with.
* @param value The value to filter with.
*/
filter(column, operator, value) {
this.url.searchParams.append(`${column}`, `${operator}.${value}`);
return this;
}
/**
* Finds all rows whose columns match the specified `query` object.
*
* @param query The object to filter with, with column names as keys mapped
* to their filter values.
*/
match(query) {
Object.keys(query).forEach((key) => {
this.url.searchParams.append(`${key}`, `eq.${query[key]}`);
});
return this;
}
}
//# sourceMappingURL=builder.js.map