mirror of
https://github.com/nextapps-de/flexsearch.git
synced 2025-09-26 21:38:58 +02:00
bundle pre-release
This commit is contained in:
971
dist/module-debug/db/postgres/index.js
vendored
Normal file
971
dist/module-debug/db/postgres/index.js
vendored
Normal file
@@ -0,0 +1,971 @@
|
||||
|
||||
|
||||
import pg_promise from "pg-promise";
|
||||
import StorageInterface from "../interface.js";
|
||||
import Document from "../../document.js";
|
||||
import { concat, toArray } from "../../common.js";
|
||||
const defaults = {
|
||||
schema: "flexsearch",
|
||||
user: "postgres",
|
||||
pass: "postgres",
|
||||
name: "postgres",
|
||||
host: "localhost",
|
||||
port: "5432"
|
||||
},
|
||||
pgp = pg_promise(),
|
||||
VERSION = 1,
|
||||
MAXIMUM_QUERY_VARS = 16000,
|
||||
fields = ["map", "ctx", "reg", "tag", "cfg"],
|
||||
types = {
|
||||
text: "text",
|
||||
char: "text",
|
||||
varchar: "text",
|
||||
string: "text",
|
||||
number: "int",
|
||||
numeric: "int",
|
||||
integer: "int",
|
||||
smallint: "int",
|
||||
tinyint: "int",
|
||||
mediumint: "int",
|
||||
int: "int",
|
||||
int8: "int",
|
||||
uint8: "int",
|
||||
int16: "int",
|
||||
uint16: "int",
|
||||
int32: "int",
|
||||
uint32: "bigint",
|
||||
int64: "bigint",
|
||||
bigint: "bigint"
|
||||
};
|
||||
|
||||
|
||||
function sanitize(str) {
|
||||
return str.toLowerCase().replace(/[^a-z0-9_]/g, "");
|
||||
}
|
||||
|
||||
let DB, TRX;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @implements StorageInterface
|
||||
*/
|
||||
|
||||
export default function PostgresDB(name, config = {}) {
|
||||
if (!(this instanceof PostgresDB)) {
|
||||
return new PostgresDB(name, config);
|
||||
}
|
||||
if ("object" == typeof name) {
|
||||
name = name.name;
|
||||
config = name;
|
||||
}
|
||||
if (!name) {
|
||||
console.info("Default storage space was used, because a name was not passed.");
|
||||
}
|
||||
this.id = (config.schema ? sanitize(config.schema) : defaults.schema) + (name ? "_" + sanitize(name) : "");
|
||||
this.field = config.field ? "_" + sanitize(config.field) : "";
|
||||
this.type = config.type ? types[config.type.toLowerCase()] : "text";
|
||||
this.support_tag_search = /* tag? */!0 /*await rows.hasNext()*/ /*await rows.hasNext()*/ /*await rows.hasNext()*/;
|
||||
if (!this.type) throw new Error("Unknown type of ID '" + config.type + "'");
|
||||
this.db = DB || (DB = config.db || null);
|
||||
Object.assign(defaults, config);
|
||||
this.db && delete defaults.db;
|
||||
}
|
||||
|
||||
PostgresDB.prototype.mount = function (flexsearch) {
|
||||
if (flexsearch instanceof Document) {
|
||||
return flexsearch.mount(this);
|
||||
}
|
||||
flexsearch.db = this;
|
||||
return this.open();
|
||||
};
|
||||
|
||||
PostgresDB.prototype.open = async function () {
|
||||
|
||||
if (!this.db) {
|
||||
this.db = DB || (DB = pgp(`postgres://${defaults.user}:${encodeURIComponent(defaults.pass)}@${defaults.host}:${defaults.port}/${defaults.name}`));
|
||||
}
|
||||
|
||||
const exist = await this.db.oneOrNone(`
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.schemata
|
||||
WHERE schema_name = '${this.id}'
|
||||
);
|
||||
`);
|
||||
if (!exist || !exist.exists) {
|
||||
await this.db.none(`CREATE SCHEMA IF NOT EXISTS ${this.id};`);
|
||||
}
|
||||
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
const exist = await this.db.oneOrNone(`
|
||||
SELECT EXISTS (
|
||||
SELECT 1 FROM pg_tables
|
||||
WHERE schemaname = '${this.id}' AND tablename = '${fields[i] + ("reg" !== fields[i] ? this.field : "")}'
|
||||
);
|
||||
`);
|
||||
if (exist && exist.exists) continue;
|
||||
|
||||
const type = "text" === this.type ? "varchar(128)" : this.type;
|
||||
|
||||
switch (fields[i]) {
|
||||
case "map":
|
||||
await this.db.none(`
|
||||
CREATE TABLE IF NOT EXISTS ${this.id}.map${this.field}(
|
||||
key varchar(128) NOT NULL,
|
||||
res smallint NOT NULL,
|
||||
id ${type} NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ${this.id}_map_index${this.field}
|
||||
ON ${this.id}.map${this.field} (key);
|
||||
CREATE INDEX IF NOT EXISTS ${this.id}_map_id${this.field}
|
||||
ON ${this.id}.map${this.field} (id);
|
||||
`);
|
||||
break;
|
||||
|
||||
case "ctx":
|
||||
await this.db.none(`
|
||||
CREATE TABLE IF NOT EXISTS ${this.id}.ctx${this.field}(
|
||||
ctx varchar(128) NOT NULL,
|
||||
key varchar(128) NOT NULL,
|
||||
res smallint NOT NULL,
|
||||
id ${type} NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ${this.id}_ctx_index${this.field}
|
||||
ON ${this.id}.ctx${this.field} (ctx, key);
|
||||
CREATE INDEX IF NOT EXISTS ${this.id}_ctx_id${this.field}
|
||||
ON ${this.id}.ctx${this.field} (id);
|
||||
`);
|
||||
break;
|
||||
|
||||
case "tag":
|
||||
await this.db.none(`
|
||||
CREATE TABLE IF NOT EXISTS ${this.id}.tag${this.field}(
|
||||
tag varchar(128) NOT NULL,
|
||||
id ${type} NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS ${this.id}_tag_index${this.field}
|
||||
ON ${this.id}.tag${this.field} (tag);
|
||||
CREATE INDEX IF NOT EXISTS ${this.id}_tag_id${this.field}
|
||||
ON ${this.id}.tag${this.field} (id);
|
||||
`);
|
||||
break;
|
||||
|
||||
case "reg":
|
||||
await this.db.none(`
|
||||
CREATE TABLE IF NOT EXISTS ${this.id}.reg(
|
||||
id ${type} NOT NULL
|
||||
CONSTRAINT ${this.id}_reg_pk
|
||||
PRIMARY KEY,
|
||||
doc text DEFAULT NULL
|
||||
);
|
||||
`).catch(() => {
|
||||
// document indexes will try to create same registry table
|
||||
// and the "IF NOT EXISTS" did not apply on parallel
|
||||
});
|
||||
break;
|
||||
|
||||
case "cfg":
|
||||
await this.db.none(`
|
||||
CREATE TABLE IF NOT EXISTS ${this.id}.cfg${this.field}(
|
||||
cfg text NOT NULL
|
||||
);
|
||||
`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return this.db;
|
||||
};
|
||||
|
||||
PostgresDB.prototype.close = function () {
|
||||
this.db.close && this.db.close();
|
||||
this.db = DB = null;
|
||||
return this;
|
||||
};
|
||||
|
||||
PostgresDB.prototype.destroy = async function () {
|
||||
await this.db.none(`
|
||||
DROP TABLE IF EXISTS ${this.id}.map${this.field};
|
||||
DROP TABLE IF EXISTS ${this.id}.ctx${this.field};
|
||||
DROP TABLE IF EXISTS ${this.id}.tag${this.field};
|
||||
DROP TABLE IF EXISTS ${this.id}.cfg${this.field};
|
||||
DROP TABLE IF EXISTS ${this.id}.reg;
|
||||
`);
|
||||
this.close();
|
||||
};
|
||||
|
||||
PostgresDB.prototype.clear = function () {
|
||||
return this.db.none(`
|
||||
TRUNCATE TABLE ${this.id}.map${this.field};
|
||||
TRUNCATE TABLE ${this.id}.ctx${this.field};
|
||||
TRUNCATE TABLE ${this.id}.tag${this.field};
|
||||
TRUNCATE TABLE ${this.id}.cfg${this.field};
|
||||
TRUNCATE TABLE ${this.id}.reg;
|
||||
`);
|
||||
};
|
||||
|
||||
function create_result(rows, resolve, enrich) {
|
||||
if (resolve) {
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
if (enrich) {
|
||||
if (rows[i].doc) {
|
||||
rows[i].doc = JSON.parse(rows[i].doc);
|
||||
}
|
||||
} else {
|
||||
rows[i] = rows[i].id;
|
||||
}
|
||||
}
|
||||
return rows;
|
||||
} else {
|
||||
const arr = [];
|
||||
for (let i = 0, row; i < rows.length; i++) {
|
||||
row = rows[i];
|
||||
arr[row.res] || (arr[row.res] = []);
|
||||
arr[row.res].push(enrich ? row : row.id);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
|
||||
PostgresDB.prototype.get = function (key, ctx, limit = 0, offset = 0, resolve = !0, enrich = !1, tags) {
|
||||
let rows,
|
||||
stmt = '',
|
||||
params = ctx ? [ctx, key] : [key],
|
||||
table = this.id + (ctx ? ".ctx" : ".map") + this.field;
|
||||
|
||||
if (tags) {
|
||||
for (let i = 0, count = params.length + 1; i < tags.length; i += 2) {
|
||||
stmt += ` AND ${table}.id IN (SELECT id FROM ${this.id}.tag_${sanitize(tags[i])} WHERE tag = $${count++})`;
|
||||
params.push(tags[i + 1]);
|
||||
}
|
||||
}
|
||||
if (ctx) {
|
||||
rows = this.db.any(`
|
||||
SELECT ${table}.id
|
||||
${resolve ? "" : ", res"}
|
||||
${enrich ? ", doc" : ""}
|
||||
FROM ${table}
|
||||
${enrich ? `
|
||||
LEFT JOIN ${this.id}.reg ON ${this.id}.reg.id = ${table}.id
|
||||
` : ""}
|
||||
WHERE ctx = $1 AND key = $2 ${stmt}
|
||||
ORDER BY res
|
||||
${limit ? "LIMIT " + limit : ""}
|
||||
${offset ? "OFFSET " + offset : ""}`, params);
|
||||
} else {
|
||||
rows = this.db.any(`
|
||||
SELECT ${table}.id
|
||||
${resolve ? "" : ", res"}
|
||||
${enrich ? ", doc" : ""}
|
||||
FROM ${table}
|
||||
${enrich ? `
|
||||
LEFT JOIN ${this.id}.reg ON ${this.id}.reg.id = ${table}.id
|
||||
` : ""}
|
||||
WHERE key = $1 ${stmt}
|
||||
ORDER BY res
|
||||
${limit ? "LIMIT " + limit : ""}
|
||||
${offset ? "OFFSET " + offset : ""}`, params);
|
||||
}
|
||||
return rows.then(function (rows) {
|
||||
return create_result(rows, resolve, enrich);
|
||||
});
|
||||
};
|
||||
|
||||
PostgresDB.prototype.tag = function (tag, limit = 0, offset = 0, enrich = !1) {
|
||||
const table = this.id + ".tag" + this.field,
|
||||
promise = this.db.any(`
|
||||
SELECT ${table}.id
|
||||
${enrich ? ", doc" : ""}
|
||||
FROM ${table}
|
||||
${enrich ? `
|
||||
LEFT JOIN ${this.id}.reg ON ${this.id}.reg.id = ${table}.id
|
||||
` : ""}
|
||||
WHERE tag = $1
|
||||
${limit ? "LIMIT " + limit : ""}
|
||||
${offset ? "OFFSET " + offset : ""}`, [tag]);
|
||||
|
||||
enrich || promise.then(function (rows) {
|
||||
return create_result(rows, !0, !1);
|
||||
});
|
||||
return promise;
|
||||
};
|
||||
|
||||
PostgresDB.prototype.enrich = async function (ids) {
|
||||
let result = [];
|
||||
if ("object" != typeof ids) {
|
||||
ids = [ids];
|
||||
}
|
||||
for (let count = 0; count < ids.length;) {
|
||||
const chunk = ids.length - count > MAXIMUM_QUERY_VARS ? ids.slice(count, count + MAXIMUM_QUERY_VARS) : count ? ids.slice(count) : ids;
|
||||
count += chunk.length;
|
||||
let stmt = "";
|
||||
for (let i = 1; i <= chunk.length; i++) {
|
||||
stmt += (stmt ? "," : "") + "$" + i;
|
||||
}
|
||||
const res = await this.db.any(`
|
||||
SELECT id, doc
|
||||
FROM ${this.id}.reg
|
||||
WHERE id IN (${stmt})`, ids);
|
||||
if (res && res.length) {
|
||||
for (let i = 0, doc; i < res.length; i++) {
|
||||
if (doc = res[i].doc) {
|
||||
res[i].doc = JSON.parse(doc);
|
||||
}
|
||||
}
|
||||
result.push(res);
|
||||
}
|
||||
}
|
||||
return 1 === result.length ? result[0] : 1 < result.length ? concat(result) : result;
|
||||
};
|
||||
|
||||
PostgresDB.prototype.has = function (id) {
|
||||
return this.db.oneOrNone("SELECT EXISTS(SELECT 1 FROM " + this.id + ".reg WHERE id = $1)", [id]);
|
||||
};
|
||||
|
||||
PostgresDB.prototype.search = function (flexsearch, query, limit = 100, offset = 0, suggest = !1, resolve = !0, enrich = !1, tags) {
|
||||
|
||||
let rows;
|
||||
|
||||
if (1 < query.length && flexsearch.depth) {
|
||||
let where = "",
|
||||
params = [],
|
||||
keyword = query[0],
|
||||
term,
|
||||
count = 1;
|
||||
|
||||
// variant new
|
||||
|
||||
for (let i = 1; i < query.length; i++) {
|
||||
term = query[i];
|
||||
const swap = flexsearch.bidirectional && term > keyword;
|
||||
where += (where ? " OR " : "") + `(ctx = $${count++} AND key = $${count++})`;
|
||||
params.push(swap ? term : keyword, swap ? keyword : term);
|
||||
keyword = term;
|
||||
}
|
||||
|
||||
if (tags) {
|
||||
where = "(" + where + ")";
|
||||
for (let i = 0; i < tags.length; i += 2) {
|
||||
where += ` AND id IN (SELECT id FROM ${this.id}.tag_${sanitize(tags[i])} WHERE tag = $${count++})`;
|
||||
params.push(tags[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
rows = this.db.any(`
|
||||
SELECT r.id
|
||||
${resolve ? "" : ", res"}
|
||||
${enrich ? ", doc" : ""}
|
||||
FROM (
|
||||
SELECT id, count(*) as count,
|
||||
${suggest ? "SUM" : "MIN"}(res) as res
|
||||
FROM ${this.id}.ctx${this.field}
|
||||
WHERE ${where}
|
||||
GROUP BY id
|
||||
) as r
|
||||
${enrich ? `
|
||||
LEFT JOIN ${this.id}.reg ON ${this.id}.reg.id = r.id
|
||||
` : ""}
|
||||
${suggest ? "" : "WHERE count = " + (query.length - 1)}
|
||||
ORDER BY ${suggest ? "count DESC, res" : "res"}
|
||||
${limit ? "LIMIT " + limit : ""}
|
||||
${offset ? "OFFSET " + offset : ""}
|
||||
`, params);
|
||||
|
||||
// variant 1
|
||||
|
||||
// for(let i = 1, count = 1; i < query.length; i++){
|
||||
// where += (where ? " UNION " : "") + `
|
||||
// SELECT id, res
|
||||
// FROM ${this.id}.ctx${this.field}
|
||||
// WHERE ctx = $${count++} AND key = $${count++}
|
||||
// `;
|
||||
// term = query[i];
|
||||
// const swap = flexsearch.bidirectional && (term > keyword);
|
||||
// params.push(
|
||||
// swap ? term : keyword,
|
||||
// swap ? keyword : term
|
||||
// );
|
||||
// keyword = term;
|
||||
// }
|
||||
//
|
||||
// rows = await db.any(`
|
||||
// SELECT id, res
|
||||
// FROM (
|
||||
// SELECT id, ${suggest ? "SUM" : "MIN"}(res) as res, count(*) as count
|
||||
// FROM (${where}) as t
|
||||
// GROUP BY id
|
||||
// ORDER BY ${suggest ? "count DESC, res" : "res"}
|
||||
// LIMIT ${limit}
|
||||
// OFFSET ${offset}
|
||||
// ) as r
|
||||
// ${suggest ? "" : "WHERE count = " + (query.length - 1)}
|
||||
// `, params);
|
||||
} else {
|
||||
let where = "",
|
||||
count = 1,
|
||||
query_length = query.length;
|
||||
|
||||
for (let i = 0; i < query_length; i++) {
|
||||
where += (where ? "," : "") + "$" + count++;
|
||||
}
|
||||
where = "key " + (1 < query_length ? "IN (" + where + ")" : "= " + where);
|
||||
|
||||
if (tags) {
|
||||
where = "(" + where + ")";
|
||||
for (let i = 0; i < tags.length; i += 2) {
|
||||
where += ` AND id IN (SELECT id FROM ${this.id}.tag_${sanitize(tags[i])} WHERE tag = $${count++})`;
|
||||
query.push(tags[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
rows = this.db.any(`
|
||||
SELECT r.id
|
||||
${resolve ? "" : ", res"}
|
||||
${enrich ? ", doc" : ""}
|
||||
FROM (
|
||||
SELECT id, count(*) as count,
|
||||
${suggest ? "SUM" : "MIN"}(res) as res
|
||||
FROM ${this.id}.map${this.field}
|
||||
WHERE ${where}
|
||||
GROUP BY id
|
||||
) as r
|
||||
${enrich ? `
|
||||
LEFT JOIN ${this.id}.reg ON ${this.id}.reg.id = r.id
|
||||
` : ""}
|
||||
${suggest ? "" : "WHERE count = " + query_length}
|
||||
ORDER BY ${suggest ? "count DESC, res" : "res"}
|
||||
${limit ? "LIMIT " + limit : ""}
|
||||
${offset ? "OFFSET " + offset : ""}
|
||||
`, query);
|
||||
|
||||
// variant 1
|
||||
// for(let i = 1; i <= query.length; i++){
|
||||
// where += (where ? " UNION " : "") + `
|
||||
// SELECT id, res
|
||||
// FROM ${ this.id }.map${ this.field }
|
||||
// WHERE key = $${i}
|
||||
// `;
|
||||
// }
|
||||
// rows = await db.any(`
|
||||
// SELECT id, res
|
||||
// FROM (
|
||||
// SELECT id, ${suggest ? "SUM" : "MIN"}(res) as res, count(*) as count
|
||||
// FROM (${where}) as t
|
||||
// GROUP BY id
|
||||
// ORDER BY ${suggest ? "count DESC, res" : "res"}
|
||||
// LIMIT ${limit}
|
||||
// OFFSET ${offset}
|
||||
// ) as r
|
||||
// ${ suggest ? "" : "WHERE count = " + query.length }
|
||||
// `, query);
|
||||
|
||||
// variant 2
|
||||
// for(let i = 1; i <= query.length; i++){
|
||||
// where += (where ? " AND EXISTS " : "") + `(SELECT FROM ${this.id}.map${this.field} as d WHERE d.id = t.id AND d.key = $` + i + ")";
|
||||
// }
|
||||
// rows = await db.any(`
|
||||
// SELECT t.id, min(t.res)
|
||||
// FROM ${this.id}.map${this.field} AS t
|
||||
// WHERE EXISTS ${where}
|
||||
// GROUP BY t.id
|
||||
// LIMIT ${limit || 100}
|
||||
// OFFSET ${offset || 0}
|
||||
// `, query);
|
||||
|
||||
// variant 3
|
||||
// for(let i = 1; i <= query.length; i++){
|
||||
// where += (where ? " INTERSECT " : "") + `SELECT id FROM ${this.id}.map${this.field} WHERE key = $` + i;
|
||||
// }
|
||||
// rows = await db.any(`
|
||||
// WITH filtering (id) AS(${where})
|
||||
// SELECT t.id, min(t.res)
|
||||
// FROM ${this.id}.map${this.field} AS t
|
||||
// JOIN filtering USING (id)
|
||||
// GROUP BY t.id
|
||||
// LIMIT ${limit || 100}
|
||||
// OFFSET ${offset || 0}
|
||||
// `, query);
|
||||
|
||||
// variant 4
|
||||
// for(let i = 1; i <= query.length; i++){
|
||||
// where += (where ? " INTERSECT " : "") + `SELECT id FROM ${this.id}.map${this.field} WHERE key = $` + i;
|
||||
// }
|
||||
// rows = await db.any(`
|
||||
// SELECT id, min(res)
|
||||
// FROM ${this.id}.map${this.field}
|
||||
// WHERE id IN (${where})
|
||||
// GROUP BY id
|
||||
// LIMIT ${limit || 100}
|
||||
// OFFSET ${offset || 0}
|
||||
// `, query);
|
||||
}
|
||||
|
||||
return rows.then(function (rows) {
|
||||
return create_result(rows, resolve, enrich);
|
||||
});
|
||||
};
|
||||
|
||||
PostgresDB.prototype.info = function () {
|
||||
// todo
|
||||
};
|
||||
|
||||
// PostgresDB.prototype.transaction = async function(task){
|
||||
// const self = this;
|
||||
// if(TRX){
|
||||
// return TRX.then(function(){
|
||||
// return self.transaction(task);
|
||||
// //task.call(self, TRX);
|
||||
// });
|
||||
// }
|
||||
// TRX = await this.db.tx(async function(trx){
|
||||
// await task.call(self, trx);
|
||||
// });
|
||||
// TRX = null;
|
||||
// };
|
||||
|
||||
PostgresDB.prototype.transaction = function (task) {
|
||||
if (TRX) {
|
||||
return task.call(this, TRX);
|
||||
}
|
||||
const self = this;
|
||||
return (TRX || this.db).tx(function (trx) {
|
||||
return task.call(self, TRX = trx);
|
||||
}).finally(function () {
|
||||
TRX = null;
|
||||
});
|
||||
};
|
||||
|
||||
PostgresDB.prototype.commit = async function (flexsearch, _replace, _append) {
|
||||
|
||||
// process cleanup tasks
|
||||
if (_replace) {
|
||||
await this.clear();
|
||||
// there are just removals in the task queue
|
||||
flexsearch.commit_task = [];
|
||||
} else {
|
||||
let tasks = flexsearch.commit_task;
|
||||
flexsearch.commit_task = [];
|
||||
for (let i = 0, task; i < tasks.length; i++) {
|
||||
task = tasks[i];
|
||||
// there are just removals in the task queue
|
||||
if (task.clear) {
|
||||
await this.clear();
|
||||
_replace = !0;
|
||||
break;
|
||||
} else {
|
||||
tasks[i] = task.del;
|
||||
}
|
||||
}
|
||||
if (!_replace) {
|
||||
if (!_append) {
|
||||
tasks = tasks.concat(toArray(flexsearch.reg));
|
||||
}
|
||||
tasks.length && (await this.remove(tasks));
|
||||
}
|
||||
|
||||
//console.log("tasks:", tasks)
|
||||
}
|
||||
|
||||
if (!flexsearch.reg.size) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.transaction(function (trx) {
|
||||
|
||||
const batch = [];
|
||||
|
||||
// Datastore + Registry
|
||||
|
||||
if (flexsearch.store) {
|
||||
let data = [],
|
||||
stmt = new pgp.helpers.ColumnSet(["id", "doc"], {
|
||||
table: this.id + ".reg"
|
||||
});
|
||||
|
||||
for (const item of flexsearch.store.entries()) {
|
||||
const id = item[0],
|
||||
doc = item[1];
|
||||
|
||||
// const migration = checkMigration.call(this, id);
|
||||
// migration && await migration;
|
||||
data.push({ id, doc: doc && JSON.stringify(doc) });
|
||||
if (data.length === MAXIMUM_QUERY_VARS) {
|
||||
let insert = pgp.helpers.insert(data, stmt);
|
||||
batch.push(trx.none(insert.replace(/^(insert into )"([^"]+)"/, '$1 $2')));
|
||||
data = [];
|
||||
}
|
||||
}
|
||||
if (data.length) {
|
||||
let insert = pgp.helpers.insert(data, stmt);
|
||||
batch.push(trx.none(insert.replace(/^(insert into )"([^"]+)"/, '$1 $2')));
|
||||
}
|
||||
// while(data.length){
|
||||
// let next;
|
||||
// if(data.length > MAXIMUM_QUERY_VARS){
|
||||
// next = data.slice(MAXIMUM_QUERY_VARS);
|
||||
// data = data.slice(0, MAXIMUM_QUERY_VARS);
|
||||
// }
|
||||
// let insert = pgp.helpers.insert(data, stmt);
|
||||
// trx.none(insert.replace(/^(insert into )"([^"]+)"/, '$1 $2'));
|
||||
// if(next) data = next;
|
||||
// else break;
|
||||
// }
|
||||
}
|
||||
|
||||
// Registry Only
|
||||
|
||||
else if (!flexsearch.bypass) {
|
||||
let data = [],
|
||||
stmt = new pgp.helpers.ColumnSet(["id"], {
|
||||
table: this.id + ".reg"
|
||||
});
|
||||
|
||||
for (const id of flexsearch.reg.keys()) {
|
||||
// const migration = checkMigration.call(this, id);
|
||||
// migration && await migration;
|
||||
data.push({ id });
|
||||
if (data.length === MAXIMUM_QUERY_VARS) {
|
||||
let insert = pgp.helpers.insert(data, stmt);
|
||||
batch.push(trx.none(insert.replace(/^(insert into )"([^"]+)"/, '$1 $2')));
|
||||
data = [];
|
||||
}
|
||||
}
|
||||
if (data.length) {
|
||||
let insert = pgp.helpers.insert(data, stmt);
|
||||
batch.push(trx.none(insert.replace(/^(insert into )"([^"]+)"/, '$1 $2')));
|
||||
}
|
||||
}
|
||||
|
||||
// Default Index
|
||||
|
||||
if (flexsearch.map.size) {
|
||||
let data = [],
|
||||
stmt = new pgp.helpers.ColumnSet(["key", "res", "id"], {
|
||||
table: this.id + ".map" + this.field
|
||||
});
|
||||
|
||||
for (const item of flexsearch.map) {
|
||||
const key = item[0],
|
||||
arr = item[1];
|
||||
|
||||
|
||||
for (let i = 0, ids; i < arr.length; i++) {
|
||||
if ((ids = arr[i]) && ids.length) {
|
||||
//this.type || (this.type = typeof ids[0]);
|
||||
// let stmt = "($1,$2,$3)";
|
||||
// let params = [key, i, ids[0]];
|
||||
for (let j = 0; j < ids.length; j++) {
|
||||
// stmt += ",($1,$2,$3)";
|
||||
// params.push(key, i, ids[j]);
|
||||
//trx.none(`INSERT INTO ${config.schema}.map${self.field} (key, res, id) VALUES ($1,$2,$3)`, [key, i, ids[j]]);
|
||||
data.push({
|
||||
key: key,
|
||||
res: i,
|
||||
id: ids[j]
|
||||
});
|
||||
if (data.length === MAXIMUM_QUERY_VARS) {
|
||||
let insert = pgp.helpers.insert(data, stmt);
|
||||
batch.push(trx.none(insert.replace(/^(insert into )"([^"]+)"/, '$1 $2')));
|
||||
data = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.length) {
|
||||
let insert = pgp.helpers.insert(data, stmt);
|
||||
batch.push(trx.none(insert.replace(/^(insert into )"([^"]+)"/, '$1 $2')));
|
||||
}
|
||||
}
|
||||
|
||||
// Context Index
|
||||
|
||||
if (flexsearch.ctx.size) {
|
||||
let data = [],
|
||||
stmt = new pgp.helpers.ColumnSet(["ctx", "key", "res", "id"], {
|
||||
table: this.id + ".ctx" + this.field
|
||||
});
|
||||
|
||||
for (const ctx of flexsearch.ctx) {
|
||||
const ctx_key = ctx[0],
|
||||
ctx_value = ctx[1];
|
||||
|
||||
|
||||
for (const item of ctx_value) {
|
||||
const key = item[0],
|
||||
arr = item[1];
|
||||
|
||||
|
||||
for (let i = 0, ids; i < arr.length; i++) {
|
||||
if ((ids = arr[i]) && ids.length) {
|
||||
// let stmt = "(?,?,?)";
|
||||
// let params = [ctx_key + ":" + key, i, ids[0]];
|
||||
for (let j = 0; j < ids.length; j++) {
|
||||
// stmt += ",(?,?,?)";
|
||||
// params.push(ctx_key + ":" + key, i, ids[j]);
|
||||
//trx.none("INSERT INTO " + config.schema + ".ctx" + self.field + " (ctx, key, res, id) VALUES ($1,$2,$3,$4)", [ctx_key, key, i, ids[j]]);
|
||||
data.push({
|
||||
ctx: ctx_key,
|
||||
key: key,
|
||||
res: i,
|
||||
id: ids[j]
|
||||
});
|
||||
if (data.length === MAXIMUM_QUERY_VARS) {
|
||||
let insert = pgp.helpers.insert(data, stmt);
|
||||
batch.push(trx.none(insert.replace(/^(insert into )"([^"]+)"/, '$1 $2')));
|
||||
data = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.length) {
|
||||
let insert = pgp.helpers.insert(data, stmt);
|
||||
batch.push(trx.none(insert.replace(/^(insert into )"([^"]+)"/, '$1 $2')));
|
||||
}
|
||||
}
|
||||
|
||||
// Tag Index
|
||||
|
||||
if (flexsearch.tag) {
|
||||
let data = [],
|
||||
stmt = new pgp.helpers.ColumnSet(["tag", "id"], {
|
||||
table: this.id + ".tag" + this.field
|
||||
});
|
||||
|
||||
for (const item of flexsearch.tag) {
|
||||
const tag = item[0],
|
||||
ids = item[1];
|
||||
|
||||
if (!ids.length) continue;
|
||||
for (let j = 0; j < ids.length; j++) {
|
||||
data.push({ tag, id: ids[j] });
|
||||
if (data.length === MAXIMUM_QUERY_VARS) {
|
||||
let insert = pgp.helpers.insert(data, stmt);
|
||||
batch.push(trx.none(insert.replace(/^(insert into )"([^"]+)"/, '$1 $2')));
|
||||
data = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (data.length) {
|
||||
let insert = pgp.helpers.insert(data, stmt);
|
||||
batch.push(trx.none(insert.replace(/^(insert into )"([^"]+)"/, '$1 $2')));
|
||||
}
|
||||
}
|
||||
|
||||
// Field Configuration
|
||||
|
||||
// TODO
|
||||
// trx.none("INSERT INTO " + this.id + ".cfg" + this.field + " (cfg) VALUES ($1)", [
|
||||
// JSON.stringify({
|
||||
// "encode": typeof flexsearch.encode === "string" ? flexsearch.encode : "",
|
||||
// "charset": typeof flexsearch.charset === "string" ? flexsearch.charset : "",
|
||||
// "tokenize": flexsearch.tokenize,
|
||||
// "resolution": flexsearch.resolution,
|
||||
// "minlength": flexsearch.minlength,
|
||||
// "optimize": flexsearch.optimize,
|
||||
// "fastupdate": flexsearch.fastupdate,
|
||||
// "encoder": flexsearch.encoder,
|
||||
// "context": {
|
||||
// "depth": flexsearch.depth,
|
||||
// "bidirectional": flexsearch.bidirectional,
|
||||
// "resolution": flexsearch.resolution_ctx
|
||||
// }
|
||||
// })
|
||||
// ]);
|
||||
|
||||
//return Promise.all(batch);
|
||||
|
||||
if (batch.length) {
|
||||
return trx.batch(batch);
|
||||
}
|
||||
});
|
||||
|
||||
flexsearch.map.clear();
|
||||
flexsearch.ctx.clear();
|
||||
flexsearch.tag && flexsearch.tag.clear();
|
||||
flexsearch.store && flexsearch.store.clear();
|
||||
flexsearch.document || flexsearch.reg.clear();
|
||||
};
|
||||
|
||||
PostgresDB.prototype.remove = function (ids) {
|
||||
|
||||
if (!ids && 0 !== ids) {
|
||||
return;
|
||||
}
|
||||
if ("object" != typeof ids) {
|
||||
ids = [ids];
|
||||
}
|
||||
if (!ids.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// ids = [ids];
|
||||
// return this.db.none(
|
||||
// "DELETE FROM " + this.id + ".map" + this.field + " WHERE id = ANY ($1);" +
|
||||
// "DELETE FROM " + this.id + ".ctx" + this.field + " WHERE id = ANY ($1);" +
|
||||
// "DELETE FROM " + this.id + ".tag" + this.field + " WHERE id = ANY ($1);" +
|
||||
// "DELETE FROM " + this.id + ".reg WHERE id = ANY ($1);", [ids]
|
||||
// );
|
||||
|
||||
// ids = [ids];
|
||||
// return Promise.all([
|
||||
// this.db.none({ text: "DELETE FROM " + this.id + ".map" + this.field + " WHERE id = ANY ($1)", rowMode: "array" }, ids),
|
||||
// this.db.none({ text: "DELETE FROM " + this.id + ".ctx" + this.field + " WHERE id = ANY ($1)", rowMode: "array" }, ids),
|
||||
// this.db.none({ text: "DELETE FROM " + this.id + ".tag" + this.field + " WHERE id = ANY ($1)", rowMode: "array" }, ids),
|
||||
// this.db.none({ text: "DELETE FROM " + this.id + ".reg WHERE id = ANY ($1)", rowMode: "array" }, ids)
|
||||
// ]);
|
||||
|
||||
return this.transaction(function (trx) {
|
||||
|
||||
//console.log("remove:", ids);
|
||||
|
||||
// ids = [ids];
|
||||
// trx.none({ text: "DELETE FROM " + this.id + ".map" + this.field + " WHERE id = ANY ($1)", rowMode: "array" }, ids);
|
||||
// trx.none({ text: "DELETE FROM " + this.id + ".ctx" + this.field + " WHERE id = ANY ($1)", rowMode: "array" }, ids);
|
||||
// trx.none({ text: "DELETE FROM " + this.id + ".tag" + this.field + " WHERE id = ANY ($1)", rowMode: "array" }, ids);
|
||||
// trx.none({ text: "DELETE FROM " + this.id + ".reg WHERE id = ANY ($1)", rowMode: "array" }, ids);
|
||||
|
||||
// ids = [ids];
|
||||
// trx.none("DELETE FROM " + this.id + ".map" + this.field + " WHERE id = ANY ($1)", ids);
|
||||
// trx.none("DELETE FROM " + this.id + ".ctx" + this.field + " WHERE id = ANY ($1)", ids);
|
||||
// trx.none("DELETE FROM " + this.id + ".tag" + this.field + " WHERE id = ANY ($1)", ids);
|
||||
// trx.none("DELETE FROM " + this.id + ".reg WHERE id = ANY ($1)", ids);
|
||||
// return;
|
||||
|
||||
// return trx.none(
|
||||
// "DELETE FROM " + this.id + ".map" + this.field + " WHERE id = ANY ($1);" +
|
||||
// "DELETE FROM " + this.id + ".ctx" + this.field + " WHERE id = ANY ($1);" +
|
||||
// "DELETE FROM " + this.id + ".tag" + this.field + " WHERE id = ANY ($1);" +
|
||||
// "DELETE FROM " + this.id + ".reg WHERE id = ANY ($1);", [ids]
|
||||
// );
|
||||
|
||||
// while(ids.length){
|
||||
// let next;
|
||||
// let stmt = "";
|
||||
// let chunk = 0;
|
||||
// let migration;
|
||||
// for(let i = 0; i < ids.length; i++){
|
||||
// stmt += (stmt ? "," : "") + "$" + (i + 1); // + "::text";
|
||||
// // maximum count of variables supported
|
||||
// if(++chunk === MAXIMUM_QUERY_VARS){
|
||||
// next = ids.slice(MAXIMUM_QUERY_VARS);
|
||||
// ids = ids.slice(0, MAXIMUM_QUERY_VARS);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// trx.batch([
|
||||
// trx.none("DELETE FROM " + this.id + ".map" + this.field + " WHERE id IN (" + stmt + ")", ids),
|
||||
// trx.none("DELETE FROM " + this.id + ".ctx" + this.field + " WHERE id IN (" + stmt + ")", ids),
|
||||
// trx.none("DELETE FROM " + this.id + ".tag" + this.field + " WHERE id IN (" + stmt + ")", ids),
|
||||
// trx.none("DELETE FROM " + this.id + ".reg WHERE id IN (" + stmt + ")", ids)
|
||||
// ]);
|
||||
//
|
||||
// // trx.none(
|
||||
// // "DELETE FROM " + this.id + ".map" + this.field + " WHERE id IN (" + stmt + ");" +
|
||||
// // "DELETE FROM " + this.id + ".ctx" + this.field + " WHERE id IN (" + stmt + ");" +
|
||||
// // "DELETE FROM " + this.id + ".tag" + this.field + " WHERE id IN (" + stmt + ");" +
|
||||
// // "DELETE FROM " + this.id + ".reg WHERE id IN (" + stmt + ");", ids
|
||||
// // );
|
||||
//
|
||||
// if(next) ids = next;
|
||||
// else break;
|
||||
// }
|
||||
|
||||
ids = [ids];
|
||||
return trx.batch([trx.none({ text: "DELETE FROM " + this.id + ".map" + this.field + " WHERE id = ANY ($1)", rowMode: "array" }, ids), trx.none({ text: "DELETE FROM " + this.id + ".ctx" + this.field + " WHERE id = ANY ($1)", rowMode: "array" }, ids), trx.none({ text: "DELETE FROM " + this.id + ".tag" + this.field + " WHERE id = ANY ($1)", rowMode: "array" }, ids), trx.none({ text: "DELETE FROM " + this.id + ".reg WHERE id = ANY ($1)", rowMode: "array" }, ids)]);
|
||||
|
||||
// ids = [ids];
|
||||
// return trx.batch([
|
||||
// trx.none("DELETE FROM " + this.id + ".map" + this.field + " WHERE id = ANY ($1)", ids),
|
||||
// trx.none("DELETE FROM " + this.id + ".ctx" + this.field + " WHERE id = ANY ($1)", ids),
|
||||
// trx.none("DELETE FROM " + this.id + ".tag" + this.field + " WHERE id = ANY ($1)", ids),
|
||||
// trx.none("DELETE FROM " + this.id + ".reg WHERE id = ANY ($1)", ids)
|
||||
// ]);
|
||||
|
||||
// return trx.batch([
|
||||
// trx.none("DELETE FROM " + this.id + ".map" + this.field + " WHERE id IN ($1:csv)", [ids]),
|
||||
// trx.none("DELETE FROM " + this.id + ".ctx" + this.field + " WHERE id IN ($1:csv)", [ids]),
|
||||
// trx.none("DELETE FROM " + this.id + ".tag" + this.field + " WHERE id IN ($1:csv)", [ids]),
|
||||
// trx.none("DELETE FROM " + this.id + ".reg WHERE id IN ($1:csv)", [ids])
|
||||
// ]);
|
||||
|
||||
// const type = self.type === "text" ? "text" : "int";
|
||||
// return trx.batch([
|
||||
// trx.none("DELETE FROM " + this.id + ".map" + self.field + " WHERE id = ANY($1::" + type + "[])", [ids]),
|
||||
// trx.none("DELETE FROM " + this.id + ".ctx" + self.field + " WHERE id = ANY($1::" + type + "[])", [ids]),
|
||||
// trx.none("DELETE FROM " + this.id + ".reg WHERE id = ANY($1::" + type + "[])", [ids])
|
||||
// ]);
|
||||
|
||||
// return trx.batch([
|
||||
// trx.none("DELETE FROM " + this.id + ".map" + self.field + " WHERE id = ANY($1)", [ids]),
|
||||
// trx.none("DELETE FROM " + this.id + ".ctx" + self.field + " WHERE id = ANY($1)", [ids]),
|
||||
// trx.none("DELETE FROM " + this.id + ".reg WHERE id = ANY($1)", [ids])
|
||||
// ]);
|
||||
});
|
||||
};
|
||||
|
||||
// if(this.type === "int" && typeof ids[0] === "string"){
|
||||
// ids = ids.map(item => parseInt(item, 10));
|
||||
// }
|
||||
// if(this.type === "bigint" && typeof ids[0] === "string"){
|
||||
// ids = ids.map(item => BigInt(item));
|
||||
// }
|
||||
// if(this.type === "string" && typeof ids[0] === "number"){
|
||||
// ids = ids.map(item => item + "");
|
||||
// }
|
||||
// this.type !== "string" && checkMigration.call(this, ids[0]);
|
||||
|
||||
// function checkMigration(id){
|
||||
// if(this.type !== "string"){
|
||||
// if(typeof id === "object"){
|
||||
// id = id[0];
|
||||
// }
|
||||
// if(typeof id === "string"){
|
||||
// this.type = "string";
|
||||
// return upgradeTextId.call(this);
|
||||
// }
|
||||
// if(this.type !== "bigint"){
|
||||
// if(id > 2 ** 31 - 1){
|
||||
// this.type = "bigint";
|
||||
// return upgradeBigIntId.call(this);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// function upgradeTextId(){
|
||||
// return this.db.none(`
|
||||
// ALTER TABLE ${this.id}.map${this.field}
|
||||
// ALTER COLUMN id type varchar(128)
|
||||
// USING id::text;
|
||||
// ALTER TABLE ${this.id}.ctx${this.field}
|
||||
// ALTER COLUMN id type varchar(128)
|
||||
// USING id::text;
|
||||
// ALTER TABLE ${this.id}.tag${this.field}
|
||||
// ALTER COLUMN id type varchar(128)
|
||||
// USING id::text;
|
||||
// ALTER TABLE ${this.id}.reg
|
||||
// ALTER COLUMN id type varchar(128)
|
||||
// USING id::text;
|
||||
// `);
|
||||
// }
|
||||
//
|
||||
// function upgradeBigIntId(){
|
||||
// return this.db.none(`
|
||||
// ALTER TABLE ${this.id}.map${this.field}
|
||||
// ALTER COLUMN id type bigint
|
||||
// USING id::bigint;
|
||||
// ALTER TABLE ${this.id}.ctx${this.field}
|
||||
// ALTER COLUMN id type bigint
|
||||
// USING id::bigint;
|
||||
// ALTER TABLE ${this.id}.tag${this.field}
|
||||
// ALTER COLUMN id type bigint
|
||||
// USING id::bigint;
|
||||
// ALTER TABLE ${this.id}.reg
|
||||
// ALTER COLUMN id type bigint
|
||||
// USING id::bigint;
|
||||
// `);
|
||||
// }
|
Reference in New Issue
Block a user