"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const PostgrestFilterBuilder_1 = tslib_1.__importDefault(require("./PostgrestFilterBuilder"));
class PostgrestQueryBuilder {
/**
* Creates a query builder scoped to a Postgres table or view.
*
* @example
* ```ts
* import PostgrestQueryBuilder from '@supabase/postgrest-js'
*
* const query = new PostgrestQueryBuilder(
* new URL('https://xyzcompany.supabase.co/rest/v1/users'),
* { headers: { apikey: 'public-anon-key' } }
* )
* ```
*/
constructor(url, { headers = {}, schema, fetch, }) {
this.url = url;
this.headers = new Headers(headers);
this.schema = schema;
this.fetch = fetch;
}
/**
* Perform a SELECT query on the table or view.
*
* @param columns - The columns to retrieve, separated by commas. Columns can be renamed when returned with `customName:columnName`
*
* @param options - Named parameters
*
* @param options.head - When set to `true`, `data` will not be returned.
* Useful if you only need the count.
*
* @param options.count - Count algorithm to use to count rows in the table or view.
*
* `"exact"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the
* hood.
*
* `"planned"`: Approximated but fast count algorithm. Uses the Postgres
* statistics under the hood.
*
* `"estimated"`: Uses exact count for low numbers and planned count for high
* numbers.
*/
select(columns, options) {
const { head = false, count } = options !== null && options !== void 0 ? options : {};
const method = head ? 'HEAD' : 'GET';
// Remove whitespaces except when quoted
let quoted = false;
const cleanedColumns = (columns !== null && columns !== void 0 ? columns : '*')
.split('')
.map((c) => {
if (/\s/.test(c) && !quoted) {
return '';
}
if (c === '"') {
quoted = !quoted;
}
return c;
})
.join('');
this.url.searchParams.set('select', cleanedColumns);
if (count) {
this.headers.append('Prefer', `count=${count}`);
}
return new PostgrestFilterBuilder_1.default({
method,
url: this.url,
headers: this.headers,
schema: this.schema,
fetch: this.fetch,
});
}
/**
* Perform an INSERT into the table or view.
*
* By default, inserted rows are not returned. To return it, chain the call
* with `.select()`.
*
* @param values - The values to insert. Pass an object to insert a single row
* or an array to insert multiple rows.
*
* @param options - Named parameters
*
* @param options.count - Count algorithm to use to count inserted rows.
*
* `"exact"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the
* hood.
*
* `"planned"`: Approximated but fast count algorithm. Uses the Postgres
* statistics under the hood.
*
* `"estimated"`: Uses exact count for low numbers and planned count for high
* numbers.
*
* @param options.defaultToNull - Make missing fields default to `null`.
* Otherwise, use the default value for the column. Only applies for bulk
* inserts.
*/
insert(values, { count, defaultToNull = true, } = {}) {
var _a;
const method = 'POST';
if (count) {
this.headers.append('Prefer', `count=${count}`);
}
if (!defaultToNull) {
this.headers.append('Prefer', `missing=default`);
}
if (Array.isArray(values)) {
const columns = values.reduce((acc, x) => acc.concat(Object.keys(x)), []);
if (columns.length > 0) {
const uniqueColumns = [...new Set(columns)].map((column) => `"${column}"`);
this.url.searchParams.set('columns', uniqueColumns.join(','));
}
}
return new PostgrestFilterBuilder_1.default({
method,
url: this.url,
headers: this.headers,
schema: this.schema,
body: values,
fetch: (_a = this.fetch) !== null && _a !== void 0 ? _a : fetch,
});
}
/**
* Perform an UPSERT on the table or view. Depending on the column(s) passed
* to `onConflict`, `.upsert()` allows you to perform the equivalent of
* `.insert()` if a row with the corresponding `onConflict` columns doesn't
* exist, or if it does exist, perform an alternative action depending on
* `ignoreDuplicates`.
*
* By default, upserted rows are not returned. To return it, chain the call
* with `.select()`.
*
* @param values - The values to upsert with. Pass an object to upsert a
* single row or an array to upsert multiple rows.
*
* @param options - Named parameters
*
* @param options.onConflict - Comma-separated UNIQUE column(s) to specify how
* duplicate rows are determined. Two rows are duplicates if all the
* `onConflict` columns are equal.
*
* @param options.ignoreDuplicates - If `true`, duplicate rows are ignored. If
* `false`, duplicate rows are merged with existing rows.
*
* @param options.count - Count algorithm to use to count upserted rows.
*
* `"exact"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the
* hood.
*
* `"planned"`: Approximated but fast count algorithm. Uses the Postgres
* statistics under the hood.
*
* `"estimated"`: Uses exact count for low numbers and planned count for high
* numbers.
*
* @param options.defaultToNull - Make missing fields default to `null`.
* Otherwise, use the default value for the column. This only applies when
* inserting new rows, not when merging with existing rows under
* `ignoreDuplicates: false`. This also only applies when doing bulk upserts.
*
* @example Upsert a single row using a unique key
* ```ts
* // Upserting a single row, overwriting based on the 'username' unique column
* const { data, error } = await supabase
* .from('users')
* .upsert({ username: 'supabot' }, { onConflict: 'username' })
*
* // Example response:
* // {
* // data: [
* // { id: 4, message: 'bar', username: 'supabot' }
* // ],
* // error: null
* // }
* ```
*
* @example Upsert with conflict resolution and exact row counting
* ```ts
* // Upserting and returning exact count
* const { data, error, count } = await supabase
* .from('users')
* .upsert(
* {
* id: 3,
* message: 'foo',
* username: 'supabot'
* },
* {
* onConflict: 'username',
* count: 'exact'
* }
* )
*
* // Example response:
* // {
* // data: [
* // {
* // id: 42,
* // handle: "saoirse",
* // display_name: "Saoirse"
* // }
* // ],
* // count: 1,
* // error: null
* // }
* ```
*/
upsert(values, { onConflict, ignoreDuplicates = false, count, defaultToNull = true, } = {}) {
var _a;
const method = 'POST';
this.headers.append('Prefer', `resolution=${ignoreDuplicates ? 'ignore' : 'merge'}-duplicates`);
if (onConflict !== undefined)
this.url.searchParams.set('on_conflict', onConflict);
if (count) {
this.headers.append('Prefer', `count=${count}`);
}
if (!defaultToNull) {
this.headers.append('Prefer', 'missing=default');
}
if (Array.isArray(values)) {
const columns = values.reduce((acc, x) => acc.concat(Object.keys(x)), []);
if (columns.length > 0) {
const uniqueColumns = [...new Set(columns)].map((column) => `"${column}"`);
this.url.searchParams.set('columns', uniqueColumns.join(','));
}
}
return new PostgrestFilterBuilder_1.default({
method,
url: this.url,
headers: this.headers,
schema: this.schema,
body: values,
fetch: (_a = this.fetch) !== null && _a !== void 0 ? _a : fetch,
});
}
/**
* Perform an UPDATE on the table or view.
*
* By default, updated rows are not returned. To return it, chain the call
* with `.select()` after filters.
*
* @param values - The values to update with
*
* @param options - Named parameters
*
* @param options.count - Count algorithm to use to count updated rows.
*
* `"exact"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the
* hood.
*
* `"planned"`: Approximated but fast count algorithm. Uses the Postgres
* statistics under the hood.
*
* `"estimated"`: Uses exact count for low numbers and planned count for high
* numbers.
*/
update(values, { count, } = {}) {
var _a;
const method = 'PATCH';
if (count) {
this.headers.append('Prefer', `count=${count}`);
}
return new PostgrestFilterBuilder_1.default({
method,
url: this.url,
headers: this.headers,
schema: this.schema,
body: values,
fetch: (_a = this.fetch) !== null && _a !== void 0 ? _a : fetch,
});
}
/**
* Perform a DELETE on the table or view.
*
* By default, deleted rows are not returned. To return it, chain the call
* with `.select()` after filters.
*
* @param options - Named parameters
*
* @param options.count - Count algorithm to use to count deleted rows.
*
* `"exact"`: Exact but slow count algorithm. Performs a `COUNT(*)` under the
* hood.
*
* `"planned"`: Approximated but fast count algorithm. Uses the Postgres
* statistics under the hood.
*
* `"estimated"`: Uses exact count for low numbers and planned count for high
* numbers.
*/
delete({ count, } = {}) {
var _a;
const method = 'DELETE';
if (count) {
this.headers.append('Prefer', `count=${count}`);
}
return new PostgrestFilterBuilder_1.default({
method,
url: this.url,
headers: this.headers,
schema: this.schema,
fetch: (_a = this.fetch) !== null && _a !== void 0 ? _a : fetch,
});
}
}
exports.default = PostgrestQueryBuilder;
//# sourceMappingURL=PostgrestQueryBuilder.js.map