@itrocks/mysql 0.0.1 → 0.0.3
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/cjs/mysql.d.ts +6 -5
- package/cjs/mysql.js +7 -5
- package/esm/mysql.d.ts +55 -0
- package/esm/mysql.js +205 -0
- package/package.json +2 -2
package/cjs/mysql.d.ts
CHANGED
|
@@ -5,17 +5,18 @@ import { Entity, MayEntity } from '@itrocks/storage';
|
|
|
5
5
|
import { Identifier, SearchType } from '@itrocks/storage';
|
|
6
6
|
import { Connection } from 'mariadb';
|
|
7
7
|
export declare const DEBUG = false;
|
|
8
|
-
export interface Dependencies {
|
|
8
|
+
export interface Dependencies<QF extends object = object> {
|
|
9
9
|
applyReadTransformer: <T extends object>(object: T, property: KeyOf<T>, data: AnyObject) => any;
|
|
10
10
|
applySaveTransformer: <T extends object>(object: T, property: KeyOf<T>, data: AnyObject) => any;
|
|
11
11
|
columnOf: (property: string) => string;
|
|
12
12
|
componentOf: <T extends object>(target: T, property: KeyOf<T>) => boolean;
|
|
13
13
|
ignoreTransformedValue: any;
|
|
14
|
-
|
|
14
|
+
QueryFunction: Type<QF>;
|
|
15
|
+
queryFunctionCall: (value: QF) => [any, string];
|
|
15
16
|
storeOf: <T extends object>(target: ObjectOrType<T>) => string | false;
|
|
16
17
|
}
|
|
17
18
|
export declare const depends: Dependencies;
|
|
18
|
-
export declare function dependsOn(dependencies: Partial<Dependencies
|
|
19
|
+
export declare function dependsOn<QF extends object = object>(dependencies: Partial<Dependencies<QF>>): void;
|
|
19
20
|
export default class Mysql extends DataSource {
|
|
20
21
|
config: {
|
|
21
22
|
host: string;
|
|
@@ -33,9 +34,9 @@ export default class Mysql extends DataSource {
|
|
|
33
34
|
connect(): Promise<Connection>;
|
|
34
35
|
delete<T extends object>(object: Entity<T>, property?: KeyOf<Entity<T>>): Promise<T>;
|
|
35
36
|
deleteId<T extends object>(type: ObjectOrType<T>, id: any, property?: KeyOf<Entity<T>>): Promise<void>;
|
|
36
|
-
|
|
37
|
+
deleteRelatedId<T extends Entity>(object: T, property: KeyOf<T>, id: Identifier): Promise<void>;
|
|
37
38
|
insert<T extends object>(object: T): Promise<Entity<T>>;
|
|
38
|
-
|
|
39
|
+
insertRelatedId<T extends Entity>(object: T, property: KeyOf<T>, id: Identifier): Promise<void>;
|
|
39
40
|
propertiesToSearchSql(search: AnyObject): string;
|
|
40
41
|
propertiesToSql(object: object): string;
|
|
41
42
|
read<T extends object>(type: Type<T>, id: Identifier): Promise<Entity<T>>;
|
package/cjs/mysql.js
CHANGED
|
@@ -13,7 +13,9 @@ exports.depends = {
|
|
|
13
13
|
columnOf: name => name,
|
|
14
14
|
componentOf: () => false,
|
|
15
15
|
ignoreTransformedValue: Symbol('ignoreTransformedValue'),
|
|
16
|
-
|
|
16
|
+
QueryFunction: class {
|
|
17
|
+
},
|
|
18
|
+
queryFunctionCall: () => [undefined, ' = ?'],
|
|
17
19
|
storeOf: () => false
|
|
18
20
|
};
|
|
19
21
|
function dependsOn(dependencies) {
|
|
@@ -43,7 +45,7 @@ class Mysql extends storage_1.DataSource {
|
|
|
43
45
|
console.log('DELETE FROM `' + exports.depends.storeOf(type) + '` WHERE `' + exports.depends.columnOf(property) + '` = ?', [id]);
|
|
44
46
|
await connection.query('DELETE FROM `' + exports.depends.storeOf(type) + '` WHERE `' + exports.depends.columnOf(property) + '` = ?', [id]);
|
|
45
47
|
}
|
|
46
|
-
async
|
|
48
|
+
async deleteRelatedId(object, property, id) {
|
|
47
49
|
const connection = this.connection ?? await this.connect();
|
|
48
50
|
const objectTable = exports.depends.storeOf(object);
|
|
49
51
|
const propertyTable = exports.depends.storeOf(new reflect_1.ReflectProperty(object, property).collectionType.elementType);
|
|
@@ -69,7 +71,7 @@ class Mysql extends storage_1.DataSource {
|
|
|
69
71
|
}
|
|
70
72
|
return entity;
|
|
71
73
|
}
|
|
72
|
-
async
|
|
74
|
+
async insertRelatedId(object, property, id) {
|
|
73
75
|
const connection = this.connection ?? await this.connect();
|
|
74
76
|
const objectTable = exports.depends.storeOf(object);
|
|
75
77
|
const propertyTable = exports.depends.storeOf(new reflect_1.ReflectProperty(object, property).collectionType.elementType);
|
|
@@ -84,8 +86,8 @@ class Mysql extends storage_1.DataSource {
|
|
|
84
86
|
const sql = Object.entries(search)
|
|
85
87
|
.map(([name, value]) => {
|
|
86
88
|
let sql;
|
|
87
|
-
if (value instanceof exports.depends.
|
|
88
|
-
[search[name], sql] = exports.depends.
|
|
89
|
+
if (value instanceof exports.depends.QueryFunction) {
|
|
90
|
+
[search[name], sql] = exports.depends.queryFunctionCall(value);
|
|
89
91
|
}
|
|
90
92
|
else {
|
|
91
93
|
sql = ' = ?';
|
package/esm/mysql.d.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { AnyObject } from '@itrocks/class-type';
|
|
2
|
+
import { KeyOf, ObjectOrType, Type } from '@itrocks/class-type';
|
|
3
|
+
import { DataSource } from '@itrocks/storage';
|
|
4
|
+
import { Entity, MayEntity } from '@itrocks/storage';
|
|
5
|
+
import { Identifier, SearchType } from '@itrocks/storage';
|
|
6
|
+
import { Connection } from 'mariadb';
|
|
7
|
+
export declare const DEBUG = false;
|
|
8
|
+
export interface Dependencies<QF extends object = object> {
|
|
9
|
+
applyReadTransformer: <T extends object>(object: T, property: KeyOf<T>, data: AnyObject) => any;
|
|
10
|
+
applySaveTransformer: <T extends object>(object: T, property: KeyOf<T>, data: AnyObject) => any;
|
|
11
|
+
columnOf: (property: string) => string;
|
|
12
|
+
componentOf: <T extends object>(target: T, property: KeyOf<T>) => boolean;
|
|
13
|
+
ignoreTransformedValue: any;
|
|
14
|
+
QueryFunction: Type<QF>;
|
|
15
|
+
queryFunctionCall: (value: QF) => [any, string];
|
|
16
|
+
storeOf: <T extends object>(target: ObjectOrType<T>) => string | false;
|
|
17
|
+
}
|
|
18
|
+
export declare const depends: Dependencies;
|
|
19
|
+
export declare function dependsOn<QF extends object = object>(dependencies: Partial<Dependencies<QF>>): void;
|
|
20
|
+
export default class Mysql extends DataSource {
|
|
21
|
+
config: {
|
|
22
|
+
host: string;
|
|
23
|
+
user: string;
|
|
24
|
+
password: string;
|
|
25
|
+
database: string;
|
|
26
|
+
};
|
|
27
|
+
connection?: Connection;
|
|
28
|
+
constructor(config: {
|
|
29
|
+
host: string;
|
|
30
|
+
user: string;
|
|
31
|
+
password: string;
|
|
32
|
+
database: string;
|
|
33
|
+
});
|
|
34
|
+
connect(): Promise<Connection>;
|
|
35
|
+
delete<T extends object>(object: Entity<T>, property?: KeyOf<Entity<T>>): Promise<T>;
|
|
36
|
+
deleteId<T extends object>(type: ObjectOrType<T>, id: any, property?: KeyOf<Entity<T>>): Promise<void>;
|
|
37
|
+
deleteRelatedId<T extends Entity>(object: T, property: KeyOf<T>, id: Identifier): Promise<void>;
|
|
38
|
+
insert<T extends object>(object: T): Promise<Entity<T>>;
|
|
39
|
+
insertRelatedId<T extends Entity>(object: T, property: KeyOf<T>, id: Identifier): Promise<void>;
|
|
40
|
+
propertiesToSearchSql(search: AnyObject): string;
|
|
41
|
+
propertiesToSql(object: object): string;
|
|
42
|
+
read<T extends object>(type: Type<T>, id: Identifier): Promise<Entity<T>>;
|
|
43
|
+
readCollection<T extends object, PT extends object>(object: Entity<T>, property: KeyOf<T>, type?: Type<PT>): Promise<Awaited<PT & {
|
|
44
|
+
id: Identifier;
|
|
45
|
+
}>[]>;
|
|
46
|
+
readCollectionIds<T extends object, PT extends object>(object: Entity<T>, property: KeyOf<T>, type?: Type<PT>): Promise<Identifier[]>;
|
|
47
|
+
readMultiple<T extends object>(type: Type<T>, ids: Identifier[]): Promise<Awaited<T & {
|
|
48
|
+
id: Identifier;
|
|
49
|
+
}>[]>;
|
|
50
|
+
save<T extends object>(object: MayEntity<T>): Promise<Entity<T>>;
|
|
51
|
+
search<T extends object>(type: Type<T>, search?: SearchType<T>): Promise<Entity<T>[]>;
|
|
52
|
+
update<T extends object>(object: Entity<T>): Promise<Entity<T>>;
|
|
53
|
+
valuesFromDb<T extends object>(row: Entity<T>, type: Type<T>): Promise<Entity<T>>;
|
|
54
|
+
valuesToDb<T extends object>(object: T, type?: Type<T>): Promise<[AnyObject, Function[]]>;
|
|
55
|
+
}
|
package/esm/mysql.js
ADDED
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { isAnyFunction } from '@itrocks/class-type';
|
|
2
|
+
import { ReflectClass, ReflectProperty } from '@itrocks/reflect';
|
|
3
|
+
import { DataSource } from '@itrocks/storage';
|
|
4
|
+
import { createConnection } from 'mariadb';
|
|
5
|
+
export const DEBUG = false;
|
|
6
|
+
export const depends = {
|
|
7
|
+
applyReadTransformer: value => value,
|
|
8
|
+
applySaveTransformer: value => value,
|
|
9
|
+
columnOf: name => name,
|
|
10
|
+
componentOf: () => false,
|
|
11
|
+
ignoreTransformedValue: Symbol('ignoreTransformedValue'),
|
|
12
|
+
QueryFunction: class {
|
|
13
|
+
},
|
|
14
|
+
queryFunctionCall: () => [undefined, ' = ?'],
|
|
15
|
+
storeOf: () => false
|
|
16
|
+
};
|
|
17
|
+
export function dependsOn(dependencies) {
|
|
18
|
+
Object.assign(depends, dependencies);
|
|
19
|
+
}
|
|
20
|
+
export default class Mysql extends DataSource {
|
|
21
|
+
config;
|
|
22
|
+
connection;
|
|
23
|
+
constructor(config) {
|
|
24
|
+
super();
|
|
25
|
+
this.config = config;
|
|
26
|
+
}
|
|
27
|
+
async connect() {
|
|
28
|
+
const mariaDbConfig = Object.assign(this.config, {
|
|
29
|
+
allowPublicKeyRetrieval: true,
|
|
30
|
+
dateStrings: false
|
|
31
|
+
});
|
|
32
|
+
return this.connection = await createConnection(mariaDbConfig);
|
|
33
|
+
}
|
|
34
|
+
async delete(object, property = 'id') {
|
|
35
|
+
await this.deleteId(object, object[property], property);
|
|
36
|
+
return this.disconnectObject(object);
|
|
37
|
+
}
|
|
38
|
+
async deleteId(type, id, property = 'id') {
|
|
39
|
+
const connection = this.connection ?? await this.connect();
|
|
40
|
+
if (DEBUG)
|
|
41
|
+
console.log('DELETE FROM `' + depends.storeOf(type) + '` WHERE `' + depends.columnOf(property) + '` = ?', [id]);
|
|
42
|
+
await connection.query('DELETE FROM `' + depends.storeOf(type) + '` WHERE `' + depends.columnOf(property) + '` = ?', [id]);
|
|
43
|
+
}
|
|
44
|
+
async deleteRelatedId(object, property, id) {
|
|
45
|
+
const connection = this.connection ?? await this.connect();
|
|
46
|
+
const objectTable = depends.storeOf(object);
|
|
47
|
+
const propertyTable = depends.storeOf(new ReflectProperty(object, property).collectionType.elementType);
|
|
48
|
+
const joinTable = [objectTable, propertyTable].sort().join('_');
|
|
49
|
+
const query = 'DELETE FROM `' + joinTable + '` WHERE ' + objectTable + '_id = ? AND ' + propertyTable + '_id = ?';
|
|
50
|
+
const values = [object.id, id];
|
|
51
|
+
if (DEBUG)
|
|
52
|
+
console.log(query, JSON.stringify(values));
|
|
53
|
+
connection.query(query, values);
|
|
54
|
+
}
|
|
55
|
+
async insert(object) {
|
|
56
|
+
const connection = this.connection ?? await this.connect();
|
|
57
|
+
const [values, deferred] = await this.valuesToDb(object);
|
|
58
|
+
const sql = this.propertiesToSql(values);
|
|
59
|
+
const query = 'INSERT INTO `' + depends.storeOf(object) + '` SET ' + sql;
|
|
60
|
+
if (DEBUG)
|
|
61
|
+
console.log(query, JSON.stringify(Object.values(values)));
|
|
62
|
+
const result = await connection.query(query, Object.values(values));
|
|
63
|
+
const id = result.insertId;
|
|
64
|
+
const entity = this.connectObject(object, ((id >= Number.MIN_SAFE_INTEGER) && (id <= Number.MAX_SAFE_INTEGER)) ? Number(id) : id);
|
|
65
|
+
for (const callback of deferred) {
|
|
66
|
+
callback(object);
|
|
67
|
+
}
|
|
68
|
+
return entity;
|
|
69
|
+
}
|
|
70
|
+
async insertRelatedId(object, property, id) {
|
|
71
|
+
const connection = this.connection ?? await this.connect();
|
|
72
|
+
const objectTable = depends.storeOf(object);
|
|
73
|
+
const propertyTable = depends.storeOf(new ReflectProperty(object, property).collectionType.elementType);
|
|
74
|
+
const joinTable = [objectTable, propertyTable].sort().join('_');
|
|
75
|
+
const query = 'INSERT INTO `' + joinTable + '` SET ' + objectTable + '_id = ?, ' + propertyTable + '_id = ?';
|
|
76
|
+
const values = [object.id, id];
|
|
77
|
+
if (DEBUG)
|
|
78
|
+
console.log(query, JSON.stringify(values));
|
|
79
|
+
connection.query(query, values);
|
|
80
|
+
}
|
|
81
|
+
propertiesToSearchSql(search) {
|
|
82
|
+
const sql = Object.entries(search)
|
|
83
|
+
.map(([name, value]) => {
|
|
84
|
+
let sql;
|
|
85
|
+
if (value instanceof depends.QueryFunction) {
|
|
86
|
+
[search[name], sql] = depends.queryFunctionCall(value);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
sql = ' = ?';
|
|
90
|
+
}
|
|
91
|
+
return '`' + depends.columnOf(name) + '`' + sql;
|
|
92
|
+
})
|
|
93
|
+
.join(' AND ');
|
|
94
|
+
return sql.length
|
|
95
|
+
? ' WHERE ' + sql
|
|
96
|
+
: '';
|
|
97
|
+
}
|
|
98
|
+
propertiesToSql(object) {
|
|
99
|
+
return Object.keys(object).map(name => '`' + depends.columnOf(name) + '` = ?').join(', ');
|
|
100
|
+
}
|
|
101
|
+
async read(type, id) {
|
|
102
|
+
const connection = this.connection ?? await this.connect();
|
|
103
|
+
if (DEBUG)
|
|
104
|
+
console.log('SELECT * FROM `' + depends.storeOf(type) + '` WHERE id = ?', [id]);
|
|
105
|
+
const rows = await connection.query('SELECT * FROM `' + depends.storeOf(type) + '` WHERE id = ?', [id]);
|
|
106
|
+
return this.valuesFromDb(rows[0], type);
|
|
107
|
+
}
|
|
108
|
+
async readCollection(object, property, type = new ReflectProperty(object, property).collectionType.elementType) {
|
|
109
|
+
const connection = this.connection ?? await this.connect();
|
|
110
|
+
const objectTable = depends.storeOf(object);
|
|
111
|
+
const table = depends.storeOf(type);
|
|
112
|
+
let query;
|
|
113
|
+
if (depends.componentOf(object, property)) {
|
|
114
|
+
query = 'SELECT * FROM `' + table + '` WHERE ' + objectTable + '_id = ?';
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
const joinTable = [objectTable, table].sort().join('_');
|
|
118
|
+
query = 'SELECT `' + table + '`.* FROM `' + table + '`'
|
|
119
|
+
+ ' INNER JOIN `' + joinTable + '` ON `' + joinTable + '`.' + table + '_id = `' + table + '`.id'
|
|
120
|
+
+ ' WHERE `' + joinTable + '`.' + objectTable + '_id = ?';
|
|
121
|
+
}
|
|
122
|
+
const rows = await connection.query(query, [object.id]);
|
|
123
|
+
return Promise.all(rows.map(row => this.valuesFromDb(row, type)));
|
|
124
|
+
}
|
|
125
|
+
async readCollectionIds(object, property, type = new ReflectProperty(object, property).collectionType.elementType) {
|
|
126
|
+
const connection = this.connection ?? await this.connect();
|
|
127
|
+
const objectTable = depends.storeOf(object);
|
|
128
|
+
const propertyTable = depends.storeOf(type);
|
|
129
|
+
let query;
|
|
130
|
+
if (depends.componentOf(object, property)) {
|
|
131
|
+
query = 'SELECT id FROM `' + propertyTable + '` WHERE ' + objectTable + '_id = ?';
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
const joinTable = [objectTable, propertyTable].sort().join('_');
|
|
135
|
+
query = 'SELECT ' + propertyTable + '_id id FROM `' + joinTable + '`'
|
|
136
|
+
+ ' WHERE `' + joinTable + '`.' + objectTable + '_id = ?';
|
|
137
|
+
}
|
|
138
|
+
const rows = await connection.query(query, [object.id]);
|
|
139
|
+
return Promise.all(rows.map(row => row.id));
|
|
140
|
+
}
|
|
141
|
+
async readMultiple(type, ids) {
|
|
142
|
+
if (!ids.length)
|
|
143
|
+
return [];
|
|
144
|
+
const connection = this.connection ?? await this.connect();
|
|
145
|
+
const questionMarks = Array(ids.length).fill('?').join(', ');
|
|
146
|
+
if (DEBUG)
|
|
147
|
+
console.log('SELECT * FROM `' + depends.storeOf(type) + '` WHERE id IN (' + questionMarks + ')', ids);
|
|
148
|
+
const rows = await connection.query('SELECT * FROM `' + depends.storeOf(type) + '` WHERE id IN (' + questionMarks + ')', ids);
|
|
149
|
+
return Promise.all(rows.map(row => this.valuesFromDb(row, type)));
|
|
150
|
+
}
|
|
151
|
+
async save(object) {
|
|
152
|
+
return this.isObjectConnected(object)
|
|
153
|
+
? this.update(object)
|
|
154
|
+
: this.insert(object);
|
|
155
|
+
}
|
|
156
|
+
async search(type, search = {}) {
|
|
157
|
+
const connection = this.connection ?? await this.connect();
|
|
158
|
+
const sql = this.propertiesToSearchSql(search);
|
|
159
|
+
const [values] = await this.valuesToDb(search, type);
|
|
160
|
+
if (DEBUG)
|
|
161
|
+
console.log('SELECT * FROM `' + depends.storeOf(type) + '`' + sql, '[', values, ']');
|
|
162
|
+
const rows = await connection.query('SELECT * FROM `' + depends.storeOf(type) + '`' + sql, Object.values(values));
|
|
163
|
+
return Promise.all(rows.map(row => this.valuesFromDb(row, type)));
|
|
164
|
+
}
|
|
165
|
+
async update(object) {
|
|
166
|
+
const connection = this.connection ?? await this.connect();
|
|
167
|
+
const [values, deferred] = await this.valuesToDb(object);
|
|
168
|
+
const sql = this.propertiesToSql(values);
|
|
169
|
+
const query = 'UPDATE `' + depends.storeOf(object) + '` SET ' + sql + ' WHERE id = ?';
|
|
170
|
+
if (DEBUG)
|
|
171
|
+
console.log(query, JSON.stringify(Object.values(values).concat([object.id])));
|
|
172
|
+
await connection.query(query, Object.values(values).concat([object.id]));
|
|
173
|
+
for (const callback of deferred) {
|
|
174
|
+
callback(object);
|
|
175
|
+
}
|
|
176
|
+
return object;
|
|
177
|
+
}
|
|
178
|
+
async valuesFromDb(row, type) {
|
|
179
|
+
const object = (new type);
|
|
180
|
+
let property;
|
|
181
|
+
for (property in row) {
|
|
182
|
+
const value = await depends.applyReadTransformer(object, property, row);
|
|
183
|
+
if (value === depends.ignoreTransformedValue)
|
|
184
|
+
continue;
|
|
185
|
+
object[property] = value;
|
|
186
|
+
}
|
|
187
|
+
return object;
|
|
188
|
+
}
|
|
189
|
+
async valuesToDb(object, type) {
|
|
190
|
+
const typeObject = type ? new type : object;
|
|
191
|
+
const deferred = [];
|
|
192
|
+
const values = {};
|
|
193
|
+
for (const property of type ? Object.keys(object) : new ReflectClass(object).propertyNames) {
|
|
194
|
+
const value = await depends.applySaveTransformer(typeObject, property, values);
|
|
195
|
+
if (value === depends.ignoreTransformedValue)
|
|
196
|
+
continue;
|
|
197
|
+
if (isAnyFunction(value)) {
|
|
198
|
+
deferred.push(value);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
values[property] = value;
|
|
202
|
+
}
|
|
203
|
+
return [values, deferred];
|
|
204
|
+
}
|
|
205
|
+
}
|
package/package.json
CHANGED
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"scripts": {
|
|
56
56
|
"build": "npm run build:cjs && npm run build:esm",
|
|
57
57
|
"build:cjs": "tsc -p tsconfig.cjs.json",
|
|
58
|
-
"build:esm": "tsc -p tsconfig.esm.json
|
|
58
|
+
"build:esm": "tsc -p tsconfig.esm.json"
|
|
59
59
|
},
|
|
60
60
|
"types": "./esm/mysql.d.ts",
|
|
61
|
-
"version": "0.0.
|
|
61
|
+
"version": "0.0.3"
|
|
62
62
|
}
|