meadow-connection-sqlite 1.0.10

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.
@@ -0,0 +1,24 @@
1
+ {
2
+ "Generated": "2026-02-15T22:10:52.774Z",
3
+ "GitHubOrg": "stevenvelozo",
4
+ "DefaultBranch": "master",
5
+ "Groups": [
6
+ {
7
+ "Name": "Dist",
8
+ "Key": "dist",
9
+ "Description": "",
10
+ "Modules": [
11
+ {
12
+ "Name": "indoctrinate_content_staging",
13
+ "Repo": "indoctrinate_content_staging",
14
+ "Group": "dist",
15
+ "Branch": "master",
16
+ "HasDocs": false,
17
+ "HasCover": false,
18
+ "Sidebar": [],
19
+ "DocFiles": []
20
+ }
21
+ ]
22
+ }
23
+ ]
24
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "Generated": "2026-02-15T22:10:52.851Z",
3
+ "DocumentCount": 0,
4
+ "LunrIndex": {
5
+ "version": "2.3.9",
6
+ "fields": [
7
+ "title",
8
+ "module",
9
+ "group",
10
+ "body"
11
+ ],
12
+ "fieldVectors": [],
13
+ "invertedIndex": [],
14
+ "pipeline": [
15
+ "stemmer"
16
+ ]
17
+ },
18
+ "Documents": {}
19
+ }
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "meadow-connection-sqlite",
3
+ "version": "1.0.10",
4
+ "description": "Meadow SQLite Plugin",
5
+ "main": "source/Meadow-Connection-SQLite.js",
6
+ "scripts": {
7
+ "start": "node source/Meadow-Connection-SQLite.js",
8
+ "build": "npx quack build",
9
+ "test": "npx mocha -u tdd -R spec",
10
+ "tests": "npx mocha -u tdd --exit -R spec --grep",
11
+ "coverage": "npx nyc --reporter=lcov --reporter=text-lcov npx mocha -- -u tdd -R spec"
12
+ },
13
+ "mocha": {
14
+ "diff": true,
15
+ "extension": [
16
+ "js"
17
+ ],
18
+ "package": "./package.json",
19
+ "reporter": "spec",
20
+ "slow": "75",
21
+ "timeout": "5000",
22
+ "ui": "tdd",
23
+ "watch-files": [
24
+ "source/**/*.js",
25
+ "test/**/*.js"
26
+ ],
27
+ "watch-ignore": [
28
+ "lib/vendor"
29
+ ]
30
+ },
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/stevenvelozo/meadow-connection-sqlite.git"
34
+ },
35
+ "keywords": [
36
+ "cache"
37
+ ],
38
+ "author": "Steven Velozo <steven@velozo.com> (http://velozo.com/)",
39
+ "license": "MIT",
40
+ "bugs": {
41
+ "url": "https://github.com/stevenvelozo/meadow-connection-sqlite/issues"
42
+ },
43
+ "homepage": "https://github.com/stevenvelozo/meadow-connection-sqlite",
44
+ "devDependencies": {
45
+ "quackage": "^1.0.48",
46
+ "retold-harness": "^1.0.6"
47
+ },
48
+ "dependencies": {
49
+ "better-sqlite3": "^12.3.0",
50
+ "fable-serviceproviderbase": "^3.0.16"
51
+ }
52
+ }
@@ -0,0 +1,246 @@
1
+ /**
2
+ * Meadow SQLite Provider Fable Service
3
+ * @author Steven Velozo <steven@velozo.com>
4
+ */
5
+ const libFableServiceProviderBase = require('fable-serviceproviderbase');
6
+
7
+ const libSQLite = require('better-sqlite3');
8
+
9
+ /*
10
+ Das alt muster:
11
+
12
+ {
13
+ "SQLiteFilePath": "./Meadow-SQLite-Database.sqlite"
14
+ }
15
+ */
16
+
17
+ class MeadowConnectionSQLite extends libFableServiceProviderBase
18
+ {
19
+ constructor(pFable, pManifest, pServiceHash)
20
+ {
21
+ super(pFable, pManifest, pServiceHash);
22
+
23
+ this.serviceType = 'MeadowConnectionSQLite';
24
+
25
+ this.connected = false;
26
+ this._database = false;
27
+
28
+ if (this.fable.settings.hasOwnProperty('SQLite'))
29
+ {
30
+ if (this.fable.settings.SQLite.hasOwnProperty('SQLiteFilePath'))
31
+ {
32
+ this.options.SQLiteFilePath = this.fable.settings.SQLite.SQLiteFilePath;
33
+ }
34
+ }
35
+ }
36
+
37
+ generateDropTableStatement(pTableName)
38
+ {
39
+ let tmpDropTableStatement = `IF OBJECT_ID('dbo.[${pTableName}]', 'U') IS NOT NULL\n`;
40
+ tmpDropTableStatement += ` DROP TABLE dbo.[${pTableName}];\n`;
41
+ tmpDropTableStatement += `GO`;
42
+ return tmpDropTableStatement;
43
+ }
44
+
45
+ generateCreateTableStatement(pMeadowTableSchema)
46
+ {
47
+ this.log.info(`--> Building the table create string for ${pMeadowTableSchema} ...`);
48
+
49
+ let tmpPrimaryKey = false;
50
+ let tmpCreateTableStatement = `-- [ ${pMeadowTableSchema.TableName} ]`;
51
+ tmpCreateTableStatement += `\nCREATE TABLE [dbo].[${pMeadowTableSchema.TableName}]\n (`;
52
+ for (let j = 0; j < pMeadowTableSchema.Columns.length; j++)
53
+ {
54
+ let tmpColumn = pMeadowTableSchema.Columns[j];
55
+
56
+ // If we aren't the first column, append a comma.
57
+ if (j > 0)
58
+ {
59
+ tmpCreateTableStatement += `,`;
60
+ }
61
+
62
+ tmpCreateTableStatement += `\n`;
63
+ // Dump out each column......
64
+ switch (tmpColumn.DataType)
65
+ {
66
+ case 'ID':
67
+ // if (this.options.AllowIdentityInsert)
68
+ // {
69
+ // tmpCreateTableStatement += ` [${tmpColumn.Column}] INT NOT NULL PRIMARY KEY`;
70
+ // }
71
+ // else
72
+ // {
73
+ // There is debate on whether IDENTITY(1,1) is better or not.
74
+ tmpCreateTableStatement += ` [${tmpColumn.Column}] INT NOT NULL IDENTITY PRIMARY KEY`;
75
+ //}
76
+ tmpPrimaryKey = tmpColumn.Column;
77
+ break;
78
+ case 'GUID':
79
+ tmpCreateTableStatement += ` [${tmpColumn.Column}] VARCHAR(254) DEFAULT '00000000-0000-0000-0000-000000000000'`;
80
+ break;
81
+ case 'ForeignKey':
82
+ tmpCreateTableStatement += ` [${tmpColumn.Column}] INT UNSIGNED NOT NULL DEFAULT 0`;
83
+ tmpPrimaryKey = tmpColumn.Column;
84
+ break;
85
+ case 'Numeric':
86
+ tmpCreateTableStatement += ` [${tmpColumn.Column}] INT NOT NULL DEFAULT 0`;
87
+ break;
88
+ case 'Decimal':
89
+ tmpCreateTableStatement += ` [${tmpColumn.Column}] DECIMAL(${tmpColumn.Size})`;
90
+ break;
91
+ case 'String':
92
+ tmpCreateTableStatement += ` [${tmpColumn.Column}] VARCHAR(${tmpColumn.Size}) DEFAULT ''`;
93
+ break;
94
+ case 'Text':
95
+ tmpCreateTableStatement += ` [${tmpColumn.Column}] TEXT`;
96
+ break;
97
+ case 'DateTime':
98
+ tmpCreateTableStatement += ` [${tmpColumn.Column}] DATETIME`;
99
+ break;
100
+ case 'Boolean':
101
+ tmpCreateTableStatement += ` [${tmpColumn.Column}] TINYINT DEFAULT 0`;
102
+ break;
103
+ default:
104
+ break;
105
+ }
106
+ }
107
+ if (tmpPrimaryKey)
108
+ {
109
+ // tmpCreateTableStatement += `,\n\n PRIMARY KEY (${tmpPrimaryKey$})`;
110
+ }
111
+ tmpCreateTableStatement += `\n );`;
112
+
113
+ this.log.info(`Generated Create Table Statement: ${tmpCreateTableStatement}`);
114
+
115
+ return tmpCreateTableStatement;
116
+ }
117
+
118
+ createTables(pMeadowSchema, fCallback)
119
+ {
120
+ this.fable.Utility.eachLimit(pMeadowSchema.Tables, 1,
121
+ (pTable, fCreateComplete) =>
122
+ {
123
+ return this.createTable(pTable, fCreateComplete)
124
+ },
125
+ (pCreateError) =>
126
+ {
127
+ if (pCreateError)
128
+ {
129
+ this.log.error(`Meadow-SQLite Error creating tables from Schema: ${pCreateError}`,pCreateError);
130
+ }
131
+ this.log.info('Done creating tables!');
132
+ return fCallback(pCreateError);
133
+ });
134
+ }
135
+
136
+ createTable(pMeadowTableSchema, fCallback)
137
+ {
138
+ let tmpCreateTableStatement = this.generateCreateTableStatement(pMeadowTableSchema);
139
+ this._ConnectionPool.query(tmpCreateTableStatement)
140
+ .then((pResult) =>
141
+ {
142
+ this.log.info(`Meadow-SQLite CREATE TABLE ${pMeadowTableSchema.TableName} Success`);
143
+ this.log.warn(`Meadow-SQLite Create Table Statement: ${tmpCreateTableStatement}`)
144
+ return fCallback();
145
+ })
146
+ .catch((pError) =>
147
+ {
148
+ if (pError.hasOwnProperty('originalError')
149
+ // TODO: This check may be extraneous; not familiar enough with the sqlite node driver yet
150
+ && (pError.originalError.hasOwnProperty('info'))
151
+ // TODO: Validate that there isn't a better way to find this (pError.code isn't explicit enough)
152
+ && (pError.originalError.info.message.indexOf("There is already an object named") == 0)
153
+ && (pError.originalError.info.message.indexOf('in the database.') > 0))
154
+ {
155
+ // The table already existed; log a warning but keep on keeping on.
156
+ //this.log.warn(`Meadow-SQLite CREATE TABLE ${pMeadowTableSchema.TableName} executed but table already existed.`);
157
+ //this.log.warn(`Meadow-SQLite Create Table Statement: ${tmpCreateTableStatement}`)
158
+ return fCallback();
159
+ }
160
+ else
161
+ {
162
+ this.log.error(`Meadow-SQLite CREATE TABLE ${pMeadowTableSchema.TableName} failed!`, pError);
163
+ //this.log.warn(`Meadow-SQLite Create Table Statement: ${tmpCreateTableStatement}`)
164
+ return fCallback(pError);
165
+ }
166
+ });
167
+ }
168
+
169
+ connect()
170
+ {
171
+ this.connectAsync();
172
+ }
173
+
174
+ connectAsync(fCallback)
175
+ {
176
+ let tmpCallback = fCallback;
177
+ if (typeof (tmpCallback) !== 'function')
178
+ {
179
+ this.log.error(`Meadow SQLite connect() called without a callback; this could lead to connection race conditions.`);
180
+ tmpCallback = () => { };
181
+ }
182
+
183
+ let tmpConnectionSettings = this.options;
184
+
185
+ if (!tmpConnectionSettings.SQLiteFilePath)
186
+ {
187
+ let tmpCleansedLogSettings = JSON.parse(JSON.stringify(tmpConnectionSettings));
188
+ // No leaking passwords!
189
+ tmpCleansedLogSettings.password = '*****************';
190
+ this.log.error(`Meadow-Connection-SQLite trying to connect to SQLite but the database file path is invalid; SQLiteFilePath must be in either the fable.settings.SQLite object or the connection provider constructor options.`, tmpCleansedLogSettings);
191
+ return tmpCallback(new Error(`Meadow-Connection-SQLite trying to connect to SQLite but the database file path is invalid.`));
192
+ }
193
+
194
+ if (this.connected)
195
+ {
196
+ let tmpCleansedLogSettings = JSON.parse(JSON.stringify(tmpConnectionSettings));
197
+ // No leaking passwords!
198
+ tmpCleansedLogSettings.password = '*****************';
199
+ this.log.error(`Meadow-Connection-SQLite trying to connect to SQLite but is already connected - skipping the second connect call.`, tmpCleansedLogSettings);
200
+ return tmpCallback(null, this._database);
201
+ }
202
+ else
203
+ {
204
+ try
205
+ {
206
+ this.log.info(`Meadow-Connection-SQLite connecting to file [${tmpConnectionSettings.SQLiteFilePath}].`);
207
+ this._database = new libSQLite(tmpConnectionSettings.SQLiteFilePath, tmpConnectionSettings);
208
+ // According to the documentation, setting this journal mode is very important for performance.
209
+ // > Though not required, [it is generally important to set the WAL pragma for performance reasons](https://github.com/WiseLibs/better-sqlite3/blob/master/docs/performance.md).
210
+ this._database.pragma('journal_mode = WAL');
211
+ this.log.info(`Meadow-Connection-SQLite successfully connected to SQLite file [${tmpConnectionSettings.SQLiteFilePath}].`);
212
+ this.connected = true;
213
+ return tmpCallback(null, this._database);
214
+ }
215
+ catch (pError)
216
+ {
217
+ this.log.error(`Meadow-Connection-SQLite error connecting to SQLite file [${tmpConnectionSettings.SQLiteFilePath}]: ${pError}`);
218
+ return tmpCallback(pError);
219
+ };
220
+ }
221
+ }
222
+
223
+ get preparedStatement()
224
+ {
225
+ if (this.connected && this._ConnectionPool)
226
+ {
227
+ return new libSQLite.PreparedStatement(this._ConnectionPool);
228
+ }
229
+ else
230
+ {
231
+ throw new Error('The Meadow Microsoft SQL provider could not create a prepared statement; disconnected or no valid connection pool.');
232
+ }
233
+ }
234
+
235
+ get SQLite()
236
+ {
237
+ return libSQLite;
238
+ }
239
+
240
+ get db()
241
+ {
242
+ return this._database;
243
+ }
244
+ }
245
+
246
+ module.exports = MeadowConnectionSQLite;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * @license MIT
3
+ * @author Steven Velozo <steven@velozo.com>
4
+ */
5
+
6
+ const Chai = require('chai');
7
+ const Expect = Chai.expect;
8
+ const Assert = Chai.assert;
9
+ const libFS = require('fs');
10
+
11
+ const libFable = require('fable');
12
+ const libMeadowConnectionSQLite = require('../source/Meadow-Connection-SQLite.js');
13
+
14
+ const _FableConfig = (
15
+ {
16
+ "Product": "MeadowSQLiteTestBookstore",
17
+ "ProductVersion": "1.0.0",
18
+
19
+ "UUID":
20
+ {
21
+ "DataCenter": 0,
22
+ "Worker": 0
23
+ },
24
+ "LogStreams":
25
+ [
26
+ {
27
+ "streamtype": "console"
28
+ }
29
+ ],
30
+
31
+ "SQLite":
32
+ {
33
+ "SQLiteFilePath": "./dist/FableTest.db"
34
+ }
35
+ });
36
+
37
+ suite
38
+ (
39
+ 'Connection',
40
+ ()=>
41
+ {
42
+ setup(
43
+ (fDone) =>
44
+ {
45
+ if (libFS.existsSync('./dist/FableTest.db'))
46
+ {
47
+ libFS.unlinkSync('./dist/FableTest.db');
48
+ }
49
+
50
+ let _Fable = new libFable(_FableConfig);
51
+ _Fable.serviceManager.addServiceType('MeadowSQLiteProvider', libMeadowConnectionSQLite);
52
+ _Fable.serviceManager.instantiateServiceProvider('MeadowSQLiteProvider');
53
+ return fDone();
54
+ });
55
+
56
+ suite
57
+ (
58
+ 'Connect to SQLite',
59
+ ()=>
60
+ {
61
+ test
62
+ (
63
+ 'use default settings from fable.settings',
64
+ (fDone) =>
65
+ {
66
+ let _Fable = new libFable(_FableConfig);
67
+ _Fable.serviceManager.addServiceType('MeadowSQLiteProvider', libMeadowConnectionSQLite);
68
+ _Fable.serviceManager.instantiateServiceProvider('MeadowSQLiteProvider');
69
+
70
+ Expect(_Fable.MeadowSQLiteProvider).to.be.an('object');
71
+
72
+ _Fable.MeadowSQLiteProvider.connectAsync(
73
+ (pError) =>
74
+ {
75
+ if (pError)
76
+ {
77
+ return fDone(pError);
78
+ }
79
+ let tmpRows = _Fable.MeadowSQLiteProvider.db.prepare(`SELECT * FROM FableTest`).get();
80
+ Expect(tmpRows).to.be.an('array');
81
+ return fDone();
82
+ }
83
+ );
84
+ }
85
+ );
86
+ }
87
+ );
88
+ }
89
+ );