@webda/postgres
Version:
Implements Postgres on webda
166 lines • 6.23 kB
JavaScript
import { Store, StoreNotFoundError, StoreParameters, UpdateConditionFailError, WebdaQL } from "@webda/core";
export class SQLStoreParameters extends StoreParameters {
}
export class SQLComparisonExpression extends WebdaQL.ComparisonExpression {
toStringValue(value) {
if (typeof value === "string") {
return `'${value.replace(/'/g, "''")}'`;
}
return super.toStringValue(value);
}
toStringAttribute() {
switch (typeof this.value) {
case "boolean":
return `CAST(${this.attribute[0]} AS boolean)`;
case "number":
// coalesce(data#>>'{${this.attribute[0]}}', '0') ?
return `CAST(${this.attribute[0]} AS bigint)`;
default:
return this.attribute[0];
}
}
}
export class SQLStore extends Store {
sqlQuery(q, values) {
q = this.completeQuery(q);
return this.executeQuery(q, values);
}
/**
* Add the SELECT * FROM table if the query is not a full query
* @param q query to complete
* @returns
*/
completeQuery(q) {
// Should add the INNER JOIN from map
// this.parameters.map
// SELECT * FROM table as t1 LEFT JOIN table2 as t2 ON t2.target = t1.uuid
// if not same db: table2 is map_${name}_external
if (!q.startsWith("DELETE") && !q.startsWith("INSERT") && !q.startsWith("SELECT") && !q.startsWith("UPDATE")) {
return `SELECT * FROM ${this.parameters.table} WHERE ${q}`;
}
return q;
}
/**
* @override
*/
async _delete(uid, writeCondition, writeConditionField) {
let query = `DELETE FROM ${this.parameters.table} WHERE uuid=$1`;
const args = [uid];
if (writeCondition) {
query += this.getQueryCondition(writeCondition, writeConditionField, args);
}
let res = await this.sqlQuery(query, args);
if (res.rowCount === 0 && writeCondition) {
throw new UpdateConditionFailError(uid, writeConditionField, writeCondition);
}
}
duplicateExpression(expression) {
if (expression instanceof WebdaQL.AndExpression) {
return new WebdaQL.AndExpression(expression.children.map(exp => this.duplicateExpression(exp)));
}
else if (expression instanceof WebdaQL.OrExpression) {
return new WebdaQL.OrExpression(expression.children.map(exp => this.duplicateExpression(exp)));
}
else if (expression instanceof WebdaQL.ComparisonExpression) {
if (expression.operator === "IN") {
const attr = this.mapExpressionAttribute(expression.attribute);
return new WebdaQL.OrExpression(expression.value.map(v => new SQLComparisonExpression("=", attr, v)));
}
if (expression.operator === "CONTAINS") {
return new SQLComparisonExpression(
// Small hack
"?", "(" + this.mapExpressionAttribute(expression.attribute, false) + ")", expression.value);
}
return new SQLComparisonExpression(expression.operator, this.mapExpressionAttribute(expression.attribute), expression.value);
}
}
/**
* @override
*/
async find(query) {
// Update condition
let sql = this.duplicateExpression(query.filter).toString() || "TRUE";
let offset = 0;
offset = parseInt(query.continuationToken || "0", 10);
if (query.orderBy && query.orderBy.length) {
sql +=
" ORDER BY " +
query.orderBy.map(c => `${this.mapExpressionAttribute(c.field.split("."))} ${c.direction}`).join(", ");
}
sql += ` LIMIT ${query.limit || "1000"}`;
if (offset) {
sql += ` OFFSET ${offset}`;
}
const results = (await this.sqlQuery(sql, [])).rows.map(c => this.initModel(c));
return {
results,
continuationToken: query.limit <= results.length ? (offset + query.limit).toString() : undefined,
filter: new WebdaQL.AndExpression([])
};
}
/**
* @override
*/
async _exists(uid) {
let res = await this.sqlQuery(`SELECT uuid FROM ${this.parameters.table} WHERE ${this.getModel().getUuidField()} = $1`, [this.getUuid(uid)]);
return res.rowCount === 1;
}
/**
* @override
*/
async _get(uid, raiseIfNotFound) {
let res = await this.sqlQuery(`${this.getModel().getUuidField()} = $1`, [this.getUuid(uid)]);
if (res.rowCount === 0 && raiseIfNotFound) {
throw new StoreNotFoundError(uid, this.getName());
}
return res.rows.shift();
}
/**
* @override
*/
async getAll(list) {
if (list) {
return (await this.sqlQuery(list.map((_, index) => `uuid=$${index + 1}`).join(" OR "), list)).rows;
}
return (await this.sqlQuery("TRUE", [])).rows;
}
/**
* @override
*/
async _update(object, uid, itemWriteCondition, itemWriteConditionField) {
let q = `UPDATE ${this.parameters.table} SET data=$1 WHERE uuid=$2`;
const args = [object.toStoredJSON(true), this.getUuid(uid)];
if (itemWriteCondition) {
q += this.getQueryCondition(itemWriteCondition, itemWriteConditionField, args);
}
let res = await this.sqlQuery(q, args);
if (res.rowCount === 0) {
throw new UpdateConditionFailError(uid, itemWriteConditionField, itemWriteCondition);
}
return object;
}
getUuid(object) {
let id;
if (typeof object === "string") {
id = object;
}
else {
id = object.getUuid();
}
return id;
}
/**
* @override
*/
async _save(object) {
await this.sqlQuery(`INSERT INTO ${this.parameters.table}(uuid,data) VALUES($1, $2)`, [
this.getUuid(object),
object.toStoredJSON(true)
]);
return object;
}
async __clean() {
await this.sqlQuery(`DELETE FROM ${this.parameters.table}`, []);
}
}
//# sourceMappingURL=sqlstore.js.map