easy-postgresql 0.0.1
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/LICENSE +21 -0
- package/README.md +45 -0
- package/SECURITY.md +15 -0
- package/database/procedure.ts +129 -0
- package/database/query.ts +78 -0
- package/database/sql_types.d.ts +52 -0
- package/database/sql_types.ts +90 -0
- package/database/table.ts +378 -0
- package/database.ts +26 -0
- package/dist/database/procedure.d.ts +26 -0
- package/dist/database/procedure.js +107 -0
- package/dist/database/procedure.js.map +1 -0
- package/dist/database/query.d.ts +13 -0
- package/dist/database/query.js +79 -0
- package/dist/database/query.js.map +1 -0
- package/dist/database/sql_types.d.ts +48 -0
- package/dist/database/sql_types.js +50 -0
- package/dist/database/sql_types.js.map +1 -0
- package/dist/database/table.d.ts +54 -0
- package/dist/database/table.js +308 -0
- package/dist/database/table.js.map +1 -0
- package/dist/database.d.ts +24 -0
- package/dist/database.js +28 -0
- package/dist/database.js.map +1 -0
- package/dist/operations/config.d.ts +22 -0
- package/dist/operations/config.js +30 -0
- package/dist/operations/config.js.map +1 -0
- package/dist/operations/connect_to_server.d.ts +28 -0
- package/dist/operations/connect_to_server.js +108 -0
- package/dist/operations/connect_to_server.js.map +1 -0
- package/dist/operations/data_types.d.ts +6 -0
- package/dist/operations/data_types.js +120 -0
- package/dist/operations/data_types.js.map +1 -0
- package/dist/operations/get_pieces.d.ts +29 -0
- package/dist/operations/get_pieces.js +56 -0
- package/dist/operations/get_pieces.js.map +1 -0
- package/dist/operations/log.d.ts +12 -0
- package/dist/operations/log.js +27 -0
- package/dist/operations/log.js.map +1 -0
- package/dist/operations/procedure_execute.d.ts +18 -0
- package/dist/operations/procedure_execute.js +53 -0
- package/dist/operations/procedure_execute.js.map +1 -0
- package/operations/config.ts +28 -0
- package/operations/connect_to_server.ts +111 -0
- package/operations/data_types.ts +129 -0
- package/operations/get_pieces.ts +63 -0
- package/operations/log.ts +27 -0
- package/operations/procedure_execute.ts +58 -0
- package/package.json +55 -0
- package/simple/advanced-test.js +631 -0
- package/simple/config.simple.js +9 -0
- package/simple/config.simple.ts +9 -0
- package/simple/test.js +398 -0
- package/simple/test.ts +392 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import { sqlTypes } from '../operations/data_types';
|
|
2
|
+
import { getConditionPieces, getInsertPieces, isValidIdentifier } from '../operations/get_pieces';
|
|
3
|
+
import { config } from '../operations/config';
|
|
4
|
+
import { Query } from './query';
|
|
5
|
+
import { log } from '../operations/log';
|
|
6
|
+
|
|
7
|
+
interface TableOptions {
|
|
8
|
+
limit?: number | null;
|
|
9
|
+
selected_keys?: string[];
|
|
10
|
+
likes?: Record<string, string>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface TableSchema {
|
|
14
|
+
[key: string]: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface TableInfo {
|
|
18
|
+
name: string;
|
|
19
|
+
type: string;
|
|
20
|
+
date: string | null;
|
|
21
|
+
schema: TableSchema;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface TableResult {
|
|
25
|
+
status: number;
|
|
26
|
+
message: string;
|
|
27
|
+
data: any[] | null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
interface TableReference {
|
|
31
|
+
[key: string]: any;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface TableData {
|
|
35
|
+
[key: string]: any;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
interface TableFunctions {
|
|
39
|
+
create: (scheme: TableSchema) => Promise<boolean>;
|
|
40
|
+
remove: () => Promise<boolean>;
|
|
41
|
+
isThere: () => Promise<boolean>;
|
|
42
|
+
info: () => Promise<TableInfo | null>;
|
|
43
|
+
getAll: () => Promise<TableInfo[] | null>;
|
|
44
|
+
updateColumn: (columnName: string) => {
|
|
45
|
+
add: (type: string) => Promise<boolean>;
|
|
46
|
+
remove: () => Promise<boolean>;
|
|
47
|
+
rename: (newColumnName: string) => Promise<boolean>;
|
|
48
|
+
update: (type: string) => Promise<boolean>;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function TableFunctions(name: string): TableFunctions {
|
|
53
|
+
async function create(scheme: TableSchema): Promise<boolean> {
|
|
54
|
+
const isThereTable = await isThere();
|
|
55
|
+
if (isThereTable) return false;
|
|
56
|
+
|
|
57
|
+
if (!scheme || Object.keys(scheme).length === 0) return false;
|
|
58
|
+
const stringScheme = Object.keys(scheme).map(m => m + ' ' + scheme[m]).join(', ');
|
|
59
|
+
|
|
60
|
+
const queryString = `CREATE TABLE ${name} (${stringScheme})`;
|
|
61
|
+
return (await Query(queryString))?.status === 200;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function remove(): Promise<boolean> {
|
|
65
|
+
const isThereTable = await isThere();
|
|
66
|
+
if (!isThereTable) return false;
|
|
67
|
+
|
|
68
|
+
const queryString = `DROP TABLE ${name}`;
|
|
69
|
+
return (await Query(queryString))?.status === 200;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function isThere(): Promise<boolean> {
|
|
73
|
+
const queryString = `SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND LOWER(table_name) = LOWER($1)`;
|
|
74
|
+
const queryOutput = await Query(queryString, [name]);
|
|
75
|
+
return queryOutput?.status === 200 && (queryOutput?.data?.length ?? 0) > 0;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function info(): Promise<TableInfo | null> {
|
|
79
|
+
const queryString = `SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND LOWER(table_name) = LOWER($1)`;
|
|
80
|
+
const queryOutput = await Query(queryString, [name]);
|
|
81
|
+
if (queryOutput?.status !== 200) {
|
|
82
|
+
if (config.get.logingMode()) log('Table', 'Info', `Table ${name} not found.`);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const data = queryOutput?.data?.[0] || null;
|
|
87
|
+
if (!data) return null;
|
|
88
|
+
|
|
89
|
+
const schema = await getSchema();
|
|
90
|
+
return {
|
|
91
|
+
name: data.table_name,
|
|
92
|
+
type: 'Table',
|
|
93
|
+
date: null,
|
|
94
|
+
schema
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function getAll(): Promise<TableInfo[] | null> {
|
|
99
|
+
const queryString = `SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'`;
|
|
100
|
+
const queryOutput = await Query(queryString);
|
|
101
|
+
if (queryOutput?.status !== 200) {
|
|
102
|
+
if (config.get.logingMode()) log('Table', 'Get All', 'Tables not found.');
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const data = queryOutput?.data || [];
|
|
107
|
+
if (!data) return null;
|
|
108
|
+
|
|
109
|
+
return Promise.all(data.map(async (m: any) => {
|
|
110
|
+
const schema = await getSchema(m.table_name);
|
|
111
|
+
return {
|
|
112
|
+
name: m.table_name,
|
|
113
|
+
type: 'Table',
|
|
114
|
+
date: null,
|
|
115
|
+
schema
|
|
116
|
+
};
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function getSchema(tableName: string = name): Promise<TableSchema> {
|
|
121
|
+
const queryString = `SELECT COLUMN_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE LOWER(TABLE_NAME) = LOWER($1)`;
|
|
122
|
+
const queryOutput = await Query(queryString, [tableName]);
|
|
123
|
+
if (queryOutput?.status !== 200) return {};
|
|
124
|
+
|
|
125
|
+
const data = queryOutput?.data || [];
|
|
126
|
+
return data.reduce((acc: Record<string, string>, cur: any) => ({ ...acc, [cur.column_name]: cur.data_type }), {});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function updateColumn(columnName: string) {
|
|
130
|
+
async function add(type: string): Promise<boolean> {
|
|
131
|
+
const queryString = `ALTER TABLE ${name} ADD ${columnName} ${type}`;
|
|
132
|
+
return (await Query(queryString))?.status === 200;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function remove(): Promise<boolean> {
|
|
136
|
+
const queryString = `ALTER TABLE ${name} DROP COLUMN ${columnName}`;
|
|
137
|
+
return (await Query(queryString))?.status === 200;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async function rename(newColumnName: string): Promise<boolean> {
|
|
141
|
+
const queryString = `ALTER TABLE ${name} RENAME COLUMN ${columnName} TO ${newColumnName}`;
|
|
142
|
+
return (await Query(queryString))?.status === 200;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function update(type: string): Promise<boolean> {
|
|
146
|
+
const queryString = `ALTER TABLE ${name} ALTER COLUMN ${columnName} TYPE ${type}`;
|
|
147
|
+
return (await Query(queryString))?.status === 200;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
add,
|
|
152
|
+
remove,
|
|
153
|
+
rename,
|
|
154
|
+
update
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return {
|
|
159
|
+
create,
|
|
160
|
+
remove,
|
|
161
|
+
isThere,
|
|
162
|
+
info,
|
|
163
|
+
getAll,
|
|
164
|
+
updateColumn
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function Table(name: string) {
|
|
169
|
+
async function find(reference: TableReference = {}, options: TableOptions = { limit: null, selected_keys: [], likes: {} }): Promise<any[]> {
|
|
170
|
+
let table = await TableFunctions(name).info();
|
|
171
|
+
if (!table) {
|
|
172
|
+
if (config.get.logingMode()) log('Table', 'Find', `Table ${name} not found.`);
|
|
173
|
+
return [];
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const { condition, inputs } = getConditionPieces(reference, 0);
|
|
177
|
+
let referenceString = condition ? `WHERE ${condition}` : '';
|
|
178
|
+
|
|
179
|
+
if (Object.keys(options.likes || {}).length > 0) {
|
|
180
|
+
let likeKeys = Object.keys(options.likes || {});
|
|
181
|
+
let startIdx = inputs.length;
|
|
182
|
+
let likes = likeKeys.map((m, i) => `${m} LIKE $${startIdx + i + 1}`);
|
|
183
|
+
referenceString += referenceString ? ` AND ${likes.join(' AND ')}` : `WHERE ${likes.join(' AND ')}`;
|
|
184
|
+
for (const key of likeKeys) {
|
|
185
|
+
inputs.push((options.likes?.[key] || '').replaceAll('?', '%').replaceAll('.', '_'));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
let columns = '*';
|
|
190
|
+
if (Array.isArray(options.selected_keys) && options.selected_keys && options.selected_keys?.length > 0) {
|
|
191
|
+
columns = options.selected_keys.filter(k => isValidIdentifier(k)).join(', ');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
let limitString = (typeof options.limit === 'number' && options.limit > 0) ? ` LIMIT ${options.limit}` : '';
|
|
195
|
+
let queryString = `SELECT ${columns} FROM ${name} ${referenceString}${limitString}`;
|
|
196
|
+
|
|
197
|
+
let queryOutput = await Query(queryString, inputs.length > 0 ? inputs : undefined);
|
|
198
|
+
let data = queryOutput?.data || [];
|
|
199
|
+
|
|
200
|
+
if (data.length > 0) {
|
|
201
|
+
data = data.map(m => {
|
|
202
|
+
let keys = Object.keys(m);
|
|
203
|
+
let schemaControlled = false;
|
|
204
|
+
if (options?.selected_keys && options.selected_keys.length > 0 && keys.length <= Object.keys(table?.schema || {}).length) schemaControlled = true;
|
|
205
|
+
if (!schemaControlled && keys.length === Object.keys(table?.schema || {}).length) schemaControlled = true;
|
|
206
|
+
if (!schemaControlled) return null;
|
|
207
|
+
|
|
208
|
+
let new_data: Record<string, any> = {};
|
|
209
|
+
keys.forEach(key => {
|
|
210
|
+
const lowerKey = (key || '').toLowerCase();
|
|
211
|
+
const schemaKey = Object.keys(table!.schema).find(k => k.toLowerCase() === lowerKey) || '';
|
|
212
|
+
const converter = sqlTypes[table!.schema[schemaKey]];
|
|
213
|
+
new_data[key] = converter ? converter(m[key]) : m[key];
|
|
214
|
+
});
|
|
215
|
+
return new_data;
|
|
216
|
+
}).filter(f => f !== null);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
return data;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
async function findOne(reference: TableReference = {}, options: TableOptions = { selected_keys: [], likes: {} }): Promise<any | null> {
|
|
223
|
+
const findOption = { limit: 1, selected_keys: options.selected_keys, likes: options.likes };
|
|
224
|
+
return (await find(reference, findOption))[0] || null;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async function createOne(data: TableData): Promise<boolean> {
|
|
228
|
+
const { columns, values, inputs } = getInsertPieces(data);
|
|
229
|
+
const queryString = `INSERT INTO ${name} (${columns}) VALUES (${values})`;
|
|
230
|
+
const queryOutput = await Query(queryString, inputs);
|
|
231
|
+
return queryOutput?.status === 200;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function updateOne(reference: TableReference, data: TableData): Promise<boolean> {
|
|
235
|
+
const { condition: refCondition, inputs: refInputs } = getConditionPieces(reference, 0);
|
|
236
|
+
const { condition: dataCondition, inputs: dataInputs } = getConditionPieces(data, refInputs.length);
|
|
237
|
+
|
|
238
|
+
if (!refCondition) {
|
|
239
|
+
if (config.get.logingMode()) log('Table', 'Update', 'No reference provided for update');
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
if (!dataCondition) {
|
|
243
|
+
if (config.get.logingMode()) log('Table', 'Update', 'No data provided for update');
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const existingData = await findOne(reference);
|
|
248
|
+
if (!existingData) {
|
|
249
|
+
if (config.get.logingMode()) log('Table', 'Update', 'No data found for update');
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const allInputs = [...refInputs, ...dataInputs];
|
|
254
|
+
|
|
255
|
+
const setValues = dataCondition.replace(/ AND /g, ', ');
|
|
256
|
+
|
|
257
|
+
const queryString = `UPDATE ${name} SET ${setValues} WHERE ${refCondition}`;
|
|
258
|
+
const queryOutput = await Query(queryString, allInputs);
|
|
259
|
+
return queryOutput?.status === 200;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
async function deleteOne(reference: TableReference): Promise<boolean> {
|
|
263
|
+
const deleteOperation = await _deleteOne(reference);
|
|
264
|
+
if (deleteOperation === false) return false;
|
|
265
|
+
return deleteOperation.status === 200;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
async function _deleteOne(reference: TableReference): Promise<TableResult | false> {
|
|
269
|
+
const { condition, inputs } = getConditionPieces(reference, 0);
|
|
270
|
+
if (!condition) {
|
|
271
|
+
if (config.get.logingMode()) log('Table', 'Delete', 'No reference provided for delete');
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const queryString = `DELETE FROM ${name} WHERE ${condition}`;
|
|
276
|
+
return await Query(queryString, inputs);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
async function deleteAll(reference?: TableReference): Promise<boolean> {
|
|
280
|
+
const datas = await find(reference || {});
|
|
281
|
+
if (datas.length === 0) {
|
|
282
|
+
if (config.get.logingMode()) log('Table', 'Delete', 'No data found for delete');
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const deletes = await Promise.all(datas.map(async data => {
|
|
287
|
+
const _data: Record<string, any> = {};
|
|
288
|
+
Object.keys(data)
|
|
289
|
+
.filter(key => key !== 'created_at' && data[key] !== null)
|
|
290
|
+
.forEach(key => _data[key] = data[key]);
|
|
291
|
+
return await _deleteOne(_data);
|
|
292
|
+
}));
|
|
293
|
+
|
|
294
|
+
let output: TableResult;
|
|
295
|
+
const isCompleted = deletes.filter(f => f !== false && f.status !== 200).length === 0;
|
|
296
|
+
if (!isCompleted) output = { status: 500, message: "An error occurred while deleting", data: null };
|
|
297
|
+
else output = { status: 200, message: "Success", data: null };
|
|
298
|
+
|
|
299
|
+
return output.status === 200;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
async function first(reference: TableReference = {}, options: TableOptions = {}): Promise<any | null> {
|
|
303
|
+
const data = await find(reference, { ...options, limit: 1 });
|
|
304
|
+
return data[0] || null;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async function firstOrDefault(reference: TableReference = {}, options: TableOptions = {}): Promise<any | null> {
|
|
308
|
+
const data = await find(reference, { ...options, limit: 1 });
|
|
309
|
+
return data[0] || null;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async function single(reference: TableReference = {}, options: TableOptions = {}): Promise<any> {
|
|
313
|
+
const data = await find(reference, options);
|
|
314
|
+
if (data.length === 0) throw new Error("Sequence contains no elements");
|
|
315
|
+
if (data.length > 1) throw new Error("Sequence contains more than one element");
|
|
316
|
+
return data[0];
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async function singleOrDefault(reference: TableReference = {}, options: TableOptions = {}): Promise<any | null> {
|
|
320
|
+
const data = await find(reference, options);
|
|
321
|
+
if (data.length > 1) throw new Error("Sequence contains more than one element");
|
|
322
|
+
return data[0] || null;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async function last(reference: TableReference = {}, options: TableOptions = {}): Promise<any | null> {
|
|
326
|
+
const data = await find(reference, options);
|
|
327
|
+
return data[data.length - 1] || null;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async function lastOrDefault(reference: TableReference = {}, options: TableOptions = {}): Promise<any | null> {
|
|
331
|
+
const data = await find(reference, options);
|
|
332
|
+
return data[data.length - 1] || null;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
async function count(reference: TableReference = {}, options: TableOptions = {}): Promise<number> {
|
|
336
|
+
const data = await find(reference, options);
|
|
337
|
+
return data.length;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
async function min(key: string, reference: TableReference = {}, options: TableOptions = {}): Promise<number | null> {
|
|
341
|
+
const data = await find(reference, options);
|
|
342
|
+
if (data.length === 0) return null;
|
|
343
|
+
return Math.min(...data.map(item => item[key]));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
async function max(key: string, reference: TableReference = {}, options: TableOptions = {}): Promise<number | null> {
|
|
347
|
+
const data = await find(reference, options);
|
|
348
|
+
if (data.length === 0) return null;
|
|
349
|
+
return Math.max(...data.map(item => item[key]));
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
async function average(key: string, reference: TableReference = {}, options: TableOptions = {}): Promise<number | null> {
|
|
353
|
+
const data = await find(reference, options);
|
|
354
|
+
if (data.length === 0) return null;
|
|
355
|
+
const sum = data.reduce((acc, item) => acc + item[key], 0);
|
|
356
|
+
return sum / data.length;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return {
|
|
360
|
+
find,
|
|
361
|
+
findOne,
|
|
362
|
+
createOne,
|
|
363
|
+
updateOne,
|
|
364
|
+
deleteOne,
|
|
365
|
+
deleteAll,
|
|
366
|
+
first,
|
|
367
|
+
firstOrDefault,
|
|
368
|
+
single,
|
|
369
|
+
singleOrDefault,
|
|
370
|
+
last,
|
|
371
|
+
lastOrDefault,
|
|
372
|
+
count,
|
|
373
|
+
min,
|
|
374
|
+
max,
|
|
375
|
+
average,
|
|
376
|
+
functions: TableFunctions(name)
|
|
377
|
+
};
|
|
378
|
+
}
|
package/database.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import 'colors';
|
|
2
|
+
import { Table } from './database/table';
|
|
3
|
+
import { Procedure } from './database/procedure';
|
|
4
|
+
import { Query } from './database/query';
|
|
5
|
+
import { sqlTypes } from './database/sql_types';
|
|
6
|
+
import { connectToServer, isConnected } from './operations/connect_to_server';
|
|
7
|
+
import { config } from './operations/config';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* This class provides all database operations.
|
|
11
|
+
* @file database.ts
|
|
12
|
+
* @description This file contains the database operations.
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
class EasyPostgresql {
|
|
16
|
+
Table = Table;
|
|
17
|
+
Procedure = Procedure;
|
|
18
|
+
Query = Query;
|
|
19
|
+
Types = sqlTypes;
|
|
20
|
+
Connect = connectToServer;
|
|
21
|
+
IsConnected = isConnected;
|
|
22
|
+
Config = config.set;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const easyPostgresql = new EasyPostgresql();
|
|
26
|
+
export = easyPostgresql;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
interface ProcedureInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
type: string;
|
|
4
|
+
date: string | null;
|
|
5
|
+
}
|
|
6
|
+
interface ProcedureResult {
|
|
7
|
+
status: number;
|
|
8
|
+
message: string;
|
|
9
|
+
data: any[] | null;
|
|
10
|
+
}
|
|
11
|
+
interface ProcedureReference {
|
|
12
|
+
[key: string]: any;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* All functions in the procedure are defined in this class.
|
|
16
|
+
*
|
|
17
|
+
* @param name - The name of the procedure to be added to the procedure
|
|
18
|
+
* @returns Object containing procedure methods
|
|
19
|
+
*/
|
|
20
|
+
export declare function Procedure(name?: string): {
|
|
21
|
+
Execute: (reference?: ProcedureReference, useRecordsets?: boolean) => Promise<ProcedureResult>;
|
|
22
|
+
Info: () => Promise<ProcedureInfo | null>;
|
|
23
|
+
AllInfo: () => Promise<ProcedureInfo[] | null>;
|
|
24
|
+
SimpleOutput: () => Promise<Record<string, string>>;
|
|
25
|
+
};
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Procedure = Procedure;
|
|
4
|
+
const procedure_execute_1 = require("../operations/procedure_execute");
|
|
5
|
+
const data_types_1 = require("../operations/data_types");
|
|
6
|
+
const config_1 = require("../operations/config");
|
|
7
|
+
const query_1 = require("./query");
|
|
8
|
+
const log_1 = require("../operations/log");
|
|
9
|
+
/**
|
|
10
|
+
* All functions in the procedure are defined in this class.
|
|
11
|
+
*
|
|
12
|
+
* @param name - The name of the procedure to be added to the procedure
|
|
13
|
+
* @returns Object containing procedure methods
|
|
14
|
+
*/
|
|
15
|
+
function Procedure(name = '') {
|
|
16
|
+
/**
|
|
17
|
+
* Returns information about the procedure in the database.
|
|
18
|
+
* @returns Promise<ProcedureInfo | null> - Information about the procedure
|
|
19
|
+
*/
|
|
20
|
+
async function Info() {
|
|
21
|
+
if (!name)
|
|
22
|
+
return null;
|
|
23
|
+
const queryString = `SELECT routine_name FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND routine_schema = 'public' AND LOWER(routine_name) = LOWER($1)`;
|
|
24
|
+
const queryOutput = await (0, query_1.Query)(queryString, [name]);
|
|
25
|
+
if (queryOutput?.status !== 200) {
|
|
26
|
+
if (config_1.config.get.logingMode())
|
|
27
|
+
(0, log_1.log)('Procedure', 'Info', `The ${name} procedure not found.`);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const data = queryOutput?.data?.[0] || null;
|
|
31
|
+
if (!data)
|
|
32
|
+
return null;
|
|
33
|
+
return {
|
|
34
|
+
name: data.routine_name,
|
|
35
|
+
type: 'Function',
|
|
36
|
+
date: null
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Returns information about all procedures in the database.
|
|
41
|
+
* @returns Promise<ProcedureInfo[] | null> - Information about all procedures
|
|
42
|
+
*/
|
|
43
|
+
async function AllInfo() {
|
|
44
|
+
const queryString = `SELECT routine_name FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND routine_schema = 'public'`;
|
|
45
|
+
const queryOutput = await (0, query_1.Query)(queryString);
|
|
46
|
+
if (queryOutput?.status !== 200) {
|
|
47
|
+
if (config_1.config.get.logingMode())
|
|
48
|
+
(0, log_1.log)('Procedure', 'All Info', 'Procedures not found.');
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
const data = queryOutput?.data || [];
|
|
52
|
+
if (!data)
|
|
53
|
+
return null;
|
|
54
|
+
return data.map(m => ({
|
|
55
|
+
name: m.routine_name,
|
|
56
|
+
type: 'Function',
|
|
57
|
+
date: null
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Gets the output schema of the procedure in the database.
|
|
62
|
+
* @returns Promise<Record<string, string>> - The output schema of the procedure
|
|
63
|
+
*/
|
|
64
|
+
async function SimpleOutput() {
|
|
65
|
+
if (!name)
|
|
66
|
+
return {};
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Executes the procedure in the database
|
|
71
|
+
*
|
|
72
|
+
* @param reference - The reference parameters to be executed in the database
|
|
73
|
+
* @param useRecordsets - If true, returns result?.recordsets; otherwise returns result?.recordset (default: false)
|
|
74
|
+
* @returns Promise<ProcedureResult> - The result of the procedure execution
|
|
75
|
+
*/
|
|
76
|
+
async function Execute(reference = {}, useRecordsets = false) {
|
|
77
|
+
let procedureOutput = await (0, procedure_execute_1.executeProcedure)(name, reference, useRecordsets);
|
|
78
|
+
if (procedureOutput?.status !== 200) {
|
|
79
|
+
if (config_1.config.get.logingMode())
|
|
80
|
+
(0, log_1.log)('Procedure', 'Execute', `The ${name} procedure could not be executed.`);
|
|
81
|
+
return { status: 501, message: 'The procedure could not be executed.', data: [] };
|
|
82
|
+
}
|
|
83
|
+
let data = procedureOutput?.data || null;
|
|
84
|
+
if (Array.isArray(data) && data.length > 0 && useRecordsets == false) {
|
|
85
|
+
const schema = await SimpleOutput();
|
|
86
|
+
if (schema && Object.keys(schema).length > 0) {
|
|
87
|
+
data = data.map(m => {
|
|
88
|
+
const keys = Object.keys(m);
|
|
89
|
+
if (keys.length !== Object.keys(schema).length)
|
|
90
|
+
return null;
|
|
91
|
+
const new_data = {};
|
|
92
|
+
keys.forEach(key => new_data[key] = data_types_1.sqlTypes[schema[key]](m[key]));
|
|
93
|
+
return new_data;
|
|
94
|
+
}).filter(f => f !== null);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
procedureOutput.data = data;
|
|
98
|
+
return procedureOutput;
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
Execute,
|
|
102
|
+
Info,
|
|
103
|
+
AllInfo,
|
|
104
|
+
SimpleOutput
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=procedure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"procedure.js","sourceRoot":"","sources":["../../database/procedure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface QueryResult {
|
|
2
|
+
status: number;
|
|
3
|
+
message: string;
|
|
4
|
+
data: any[] | null;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Executes a raw SQL query with optional parameterized inputs.
|
|
8
|
+
*
|
|
9
|
+
* @param query - The SQL query to execute. Use @paramName for named parameters or $1, $2 for positional.
|
|
10
|
+
* @param inputs - Optional key/value map of named parameters (Record) or ordered values array
|
|
11
|
+
* @returns Promise<QueryResult>
|
|
12
|
+
*/
|
|
13
|
+
export declare const Query: (query: string, inputs?: Record<string, any> | any[]) => Promise<QueryResult>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Query = void 0;
|
|
4
|
+
const connect_to_server_1 = require("../operations/connect_to_server");
|
|
5
|
+
const config_1 = require("../operations/config");
|
|
6
|
+
const log_1 = require("../operations/log");
|
|
7
|
+
function pgTypeOf(value) {
|
|
8
|
+
if (value === null || value === undefined)
|
|
9
|
+
return 'text';
|
|
10
|
+
if (typeof value === 'number')
|
|
11
|
+
return Number.isInteger(value) ? 'integer' : 'float8';
|
|
12
|
+
if (typeof value === 'boolean')
|
|
13
|
+
return 'boolean';
|
|
14
|
+
if (value instanceof Date)
|
|
15
|
+
return 'timestamp';
|
|
16
|
+
if (Buffer.isBuffer(value))
|
|
17
|
+
return 'bytea';
|
|
18
|
+
return 'text';
|
|
19
|
+
}
|
|
20
|
+
function convertNamedToPositional(query, inputs) {
|
|
21
|
+
const paramRegex = /@(\w+)/g;
|
|
22
|
+
const params = [];
|
|
23
|
+
let match;
|
|
24
|
+
while ((match = paramRegex.exec(query)) !== null) {
|
|
25
|
+
if (!params.includes(match[1])) {
|
|
26
|
+
params.push(match[1]);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
let text = query;
|
|
30
|
+
params.forEach((param, i) => {
|
|
31
|
+
const type = pgTypeOf(inputs[param]);
|
|
32
|
+
text = text.replace(new RegExp(`@${param}\\b`, 'g'), `$${i + 1}::${type}`);
|
|
33
|
+
});
|
|
34
|
+
const values = params.map(p => inputs[p] !== undefined ? inputs[p] : null);
|
|
35
|
+
return { text, values };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Executes a raw SQL query with optional parameterized inputs.
|
|
39
|
+
*
|
|
40
|
+
* @param query - The SQL query to execute. Use @paramName for named parameters or $1, $2 for positional.
|
|
41
|
+
* @param inputs - Optional key/value map of named parameters (Record) or ordered values array
|
|
42
|
+
* @returns Promise<QueryResult>
|
|
43
|
+
*/
|
|
44
|
+
const Query = async (query, inputs) => {
|
|
45
|
+
try {
|
|
46
|
+
let text;
|
|
47
|
+
let values;
|
|
48
|
+
if (Array.isArray(inputs)) {
|
|
49
|
+
text = query;
|
|
50
|
+
values = inputs;
|
|
51
|
+
}
|
|
52
|
+
else if (inputs && typeof inputs === 'object') {
|
|
53
|
+
const converted = convertNamedToPositional(query, inputs);
|
|
54
|
+
text = converted.text;
|
|
55
|
+
values = converted.values;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
text = query;
|
|
59
|
+
values = [];
|
|
60
|
+
}
|
|
61
|
+
const pool = (0, connect_to_server_1.getPool)();
|
|
62
|
+
const client = await pool.connect();
|
|
63
|
+
try {
|
|
64
|
+
const result = await client.query(text, values);
|
|
65
|
+
return { status: 200, message: 'Success', data: result.rows || null };
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
client.release();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
if (config_1.config.get.logingMode()) {
|
|
73
|
+
(0, log_1.log)('Query', null, `${query} : ${err instanceof Error ? err.message : String(err)}`);
|
|
74
|
+
}
|
|
75
|
+
return { status: 500, message: String(err), data: null };
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
exports.Query = Query;
|
|
79
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../database/query.ts"],"names":[],"mappings":"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"}
|