@primate/postgresql 0.1.7 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/private/ColumnTypes.d.ts +23 -0
- package/lib/private/ColumnTypes.js +2 -0
- package/lib/private/Database.d.ts +46 -0
- package/lib/private/Database.js +166 -0
- package/lib/private/typemap.d.ts +5 -0
- package/lib/private/typemap.js +105 -0
- package/lib/public/index.d.ts +4 -0
- package/lib/public/index.js +3 -0
- package/package.json +24 -14
- package/src/default.js +0 -12
- package/src/private/Facade.js +0 -97
- package/src/private/connect.js +0 -10
- package/src/private/defaults.js +0 -4
- package/src/private/serve.js +0 -63
- package/src/private/typemap.js +0 -21
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type TypedArray from "@rcompat/type/TypedArray";
|
|
2
|
+
type Param = Array<unknown> | bigint | boolean | Date | null | number | object | string | TypedArray;
|
|
3
|
+
type Validate<T extends {
|
|
4
|
+
[K in keyof T]: Param;
|
|
5
|
+
}> = T;
|
|
6
|
+
type ColumnTypes = Validate<{
|
|
7
|
+
BIGINT: string;
|
|
8
|
+
BOOLEAN: boolean;
|
|
9
|
+
BYTEA: TypedArray;
|
|
10
|
+
FLOAT8: number;
|
|
11
|
+
INTEGER: number;
|
|
12
|
+
"NUMERIC(20, 0)": string;
|
|
13
|
+
"NUMERIC(39, 0)": string;
|
|
14
|
+
REAL: number;
|
|
15
|
+
"SERIAL PRIMARY KEY": number;
|
|
16
|
+
SMALLINT: number;
|
|
17
|
+
TEXT: string;
|
|
18
|
+
TIME: string;
|
|
19
|
+
TIMESTAMP: Date;
|
|
20
|
+
UUID: string;
|
|
21
|
+
}>;
|
|
22
|
+
export type { ColumnTypes as default };
|
|
23
|
+
//# sourceMappingURL=ColumnTypes.d.ts.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import Database from "@primate/core/Database";
|
|
2
|
+
import type As from "@primate/core/database/As";
|
|
3
|
+
import type DataDict from "@primate/core/database/DataDict";
|
|
4
|
+
import type TypeMap from "@primate/core/database/TypeMap";
|
|
5
|
+
import type Dict from "@rcompat/type/Dict";
|
|
6
|
+
import type StoreSchema from "pema/StoreSchema";
|
|
7
|
+
declare const schema: import("pema").ObjectType<{
|
|
8
|
+
database: import("pema/string").StringType;
|
|
9
|
+
host: import("pema").DefaultType<import("pema/string").StringType, "localhost">;
|
|
10
|
+
password: import("pema").OptionalType<import("pema/string").StringType>;
|
|
11
|
+
port: import("pema").DefaultType<import("pema/uint").UintType<"u32">, 5432>;
|
|
12
|
+
username: import("pema").OptionalType<import("pema/string").StringType>;
|
|
13
|
+
}>;
|
|
14
|
+
export default class PostgreSQLDatabase extends Database {
|
|
15
|
+
#private;
|
|
16
|
+
static config: typeof schema.input;
|
|
17
|
+
constructor(config?: typeof schema.input);
|
|
18
|
+
get typemap(): TypeMap<Dict>;
|
|
19
|
+
close(): Promise<void>;
|
|
20
|
+
get schema(): {
|
|
21
|
+
create: (name: string, store: StoreSchema) => Promise<void>;
|
|
22
|
+
delete: (name: string) => Promise<void>;
|
|
23
|
+
};
|
|
24
|
+
create<O extends Dict>(as: As, args: {
|
|
25
|
+
record: DataDict;
|
|
26
|
+
}): Promise<O>;
|
|
27
|
+
read(as: As, args: {
|
|
28
|
+
count: true;
|
|
29
|
+
criteria: DataDict;
|
|
30
|
+
}): Promise<number>;
|
|
31
|
+
read(as: As, args: {
|
|
32
|
+
criteria: DataDict;
|
|
33
|
+
fields?: string[];
|
|
34
|
+
limit?: number;
|
|
35
|
+
sort?: Dict<"asc" | "desc">;
|
|
36
|
+
}): Promise<Dict[]>;
|
|
37
|
+
update(as: As, args: {
|
|
38
|
+
changes: DataDict;
|
|
39
|
+
criteria: DataDict;
|
|
40
|
+
}): Promise<any>;
|
|
41
|
+
delete(as: As, args: {
|
|
42
|
+
criteria: DataDict;
|
|
43
|
+
}): Promise<any>;
|
|
44
|
+
}
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=Database.d.ts.map
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import typemap from "#typemap";
|
|
2
|
+
import Database from "@primate/core/Database";
|
|
3
|
+
import assert from "@rcompat/assert";
|
|
4
|
+
import maybe from "@rcompat/assert/maybe";
|
|
5
|
+
import pema from "pema";
|
|
6
|
+
import string from "pema/string";
|
|
7
|
+
import uint from "pema/uint";
|
|
8
|
+
import postgres from "postgres";
|
|
9
|
+
const schema = pema({
|
|
10
|
+
database: string,
|
|
11
|
+
host: string.default("localhost"),
|
|
12
|
+
password: string.optional(),
|
|
13
|
+
port: uint.port().default(5432),
|
|
14
|
+
username: string.optional(),
|
|
15
|
+
});
|
|
16
|
+
export default class PostgreSQLDatabase extends Database {
|
|
17
|
+
static config;
|
|
18
|
+
#factory;
|
|
19
|
+
#client;
|
|
20
|
+
constructor(config) {
|
|
21
|
+
super();
|
|
22
|
+
const parsed = schema.parse(config);
|
|
23
|
+
this.#factory = () => postgres({
|
|
24
|
+
db: parsed.database,
|
|
25
|
+
host: parsed.host,
|
|
26
|
+
pass: parsed.password,
|
|
27
|
+
port: parsed.port,
|
|
28
|
+
user: parsed.username,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
#sql() {
|
|
32
|
+
if (this.#client === undefined) {
|
|
33
|
+
this.#client = this.#factory();
|
|
34
|
+
}
|
|
35
|
+
return this.#client;
|
|
36
|
+
}
|
|
37
|
+
#join(parts, sep) {
|
|
38
|
+
const sql = this.#sql();
|
|
39
|
+
if (parts.length === 0)
|
|
40
|
+
return sql ``;
|
|
41
|
+
return parts.slice(1).reduce((acc, p) => sql `${acc}${sep}${p}`, parts[0]);
|
|
42
|
+
}
|
|
43
|
+
async #new(name, store) {
|
|
44
|
+
const sql = this.#sql();
|
|
45
|
+
const table = sql(name);
|
|
46
|
+
const body = Object.entries(store).map(([k, v]) => sql `${sql(k)} ${sql.unsafe(this.column(v.datatype))}`);
|
|
47
|
+
await sql `CREATE TABLE IF NOT EXISTS ${table}
|
|
48
|
+
(${this.#join(body, sql `, `)})`;
|
|
49
|
+
}
|
|
50
|
+
async #drop(name) {
|
|
51
|
+
const sql = this.#sql();
|
|
52
|
+
await sql `DROP TABLE IF EXISTS ${sql(name)};`;
|
|
53
|
+
}
|
|
54
|
+
get typemap() {
|
|
55
|
+
return typemap;
|
|
56
|
+
}
|
|
57
|
+
async close() {
|
|
58
|
+
await this.#sql().end();
|
|
59
|
+
}
|
|
60
|
+
get schema() {
|
|
61
|
+
return {
|
|
62
|
+
create: this.#new.bind(this),
|
|
63
|
+
delete: this.#drop.bind(this),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
async create(as, args) {
|
|
67
|
+
const sql = this.#sql();
|
|
68
|
+
const columns = Object.keys(args.record);
|
|
69
|
+
const binds = await this.bind(as.types, args.record);
|
|
70
|
+
const [result] = await sql `INSERT INTO
|
|
71
|
+
${sql(as.name)}
|
|
72
|
+
${columns.length > 0
|
|
73
|
+
? sql `(${sql(columns)}) VALUES ${sql(binds)}`
|
|
74
|
+
: sql.unsafe("DEFAULT VALUES")}
|
|
75
|
+
RETURNING id;
|
|
76
|
+
`;
|
|
77
|
+
return this.unbind(as.types, { ...args.record, id: result.id });
|
|
78
|
+
}
|
|
79
|
+
#sort(types, sort) {
|
|
80
|
+
maybe(sort).object();
|
|
81
|
+
// validate
|
|
82
|
+
this.toSort(types, sort);
|
|
83
|
+
const sql = this.#sql();
|
|
84
|
+
if (!sort)
|
|
85
|
+
return sql ``;
|
|
86
|
+
const entries = Object.entries(sort);
|
|
87
|
+
if (entries.length === 0)
|
|
88
|
+
return sql ``;
|
|
89
|
+
const items = entries.map(([field, direction]) => sql `${sql(field)} ${sql.unsafe(direction.toUpperCase())}`);
|
|
90
|
+
return sql ` ORDER BY ${this.#join(items, sql `, `)}`;
|
|
91
|
+
}
|
|
92
|
+
#select(types, fields) {
|
|
93
|
+
// validate
|
|
94
|
+
this.toSelect(types, fields);
|
|
95
|
+
const sql = this.#sql();
|
|
96
|
+
if (fields === undefined)
|
|
97
|
+
return sql.unsafe("*");
|
|
98
|
+
return sql(fields);
|
|
99
|
+
}
|
|
100
|
+
#limit(limit) {
|
|
101
|
+
maybe(limit).usize();
|
|
102
|
+
const sql = this.#sql();
|
|
103
|
+
return limit === undefined ? sql `` : sql ` LIMIT ${limit}`;
|
|
104
|
+
}
|
|
105
|
+
#where(types, criteria, nonnull) {
|
|
106
|
+
this.toWhere(types, criteria); // validate
|
|
107
|
+
const sql = this.#sql();
|
|
108
|
+
const entries = Object.entries(criteria);
|
|
109
|
+
if (entries.length === 0)
|
|
110
|
+
return sql ``;
|
|
111
|
+
const clauses = entries.map(([key, raw]) => {
|
|
112
|
+
if (raw === null)
|
|
113
|
+
return sql `${sql(key)} IS NULL`;
|
|
114
|
+
const value = nonnull[key];
|
|
115
|
+
// Handle operator objects
|
|
116
|
+
if (typeof raw === "object") {
|
|
117
|
+
if ("$like" in raw)
|
|
118
|
+
return sql `${sql(key)} LIKE ${value}`;
|
|
119
|
+
// if ("$gte" in raw) return sql`${sql(key)} >= ${nonnull[key]}`;
|
|
120
|
+
}
|
|
121
|
+
return sql `${sql(key)} = ${value}`;
|
|
122
|
+
});
|
|
123
|
+
return sql `WHERE ${this.#join(clauses, sql ` AND `)}`;
|
|
124
|
+
}
|
|
125
|
+
async read(as, args) {
|
|
126
|
+
const sql = this.#sql();
|
|
127
|
+
const table = sql(as.name);
|
|
128
|
+
const criteria = await this.bindCriteria(as.types, args.criteria);
|
|
129
|
+
const where = this.#where(as.types, args.criteria, criteria);
|
|
130
|
+
if (args.count === true) {
|
|
131
|
+
const [{ n }] = await sql `SELECT COUNT(*) AS n FROM ${table} ${where}`;
|
|
132
|
+
return Number(n);
|
|
133
|
+
}
|
|
134
|
+
const sort = this.#sort(as.types, args.sort);
|
|
135
|
+
const limit = this.#limit(args.limit);
|
|
136
|
+
const select = this.#select(as.types, args.fields);
|
|
137
|
+
const records = await sql `
|
|
138
|
+
SELECT ${select}
|
|
139
|
+
FROM ${table}
|
|
140
|
+
${where}
|
|
141
|
+
${sort}
|
|
142
|
+
${limit}
|
|
143
|
+
`;
|
|
144
|
+
return records.map(record => this.unbind(as.types, record));
|
|
145
|
+
}
|
|
146
|
+
async update(as, args) {
|
|
147
|
+
assert(Object.keys(args.criteria).length > 0, "update: no criteria");
|
|
148
|
+
const sql = this.#sql();
|
|
149
|
+
const table = sql(as.name);
|
|
150
|
+
const criteria = await this.bindCriteria(as.types, args.criteria);
|
|
151
|
+
const set_binds = await this.bind(as.types, args.changes);
|
|
152
|
+
const where = this.#where(as.types, args.criteria, criteria);
|
|
153
|
+
const set = sql({ ...set_binds });
|
|
154
|
+
return (await sql `UPDATE ${table} SET ${set} ${where} RETURNING 1;`).length;
|
|
155
|
+
}
|
|
156
|
+
async delete(as, args) {
|
|
157
|
+
assert(Object.keys(args.criteria).length > 0, "delete: no criteria");
|
|
158
|
+
const sql = this.#sql();
|
|
159
|
+
const criteria = await this.bindCriteria(as.types, args.criteria);
|
|
160
|
+
const where = this.#where(as.types, args.criteria, criteria);
|
|
161
|
+
const table = sql(as.name);
|
|
162
|
+
return (await sql `DELETE FROM ${table} ${where} RETURNING 1;`).length;
|
|
163
|
+
}
|
|
164
|
+
;
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=Database.js.map
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
function identity(column) {
|
|
2
|
+
return {
|
|
3
|
+
bind: value => value,
|
|
4
|
+
column,
|
|
5
|
+
unbind: value => value,
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
function number(column) {
|
|
9
|
+
return {
|
|
10
|
+
bind: value => value,
|
|
11
|
+
column,
|
|
12
|
+
unbind: value => Number(value),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
const typemap = {
|
|
16
|
+
blob: {
|
|
17
|
+
async bind(value) {
|
|
18
|
+
const arrayBuffer = await value.arrayBuffer();
|
|
19
|
+
return new Uint8Array(arrayBuffer);
|
|
20
|
+
},
|
|
21
|
+
column: "BYTEA",
|
|
22
|
+
unbind(value) {
|
|
23
|
+
return new Blob([value], { type: "application/octet-stream" });
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
boolean: identity("BOOLEAN"),
|
|
27
|
+
datetime: identity("TIMESTAMP"),
|
|
28
|
+
f32: identity("REAL"),
|
|
29
|
+
f64: identity("FLOAT8"),
|
|
30
|
+
i128: {
|
|
31
|
+
bind(value) {
|
|
32
|
+
return String(value);
|
|
33
|
+
},
|
|
34
|
+
column: "NUMERIC(39, 0)",
|
|
35
|
+
unbind(value) {
|
|
36
|
+
return BigInt(value);
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
i16: number("SMALLINT"),
|
|
40
|
+
i32: number("INTEGER"),
|
|
41
|
+
i64: {
|
|
42
|
+
bind(value) {
|
|
43
|
+
return String(value);
|
|
44
|
+
},
|
|
45
|
+
column: "BIGINT",
|
|
46
|
+
unbind(value) {
|
|
47
|
+
return BigInt(value);
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
i8: number("SMALLINT"),
|
|
51
|
+
primary: {
|
|
52
|
+
bind(value) {
|
|
53
|
+
if (typeof value === "string" && Number.isInteger(+value)) {
|
|
54
|
+
return Number(value);
|
|
55
|
+
}
|
|
56
|
+
throw new Error(`\`${value}\` is not a valid primary key value`);
|
|
57
|
+
},
|
|
58
|
+
column: "SERIAL PRIMARY KEY",
|
|
59
|
+
unbind(value) {
|
|
60
|
+
return String(value);
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
string: identity("TEXT"),
|
|
64
|
+
time: identity("TIME"),
|
|
65
|
+
u128: {
|
|
66
|
+
bind(value) {
|
|
67
|
+
return String(value);
|
|
68
|
+
},
|
|
69
|
+
column: "NUMERIC(39, 0)",
|
|
70
|
+
unbind(value) {
|
|
71
|
+
return BigInt(value);
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
u16: number("INTEGER"),
|
|
75
|
+
u32: {
|
|
76
|
+
bind(value) {
|
|
77
|
+
return String(value);
|
|
78
|
+
},
|
|
79
|
+
column: "BIGINT",
|
|
80
|
+
unbind(value) {
|
|
81
|
+
return Number(value);
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
u64: {
|
|
85
|
+
bind(value) {
|
|
86
|
+
return String(value);
|
|
87
|
+
},
|
|
88
|
+
column: "NUMERIC(20, 0)",
|
|
89
|
+
unbind(value) {
|
|
90
|
+
return BigInt(value);
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
u8: number("SMALLINT"),
|
|
94
|
+
url: {
|
|
95
|
+
bind(value) {
|
|
96
|
+
return value.toString();
|
|
97
|
+
},
|
|
98
|
+
column: "TEXT",
|
|
99
|
+
unbind(value) {
|
|
100
|
+
return new URL(value);
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
export default typemap;
|
|
105
|
+
//# sourceMappingURL=typemap.js.map
|
package/package.json
CHANGED
|
@@ -1,34 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@primate/postgresql",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Primate PostgreSQL database",
|
|
5
|
-
"homepage": "https://
|
|
6
|
-
"bugs": "https://github.com/
|
|
5
|
+
"homepage": "https://primate.run/docs/database/postgresql",
|
|
6
|
+
"bugs": "https://github.com/primate-run/primate/issues",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"files": [
|
|
9
|
-
"
|
|
10
|
-
"
|
|
9
|
+
"/lib/**/*.js",
|
|
10
|
+
"/lib/**/*.d.ts",
|
|
11
|
+
"!/**/*.spec.*"
|
|
11
12
|
],
|
|
12
13
|
"repository": {
|
|
13
14
|
"type": "git",
|
|
14
|
-
"url": "https://github.com/
|
|
15
|
+
"url": "https://github.com/primate-run/primate",
|
|
15
16
|
"directory": "packages/postgresql"
|
|
16
17
|
},
|
|
17
18
|
"dependencies": {
|
|
18
|
-
"@rcompat/
|
|
19
|
-
"@rcompat/
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"@primate/
|
|
19
|
+
"@rcompat/assert": "^0.3.1",
|
|
20
|
+
"@rcompat/record": "^0.9.1",
|
|
21
|
+
"pema": "",
|
|
22
|
+
"postgres": "^3.4.7",
|
|
23
|
+
"@primate/core": "^0.3.0"
|
|
23
24
|
},
|
|
24
25
|
"type": "module",
|
|
25
26
|
"imports": {
|
|
26
27
|
"#*": {
|
|
27
|
-
"
|
|
28
|
-
"default": "./
|
|
28
|
+
"apekit": "./src/private/*.ts",
|
|
29
|
+
"default": "./lib/private/*.js"
|
|
29
30
|
}
|
|
30
31
|
},
|
|
31
32
|
"exports": {
|
|
32
|
-
".":
|
|
33
|
+
".": {
|
|
34
|
+
"apekit": "./src/public/index.ts",
|
|
35
|
+
"default": "./lib/public/index.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "npm run clean && tsc",
|
|
40
|
+
"clean": "rm -rf ./lib",
|
|
41
|
+
"lint": "eslint .",
|
|
42
|
+
"test": "npm run build && npx proby"
|
|
33
43
|
}
|
|
34
44
|
}
|
package/src/default.js
DELETED
package/src/private/Facade.js
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
import typemap from "#typemap";
|
|
2
|
-
import make_sort from "@primate/store/sql/make-sort";
|
|
3
|
-
import filter from "@rcompat/object/filter";
|
|
4
|
-
import valmap from "@rcompat/object/valmap";
|
|
5
|
-
|
|
6
|
-
const filter_null = object => filter(object, ([, value]) => value !== null);
|
|
7
|
-
const filter_nulls = objects => objects.map(object => filter_null(object));
|
|
8
|
-
|
|
9
|
-
export default class Connection {
|
|
10
|
-
schema = {
|
|
11
|
-
create: async (name, description) => {
|
|
12
|
-
const { connection } = this;
|
|
13
|
-
const body =
|
|
14
|
-
Object.entries(valmap(description, value => typemap(value.base)))
|
|
15
|
-
.map(([column, dataType]) => `"${column}" ${dataType}`).join(",");
|
|
16
|
-
await connection`
|
|
17
|
-
create table if not exists
|
|
18
|
-
${connection(name)} (${connection.unsafe(body)})
|
|
19
|
-
`;
|
|
20
|
-
},
|
|
21
|
-
delete: async name => {
|
|
22
|
-
const { connection } = this;
|
|
23
|
-
await connection`drop table if exists ${connection(name)};`;
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
constructor(connection) {
|
|
28
|
-
this.connection = connection;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
async find(collection, criteria = {}, projection = [], options = {}) {
|
|
32
|
-
const { connection } = this;
|
|
33
|
-
const rest = make_sort(options);
|
|
34
|
-
const select = projection.length === 0 ? "*" : projection.join(", ");
|
|
35
|
-
return filter_nulls(await connection`
|
|
36
|
-
select ${connection.unsafe(select)}
|
|
37
|
-
from ${connection(collection)}
|
|
38
|
-
where ${Object.entries(criteria).reduce((acc, [key, value]) =>
|
|
39
|
-
connection`${acc} and ${connection(key)} = ${value}`, connection`true`)}
|
|
40
|
-
${connection.unsafe(rest)}`);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async count(collection, criteria = {}) {
|
|
44
|
-
const { connection } = this;
|
|
45
|
-
const [{ count }] = await connection`
|
|
46
|
-
select count(*)
|
|
47
|
-
from ${connection(collection)}
|
|
48
|
-
where ${Object.entries(criteria).reduce((acc, [key, value]) =>
|
|
49
|
-
connection`${acc} and ${connection(key)} = ${value}`, connection`true`)}
|
|
50
|
-
`;
|
|
51
|
-
return Number(count);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
async get(collection, primary, value) {
|
|
55
|
-
const { connection } = this;
|
|
56
|
-
const [result] = await connection`
|
|
57
|
-
select *
|
|
58
|
-
from ${connection(collection)}
|
|
59
|
-
where ${connection(primary)}=${value};
|
|
60
|
-
`;
|
|
61
|
-
return result === undefined ? result : filter_null(result);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
async insert(collection, primary, document) {
|
|
65
|
-
const { connection } = this;
|
|
66
|
-
const columns = Object.keys(document);
|
|
67
|
-
const [result] = await this.connection`insert into
|
|
68
|
-
${connection(collection)}
|
|
69
|
-
${columns.length > 0
|
|
70
|
-
? connection`(${connection(columns)}) values ${connection(document)}`
|
|
71
|
-
: connection.unsafe("default values")}
|
|
72
|
-
returning *;
|
|
73
|
-
`;
|
|
74
|
-
return filter_null(result);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async update(collection, criteria = {}, delta = {}) {
|
|
78
|
-
const { connection } = this;
|
|
79
|
-
return (await connection`
|
|
80
|
-
update ${connection(collection)}
|
|
81
|
-
set ${connection({ ...delta })}
|
|
82
|
-
where ${Object.entries(criteria).reduce((acc, [key, value]) =>
|
|
83
|
-
connection`${acc} and ${connection(key)} = ${value}`, connection`true`)}
|
|
84
|
-
returning *;
|
|
85
|
-
`).length;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async delete(collection, criteria = {}) {
|
|
89
|
-
const { connection } = this;
|
|
90
|
-
return (await connection`
|
|
91
|
-
delete from ${connection(collection)}
|
|
92
|
-
where ${Object.entries(criteria).reduce((acc, [key, value]) =>
|
|
93
|
-
connection`${acc} and ${connection(key)} = ${value}`, connection`true`)}
|
|
94
|
-
returning *;
|
|
95
|
-
`).length;
|
|
96
|
-
}
|
|
97
|
-
}
|
package/src/private/connect.js
DELETED
package/src/private/defaults.js
DELETED
package/src/private/serve.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import Facade from "#Facade";
|
|
2
|
-
import connect from "#connect";
|
|
3
|
-
import ident from "@primate/store/core/ident";
|
|
4
|
-
import wrap from "@primate/store/core/wrap";
|
|
5
|
-
import numeric from "@rcompat/invariant/numeric";
|
|
6
|
-
|
|
7
|
-
export default options => async () => {
|
|
8
|
-
const client = connect(options);
|
|
9
|
-
|
|
10
|
-
const types = {
|
|
11
|
-
primary: {
|
|
12
|
-
validate(value) {
|
|
13
|
-
if (typeof value === "number" || numeric(value)) {
|
|
14
|
-
return Number(value);
|
|
15
|
-
}
|
|
16
|
-
throw new Error(`\`${value}\` is not a valid primary key value`);
|
|
17
|
-
},
|
|
18
|
-
...ident,
|
|
19
|
-
},
|
|
20
|
-
object: {
|
|
21
|
-
in(value) {
|
|
22
|
-
return JSON.stringify(value);
|
|
23
|
-
},
|
|
24
|
-
out(value) {
|
|
25
|
-
return JSON.parse(value);
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
number: ident,
|
|
29
|
-
bigint: {
|
|
30
|
-
in(value) {
|
|
31
|
-
return value.toString();
|
|
32
|
-
},
|
|
33
|
-
out(value) {
|
|
34
|
-
return BigInt(value);
|
|
35
|
-
},
|
|
36
|
-
},
|
|
37
|
-
boolean: ident,
|
|
38
|
-
date: {
|
|
39
|
-
in(value) {
|
|
40
|
-
return value;
|
|
41
|
-
},
|
|
42
|
-
out(value) {
|
|
43
|
-
return new Date(value);
|
|
44
|
-
},
|
|
45
|
-
},
|
|
46
|
-
string: ident,
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
name: "@primate/postgresql",
|
|
51
|
-
types,
|
|
52
|
-
async transact(stores) {
|
|
53
|
-
return (others, next) =>
|
|
54
|
-
client.begin(async connection => {
|
|
55
|
-
const facade = new Facade(connection);
|
|
56
|
-
return next([
|
|
57
|
-
...others, ...stores.map(([name, store]) =>
|
|
58
|
-
[name, wrap(store, facade, types)]),
|
|
59
|
-
]);
|
|
60
|
-
});
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
};
|
package/src/private/typemap.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const types = {
|
|
2
|
-
/* array */
|
|
3
|
-
blob: "bytea",
|
|
4
|
-
boolean: "boolean",
|
|
5
|
-
datetime: "timestamp",
|
|
6
|
-
embedded: "text",
|
|
7
|
-
f64: "real",
|
|
8
|
-
i8: "smallint",
|
|
9
|
-
i16: "integer",
|
|
10
|
-
i32: "bigint",
|
|
11
|
-
i64: "decimal",
|
|
12
|
-
json: "json",
|
|
13
|
-
primary: "serial primary key",
|
|
14
|
-
string: "text",
|
|
15
|
-
time: "time",
|
|
16
|
-
u8: "smallint",
|
|
17
|
-
u16: "integer",
|
|
18
|
-
u32: "integer",
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export default value => types[value];
|