pict-serviceproviderbase 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Steven Velozo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # Pict Service Provider
2
+
3
+ A very basic set of base classes to provide the interface for Pict services.
4
+ This is used for instantiating connections to databases, extending core
5
+ services and whatever other services.
6
+
7
+ Some service types Pict provides out of the box:
8
+
9
+ * settings
10
+ * logging
11
+ * uuid
12
+ * templating
13
+ * providers
14
+ * application state
15
+ * views
16
+
17
+
18
+ ## Basic Services
19
+
20
+ There are two types of services -- just requiring the class provides a base
21
+ class for most services. The constructor for this type takes in a fully
22
+ initialized pict object.
23
+
24
+ ```
25
+ const libPictServiceProviderBase = require('pict-serviceproviderbase');
26
+
27
+ class SimpleService extends libPictServiceProviderBase
28
+ {
29
+ constructor(pPict, pOptions, pServiceHash)
30
+ {
31
+ super(pPict, pOptions, pServiceHash);
32
+
33
+ this.serviceType = 'SimpleService';
34
+ }
35
+
36
+ doSomething()
37
+ {
38
+ this.pict.log.info(`SimpleService ${this.UUID}::${this.Hash} is doing something.`);
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## Core Pre-initialization Services
44
+
45
+ For some service types, we want to instantiate behaviors before the pict
46
+ class has been initialized. These use a special service base that defers
47
+ the connection of an initialized pict object until after it's created.
48
+
49
+ The one caveat here is the pict service doesn't provide consistent settings,
50
+ log or uuid functionality until they have been initialized and mapped in.
51
+
52
+ If you want to use this base class, please refer to the pict service
53
+ manager code as well to get a good understanding of how initialization
54
+ differs from the basic services.
55
+
56
+
57
+ ```
58
+ const libPictServiceProviderBase = require('pict-serviceproviderbase');
59
+
60
+ class SimpleService extends libPictServiceProviderBase
61
+ {
62
+ constructor(pPict, pOptions, pServiceHash)
63
+ {
64
+ super(pPict, pOptions, pServiceHash);
65
+
66
+ this.serviceType = 'SimpleService';
67
+ }
68
+
69
+ doSomething()
70
+ {
71
+ this.pict.log.info(`SimpleService ${this.UUID}::${this.Hash} is doing something.`);
72
+ }
73
+ }
74
+ ```
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "pict-serviceproviderbase",
3
+ "version": "1.0.0",
4
+ "description": "Simple base classes for pict services.",
5
+ "main": "source/Pict-ServiceProviderBase.js",
6
+ "scripts": {
7
+ "start": "node source/Pict-ServiceProviderBase.js",
8
+ "test": "npx mocha -u tdd -R spec",
9
+ "tests": "npx mocha -u tdd --exit -R spec --grep",
10
+ "coverage": "npx nyc --reporter=lcov --reporter=text-lcov npx mocha -- -u tdd -R spec",
11
+ "build": "npx quack build"
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/pict-serviceproviderbase.git"
34
+ },
35
+ "keywords": [],
36
+ "author": "Steven Velozo <steven@velozo.com> (http://velozo.com/)",
37
+ "license": "MIT",
38
+ "bugs": {
39
+ "url": "https://github.com/stevenvelozo/pict-serviceproviderbase/issues"
40
+ },
41
+ "homepage": "https://github.com/stevenvelozo/pict-serviceproviderbase",
42
+ "devDependencies": {
43
+ "quackage": "^1.0.45"
44
+ },
45
+ "dependencies": {
46
+ "fable-serviceproviderbase": "^3.0.15",
47
+ "pict": "^1.0.343"
48
+ }
49
+ }
@@ -0,0 +1,31 @@
1
+ const libPackage = require('../package.json');
2
+ const libFableServiceProviderBase = require('fable-serviceproviderbase');
3
+
4
+ class PictServiceProviderBase extends libFableServiceProviderBase
5
+ {
6
+ // The constructor can be used in two ways:
7
+ // 1) With a fable, options object and service hash (the options object and service hash are optional)
8
+ // 2) With an object or nothing as the first parameter, where it will be treated as the options object
9
+ constructor(pFable, pOptions, pServiceHash)
10
+ {
11
+ super(pFable, pOptions, pServiceHash);
12
+
13
+ /** @type {Object} */
14
+ this._PackagePictServiceProvider = libPackage;
15
+ }
16
+
17
+ connectFable(pFable)
18
+ {
19
+ super.connectFable(pFable);
20
+
21
+ if (!this.pict)
22
+ {
23
+ this.pict = pFable;
24
+ }
25
+ return true;
26
+ }
27
+ }
28
+
29
+ module.exports = PictServiceProviderBase;
30
+ // This is left here in case we want to go back to having different code/base class for "core" services
31
+ module.exports.CoreServiceProviderBase = PictServiceProviderBase;
@@ -0,0 +1,302 @@
1
+ /**
2
+ * Unit tests for Pict Service Provider Base
3
+ *
4
+ * @license MIT
5
+ *
6
+ * @author Steven Velozo <steven@velozo.com>
7
+ */
8
+
9
+ const libPict = require('pict');
10
+ const libPictServiceProviderBase = require('../source/Pict-ServiceProviderBase.js');
11
+
12
+ const Chai = require("chai");
13
+ const Expect = Chai.expect;
14
+
15
+ class SimpleService extends libPictServiceProviderBase
16
+ {
17
+ constructor(pPict, pOptions, pServiceHash)
18
+ {
19
+ super(pPict, pOptions, pServiceHash);
20
+
21
+ this.serviceType = 'SimpleService';
22
+ }
23
+
24
+ doSomething()
25
+ {
26
+ // Exercise something that is only in pict and not fable as well
27
+ this.pict.log.trace(`There are ${Object.keys(this.pict.providers).length} service providers registered in pict.`);
28
+ this.pict.log.info(`SimpleService ${this.UUID}::${this.Hash} is doing something.`);
29
+ }
30
+ }
31
+
32
+ class MockDatabaseService extends libPictServiceProviderBase
33
+ {
34
+ constructor(pPict, pOptions, pServiceHash)
35
+ {
36
+ super(pPict, pOptions, pServiceHash);
37
+
38
+ this.serviceType = 'MockDatabaseService';
39
+ }
40
+
41
+ connect()
42
+ {
43
+ this.pict.log.info(`MockDatabaseService ${this.UUID}::${this.Hash} is connecting to a database.`);
44
+ }
45
+
46
+ commit(pRecord)
47
+ {
48
+ this.pict.log.info(`MockDatabaseService ${this.UUID}::${this.Hash} is committing a record ${pRecord}.`);
49
+ }
50
+ }
51
+
52
+ class MockCoreService extends libPictServiceProviderBase.CoreServiceProviderBase
53
+ {
54
+ constructor(pOptions, pServiceHash)
55
+ {
56
+ super(pOptions, pServiceHash);
57
+
58
+ this.serviceType = 'MockCoreService';
59
+
60
+
61
+ }
62
+
63
+ // Core services should be able to provide their behaviors before the Pict object is fully initialized.
64
+ magicBehavior(pData)
65
+ {
66
+ console.log(`MockCoreService ${this.UUID}::${this.Hash} is doing something magical with ${pData}.`);
67
+ }
68
+ }
69
+
70
+ suite
71
+ (
72
+ 'Pict Service Manager',
73
+ function()
74
+ {
75
+ var testPict = false;
76
+
77
+ setup
78
+ (
79
+ function()
80
+ {
81
+ }
82
+ );
83
+
84
+ suite
85
+ (
86
+ 'Service Manager',
87
+ function()
88
+ {
89
+ test
90
+ (
91
+ 'Manually initialize a Service',
92
+ function()
93
+ {
94
+ testPict = new libPict();
95
+
96
+ let tmpSimpleService = new SimpleService(testPict, {SomeOption: true});
97
+
98
+ tmpSimpleService.doSomething();
99
+
100
+ Expect(tmpSimpleService.Hash).to.be.a('string');
101
+
102
+ Expect(tmpSimpleService._PackagePictServiceProvider).to.be.an('object');
103
+ Expect(tmpSimpleService._PackagePictServiceProvider.name).to.equal('pict-serviceproviderbase');
104
+ Expect(tmpSimpleService._PackagePictServiceProvider.version)
105
+ }
106
+ );
107
+ test
108
+ (
109
+ 'Register a Service',
110
+ function()
111
+ {
112
+ testPict = new libPict();
113
+ testPict.serviceManager.addServiceType('SimpleService');
114
+ testPict.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true}, 'SimpleService-123');
115
+
116
+ Expect(testPict.serviceManager.servicesMap['SimpleService']['SimpleService-123']).to.be.an('object');
117
+ }
118
+ );
119
+ test
120
+ (
121
+ 'Use the Default Service',
122
+ function()
123
+ {
124
+ testPict = new libPict();
125
+ testPict.serviceManager.addServiceType('SimpleService', SimpleService);
126
+ let tmpSimpleService = testPict.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true}, 'SimpleService-123');
127
+
128
+ Expect(testPict.serviceManager.servicesMap['SimpleService']['SimpleService-123']).to.be.an('object');
129
+
130
+ // The passed-in magic stuff should work too.
131
+ tmpSimpleService.log.info(`There were almost ${tmpSimpleService.services.DataFormat.formatterDollars(9821229.37)} dollars just lying here!`);
132
+
133
+ Expect(testPict.serviceManager.servicesMap['SimpleService']).to.be.an('object');
134
+
135
+ testPict.serviceManager.services.SimpleService.doSomething();
136
+
137
+ Expect(testPict.serviceManager.services['SimpleService'].Hash).to.equal('SimpleService-123');
138
+ }
139
+ );
140
+ test
141
+ (
142
+ 'Use the Default Service with a different hash',
143
+ function()
144
+ {
145
+ let testPict = new libPict({});
146
+
147
+ testPict.serviceManager.addServiceType('SimpleService', SimpleService);
148
+
149
+ testPict.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true}, 'SimpleService-13');
150
+
151
+ testPict.serviceManager.servicesMap['SimpleService']['SimpleService-13'].doSomething();
152
+
153
+ Expect(testPict.serviceManager.servicesMap['SimpleService']['SimpleService-13']).to.be.an('object');
154
+ }
155
+ );
156
+
157
+ test
158
+ (
159
+ 'Instantiate a service without registering it to Pict',
160
+ function()
161
+ {
162
+ let testPict = new libPict({});
163
+
164
+ testPict.serviceManager.addServiceType('SimpleService', SimpleService);
165
+
166
+ let tmpService = testPict.serviceManager.instantiateServiceProviderWithoutRegistration('SimpleService', {SomeOption: true}, 'SimpleService-99');
167
+
168
+ Expect(testPict.servicesMap.SimpleService['SimpleService-99']).to.be.an('undefined');
169
+
170
+ Expect(tmpService).to.be.an('object');
171
+ }
172
+ );
173
+
174
+ test
175
+ (
176
+ 'Change the default service provider',
177
+ function()
178
+ {
179
+ let testPict = new libPict({});
180
+
181
+ testPict.serviceManager.addServiceType('SimpleService', SimpleService);
182
+ testPict.serviceManager.addServiceType('DatabaseService', MockDatabaseService);
183
+
184
+ testPict.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true});
185
+ testPict.serviceManager.services.SimpleService.doSomething();
186
+
187
+ testPict.serviceManager.instantiateServiceProvider('DatabaseService', {ConnectionString: 'mongodb://localhost:27017/test'}, 'PrimaryConnection');
188
+
189
+ Expect(testPict.serviceManager.services.DatabaseService.Hash).to.equal('PrimaryConnection');
190
+
191
+ testPict.serviceManager.instantiateServiceProvider('DatabaseService', {ConnectionString: 'mongodb://localhost:27017/test'}, 'SecondaryConnection');
192
+
193
+ Expect(testPict.serviceManager.services.DatabaseService.Hash).to.equal('PrimaryConnection');
194
+
195
+ testPict.serviceManager.services.DatabaseService.connect();
196
+ testPict.serviceManager.services.DatabaseService.commit('Test Record');
197
+
198
+ testPict.serviceManager.setDefaultServiceInstantiation('DatabaseService', 'SecondaryConnection');
199
+
200
+ testPict.serviceManager.services.DatabaseService.connect();
201
+ testPict.serviceManager.services.DatabaseService.commit('Another Test Record');
202
+
203
+ Expect(testPict.serviceManager.services.DatabaseService.Hash).to.equal('SecondaryConnection');
204
+ }
205
+ );
206
+
207
+ test
208
+ (
209
+ 'Construct a core service before Pict is initialized',
210
+ function()
211
+ {
212
+ let tmpCoreService = new MockCoreService({SomeOption: true});
213
+
214
+ Expect(tmpCoreService).to.be.an('object');
215
+
216
+ tmpCoreService.magicBehavior('MAGICTESTDATA');
217
+ }
218
+ )
219
+ test
220
+ (
221
+ 'Construct a core service with a hash before Pict is initialized',
222
+ function()
223
+ {
224
+ let tmpCoreService = new MockCoreService({SomeOption: true}, 'MockCoreService-1');
225
+
226
+ Expect(tmpCoreService).to.be.an('object');
227
+ Expect(tmpCoreService.Hash).to.equal('MockCoreService-1');
228
+
229
+ tmpCoreService.magicBehavior('MAGICTESTDATA');
230
+ }
231
+ )
232
+
233
+ test
234
+ (
235
+ 'Construct a core service and attach it to Pict after Pict is initialized',
236
+ function()
237
+ {
238
+
239
+ let tmpCoreService = new MockCoreService({SomeOption: true}, 'MockCoreService-2');
240
+
241
+ Expect(tmpCoreService).to.be.an('object');
242
+ Expect(tmpCoreService.Hash).to.equal('MockCoreService-2');
243
+
244
+ let testPict = new libPict({});
245
+
246
+ testPict.serviceManager.connectPreinitServiceProviderInstance(tmpCoreService);
247
+
248
+ Expect(testPict.servicesMap.MockCoreService['MockCoreService-2']).to.be.an('object');
249
+ Expect(testPict.services.MockCoreService).to.be.an('object');
250
+
251
+ Expect(testPict.services.MockCoreService.pict.log).to.be.an('object');
252
+ }
253
+ )
254
+
255
+ test
256
+ (
257
+ 'Construct a service without a pict at all',
258
+ function()
259
+ {
260
+ let tmpService = new SimpleService({Setting:'Something'});
261
+
262
+ Expect(tmpService.options.Setting).to.equal('Something');
263
+ Expect(tmpService.UUID).to.be.a('string');
264
+ }
265
+ )
266
+
267
+ test
268
+ (
269
+ 'Attempt to change the default service provider to a nonexistant provider',
270
+ function()
271
+ {
272
+ let testPict = new libPict({});
273
+
274
+ testPict.serviceManager.addServiceType('SimpleService', SimpleService);
275
+ testPict.serviceManager.addServiceType('DatabaseService', MockDatabaseService);
276
+
277
+ testPict.serviceManager.instantiateServiceProvider('SimpleService', {SomeOption: true});
278
+ testPict.serviceManager.services.SimpleService.doSomething();
279
+
280
+ testPict.serviceManager.instantiateServiceProvider('DatabaseService', {ConnectionString: 'mongodb://localhost:27017/test'}, 'PrimaryConnection');
281
+
282
+ Expect(testPict.serviceManager.services.DatabaseService.Hash).to.equal('PrimaryConnection');
283
+
284
+ testPict.serviceManager.instantiateServiceProvider('DatabaseService', {ConnectionString: 'mongodb://localhost:27017/test'}, 'SecondaryConnection');
285
+
286
+ Expect(testPict.serviceManager.services.DatabaseService.Hash).to.equal('PrimaryConnection');
287
+
288
+ testPict.serviceManager.services.DatabaseService.connect();
289
+ testPict.serviceManager.services.DatabaseService.commit('Test Record');
290
+
291
+ Expect(testPict.serviceManager.setDefaultServiceInstantiation('DatabaseService', 'TertiaryConnection')).to.be.false;
292
+
293
+ testPict.serviceManager.services.DatabaseService.connect();
294
+ testPict.serviceManager.services.DatabaseService.commit('Another Test Record');
295
+
296
+ Expect(testPict.serviceManager.services.DatabaseService.Hash).to.equal('PrimaryConnection');
297
+ }
298
+ );
299
+ }
300
+ );
301
+ }
302
+ );