Skip to content

Commit dd2a96b

Browse files
PuddySqlEngine added.
1 parent c4966e5 commit dd2a96b

File tree

3 files changed

+149
-117
lines changed

3 files changed

+149
-117
lines changed

src/SqlEngine.mjs

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
class PuddySqlEngine {
2+
/** @type {string} */
3+
#sqlEngine = '';
4+
5+
/**
6+
* Checks whether the SQL engine identifier is empty.
7+
*
8+
* Returns `true` if the SQL engine is either `null`, `undefined`, or an empty string.
9+
*
10+
* @returns {boolean} Whether the SQL engine is unset or empty.
11+
*/
12+
isSqlEngineEmpty() {
13+
return typeof this.#sqlEngine !== 'string' || this.#sqlEngine.trim() === '';
14+
}
15+
16+
/**
17+
* Returns the current SQL engine identifier used by this instance.
18+
*
19+
* Throws an error if the engine has not been defined.
20+
*
21+
* @returns {string} The name of the current SQL engine.
22+
* @throws {Error} If the SQL engine is not defined.
23+
*/
24+
getSqlEngine() {
25+
if (typeof this.#sqlEngine !== 'string' || this.#sqlEngine.trim() === '')
26+
throw new Error('SQL engine is not defined.');
27+
return this.#sqlEngine;
28+
}
29+
30+
/**
31+
* Sets the SQL engine identifier for this instance.
32+
*
33+
* This can only be set once, and only with a valid string.
34+
* Subsequent attempts or invalid types will throw an error.
35+
*
36+
* @param {string} engine - The SQL engine name to set (e.g., 'sqlite3' or 'postgre').
37+
* @throws {Error} If the SQL engine is already set or if the input is not a string.
38+
*/
39+
setSqlEngine(engine) {
40+
if (typeof this.#sqlEngine === 'string' && this.#sqlEngine.length > 0)
41+
throw new Error('SQL engine has already been set and cannot be changed.');
42+
if (typeof engine !== 'string' || engine.trim() === '')
43+
throw new Error('Invalid SQL engine: only non-empty strings are allowed.');
44+
45+
this.#sqlEngine = engine;
46+
}
47+
48+
/**
49+
* Checks if the given error message indicates a connection error based on the SQL engine in use.
50+
*
51+
* This method evaluates if the provided error message contains any known connection error codes
52+
* for the current SQL engine (PostgreSQL or SQLite3).
53+
*
54+
* @param {Error} err - The error message to check.
55+
* @returns {boolean} True if the error message matches any known connection error codes; otherwise, false.
56+
*/
57+
isConnectionError(err) {
58+
if (typeof err !== 'object' || err === null || Array.isArray(err))
59+
throw new Error('err must be a plain object');
60+
const sqlEngine = this.getSqlEngine();
61+
if (typeof sqlEngine === 'string') {
62+
// PostgreSQL
63+
if (sqlEngine === 'postgre') {
64+
const codes = [
65+
'ECONNREFUSED',
66+
'ENOTFOUND',
67+
'EHOSTUNREACH',
68+
'ETIMEDOUT',
69+
'EPIPE',
70+
'28P01',
71+
'3D000',
72+
'08006',
73+
'08001',
74+
'08004',
75+
'53300',
76+
'57P01',
77+
];
78+
// @ts-ignore
79+
for (const code of codes) if (err.code === code) return true;
80+
}
81+
82+
// Sqlite3
83+
if (sqlEngine === 'sqlite3' && typeof err.message === 'string')
84+
return err.message.includes('SQLITE_CANTOPEN');
85+
}
86+
return false;
87+
}
88+
89+
/**
90+
* Executes a query to get all rows from a database table.
91+
* @function
92+
* @async
93+
* @param {string} query - The SQL query to execute.
94+
* @param {any[*]} [params] - The parameters to bind to the query.
95+
* @param {string} [debugName] - Optional label or context name for the debug log.
96+
* @returns {Promise<any[*]>} A promise that resolves to an array of rows.
97+
* @throws {Error} Throws an error if the query fails.
98+
*/
99+
all = (query, params, debugName = '') => new Promise((resolve) => resolve(null));
100+
101+
/**
102+
* Executes a query to get a single row from a database table.
103+
* @function
104+
* @async
105+
* @param {string} query - The SQL query to execute.
106+
* @param {any[*]} [params] - The parameters to bind to the query.
107+
* @param {string} [debugName] - Optional label or context name for the debug log.
108+
* @returns {Promise<Record<any, any>|null>} A promise that resolves to a single row object.
109+
* @throws {Error} Throws an error if the query fails.
110+
*/
111+
get = (query, params, debugName = '') => new Promise((resolve) => resolve(null));
112+
113+
/**
114+
* Executes an SQL statement to modify the database (e.g., INSERT, UPDATE).
115+
* @function
116+
* @async
117+
* @param {string} query - The SQL query to execute.
118+
* @param {any[*]} params - The parameters to bind to the query.
119+
* @param {string} [debugName] - Optional label or context name for the debug log.
120+
* @returns {Promise<Record<any, any>|null>} A promise that resolves to the result of the query execution.
121+
* @throws {Error} Throws an error if the query fails.
122+
*/
123+
run = (query, params, debugName = '') => new Promise((resolve) => resolve(null));
124+
}
125+
126+
export default PuddySqlEngine;

src/TinySQL.mjs

Lines changed: 14 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { EventEmitter } from 'events';
33
import { isJsonObject } from 'tiny-essentials';
44

55
import { pg, sqlite3 } from './Modules.mjs';
6+
import PuddySqlEngine from './SqlEngine.mjs';
67
import PuddySqlQuery from './TinySqlQuery.mjs';
78

89
/** @typedef {import('pg').Pool} PgPool */
@@ -12,11 +13,12 @@ import PuddySqlQuery from './TinySqlQuery.mjs';
1213
* PuddySql is a wrapper for basic SQL operations on a local storage abstraction.
1314
* It supports inserting, updating, deleting, querying and joining JSON-based structured data.
1415
*/
15-
class PuddySqlInstance {
16-
/** @typedef {import('./TinySqlQuery.mjs').TableSettings} TableSettings */
16+
class PuddySqlInstance extends PuddySqlEngine {
17+
constructor() {
18+
super();
19+
}
1720

18-
/** @type {string} */
19-
#sqlEngine = '';
21+
/** @typedef {import('./TinySqlQuery.mjs').TableSettings} TableSettings */
2022

2123
// @ts-ignore
2224
#db;
@@ -333,47 +335,6 @@ class PuddySqlInstance {
333335
return this.#events.rawListeners(eventName);
334336
}
335337

336-
/**
337-
* Checks if the given error message indicates a connection error based on the SQL engine in use.
338-
*
339-
* This method evaluates if the provided error message contains any known connection error codes
340-
* for the current SQL engine (PostgreSQL or SQLite3).
341-
*
342-
* @param {Error} err - The error message to check.
343-
* @returns {boolean} True if the error message matches any known connection error codes; otherwise, false.
344-
*/
345-
isConnectionError(err) {
346-
if (typeof err !== 'object' || err === null || Array.isArray(err))
347-
throw new Error('err must be a plain object');
348-
const sqlEngine = this.getSqlEngine();
349-
if (typeof sqlEngine === 'string') {
350-
// PostgreSQL
351-
if (sqlEngine === 'postgre') {
352-
const codes = [
353-
'ECONNREFUSED',
354-
'ENOTFOUND',
355-
'EHOSTUNREACH',
356-
'ETIMEDOUT',
357-
'EPIPE',
358-
'28P01',
359-
'3D000',
360-
'08006',
361-
'08001',
362-
'08004',
363-
'53300',
364-
'57P01',
365-
];
366-
// @ts-ignore
367-
for (const code of codes) if (err.code === code) return true;
368-
}
369-
370-
// Sqlite3
371-
if (sqlEngine === 'sqlite3' && typeof err.message === 'string')
372-
return err.message.includes('SQLITE_CANTOPEN');
373-
}
374-
return false;
375-
}
376-
377338
/**
378339
* Formats a debug message string with colored ANSI tags for the console.
379340
* Useful for consistent and readable debug logging with identifiers.
@@ -569,20 +530,6 @@ class PuddySqlInstance {
569530
}
570531
}
571532

572-
/**
573-
* Returns the current SQL engine identifier used by this instance.
574-
*
575-
* Possible return values:
576-
* - `'sqlite3'` if using SQLite3
577-
* - `'postgre'` if using PostgreSQL
578-
* - `null` if no engine has been initialized yet
579-
*
580-
* @returns {string} The name of the current SQL engine or `null` if none is set.
581-
*/
582-
getSqlEngine() {
583-
return this.#sqlEngine;
584-
}
585-
586533
/**
587534
* Initializes an SQLite3 >= 3.35.0 database connection and sets up the SQL engine for this instance.
588535
*
@@ -595,7 +542,7 @@ class PuddySqlInstance {
595542
* @throws {Error} If a SQL engine has already been initialized for this instance.
596543
*/
597544
async initSqlite3(filePath = ':memory:') {
598-
if (!this.#sqlEngine) {
545+
if (this.isSqlEngineEmpty()) {
599546
/** @type {SqliteDb} */
600547
this.#db = await open({
601548
filename: filePath,
@@ -625,8 +572,8 @@ class PuddySqlInstance {
625572
setSqlite3(db) {
626573
if (!(db instanceof sqlite3.Database))
627574
throw new Error('Invalid type for db. Expected a Sqlite3.');
628-
if (!this.#sqlEngine) {
629-
this.#sqlEngine = 'sqlite3';
575+
if (this.isSqlEngineEmpty()) {
576+
this.setSqlEngine('sqlite3');
630577

631578
/**
632579
* Checks if the given error is a connection error.
@@ -763,7 +710,7 @@ class PuddySqlInstance {
763710
* @throws {Error} If a SQL engine is already initialized for this instance.
764711
*/
765712
async initPostgre(config) {
766-
if (!this.#sqlEngine) {
713+
if (this.isSqlEngineEmpty()) {
767714
/** @type {PgPool} */
768715
this.#db = new pg.Pool(config);
769716

@@ -791,8 +738,8 @@ class PuddySqlInstance {
791738
*/
792739
setPostgre(db) {
793740
if (!(db instanceof pg.Pool)) throw new Error('Invalid type for db. Expected a PostgreSQL.');
794-
if (!this.#sqlEngine) {
795-
this.#sqlEngine = 'postgre';
741+
if (!this.getSqlEngine()) {
742+
this.setSqlEngine('postgre');
796743

797744
/**
798745
* Checks if the given error is a connection error.
@@ -920,45 +867,6 @@ class PuddySqlInstance {
920867
}
921868
}
922869

923-
/**
924-
* Executes a query to get all rows from a database table.
925-
* @function
926-
* @async
927-
* @param {string} query - The SQL query to execute.
928-
* @param {any[*]} [params] - The parameters to bind to the query.
929-
* @param {string} [debugName] - Optional label or context name for the debug log.
930-
* @returns {Promise<any[*]>} A promise that resolves to an array of rows.
931-
* @throws {Error} Throws an error if the query fails.
932-
*/
933-
// @ts-ignore
934-
all = (query, params, debugName = '') => new Promise((resolve) => resolve(null));
935-
936-
/**
937-
* Executes a query to get a single row from a database table.
938-
* @function
939-
* @async
940-
* @param {string} query - The SQL query to execute.
941-
* @param {any[*]} [params] - The parameters to bind to the query.
942-
* @param {string} [debugName] - Optional label or context name for the debug log.
943-
* @returns {Promise<Record<any, any>|null>} A promise that resolves to a single row object.
944-
* @throws {Error} Throws an error if the query fails.
945-
*/
946-
// @ts-ignore
947-
get = (query, params, debugName = '') => new Promise((resolve) => resolve(null));
948-
949-
/**
950-
* Executes an SQL statement to modify the database (e.g., INSERT, UPDATE).
951-
* @function
952-
* @async
953-
* @param {string} query - The SQL query to execute.
954-
* @param {any[*]} params - The parameters to bind to the query.
955-
* @param {string} [debugName] - Optional label or context name for the debug log.
956-
* @returns {Promise<Record<any, any>|null>} A promise that resolves to the result of the query execution.
957-
* @throws {Error} Throws an error if the query fails.
958-
*/
959-
// @ts-ignore
960-
run = (query, params, debugName = '') => new Promise((resolve) => resolve(null));
961-
962870
/**
963871
* Gracefully destroys the current instance by:
964872
* - Removing all internal and system event listeners;
@@ -974,10 +882,8 @@ class PuddySqlInstance {
974882
this.#sysEvents.removeAllListeners();
975883

976884
const sqlEngine = this.getSqlEngine();
977-
if (typeof sqlEngine === 'string') {
978-
if (sqlEngine === 'postgre') await this.#db.end().catch(console.error);
979-
if (sqlEngine === 'sqlite3') await this.#db.close().catch(console.error);
980-
}
885+
if (sqlEngine === 'postgre') await this.#db.end().catch(console.error);
886+
if (sqlEngine === 'sqlite3') await this.#db.close().catch(console.error);
981887
}
982888
}
983889

src/TinySqlQuery.mjs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { isJsonObject } from 'tiny-essentials';
22
import { pg } from './Modules.mjs';
3-
import PuddySqlInstance from './TinySQL.mjs';
3+
import PuddySqlEngine from './SqlEngine.mjs';
44
import PuddySqlTags from './TinySqlTags.mjs';
55

66
/**
@@ -123,7 +123,7 @@ class PuddySqlQuery {
123123
/** @type {Record<string, function(string) : string>} */
124124
#customValFunc = {};
125125

126-
/** @type {PuddySqlInstance|null} */
126+
/** @type {PuddySqlEngine|null} */
127127
#db = null;
128128

129129
/**
@@ -153,17 +153,17 @@ class PuddySqlQuery {
153153
/**
154154
* Safely retrieves the internal database instance.
155155
*
156-
* This method ensures that the current internal `#db` is a valid instance of `PuddySqlInstance`.
156+
* This method ensures that the current internal `#db` is a valid instance of `PuddySqlEngine`.
157157
* If the internal value is invalid or was not properly initialized, an error is thrown.
158158
*
159-
* @returns {PuddySqlInstance} The internal database instance.
160-
* @throws {Error} If the internal database is not a valid `PuddySqlInstance`.
159+
* @returns {PuddySqlEngine} The internal database instance.
160+
* @throws {Error} If the internal database is not a valid `PuddySqlEngine`.
161161
*/
162162
getDb() {
163163
// @ts-ignore
164-
if (this.#db !== null || !(this.#db instanceof PuddySqlInstance)) {
164+
if (this.#db !== null || !(this.#db instanceof PuddySqlEngine)) {
165165
throw new Error(
166-
'Database instance is invalid or uninitialized. Expected an instance of PuddySqlInstance.',
166+
'Database instance is invalid or uninitialized. Expected an instance of PuddySqlEngine.',
167167
);
168168
}
169169
return this.#db;
@@ -1016,11 +1016,11 @@ class PuddySqlQuery {
10161016
* This function ensures safe fallback values and formats the SELECT clause.
10171017
*
10181018
* @param {TableSettings} [settings={}] - Partial configuration to apply. Will be merged with current settings.
1019-
* @param {PuddySqlInstance} [db] - PuddySql Instance.
1019+
* @param {PuddySqlEngine} [db] - PuddySql Instance.
10201020
*/
10211021
setDb(settings = {}, db) {
10221022
if (!isJsonObject(settings)) throw new Error('Settings must be a plain object.');
1023-
if (!(db instanceof PuddySqlInstance))
1023+
if (!(db instanceof PuddySqlEngine))
10241024
throw new Error('Invalid type for db. Expected a PuddySql.');
10251025
this.#db = db;
10261026

0 commit comments

Comments
 (0)