Skip to content

Commit 1256661

Browse files
committed
Add a CompositeTemplateProvider
This can be used to aggregate multiple template providers together (e.g., templates from multiple sources).
1 parent 3d262a0 commit 1256661

File tree

3 files changed

+152
-2
lines changed

3 files changed

+152
-2
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# v0.20.0
2+
## Added
3+
* Add a CompositeTemplateProvider to aggregate results from multiple template providers
4+
5+
## Changed
6+
* Update dependencies
7+
18
# v0.19.1
29
## Changed
310
* Update dependencies

lib/template_provider.js

Lines changed: 128 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -686,9 +686,136 @@ class DataStoreTemplateProvider extends BaseTemplateProvider {
686686
}
687687
}
688688

689+
/**
690+
* TemplateProvider that aggregates multiple template providers
691+
*/
692+
class CompositeTemplateProvider extends BaseTemplateProvider {
693+
/**
694+
* @param {BaseTemplateProvider[]} providers - an array of template providers
695+
* @param {object} [supportedHashes={}] - an optional map of hash values to validate against
696+
*/
697+
constructor(providers, supportedHashes) {
698+
super(supportedHashes);
699+
this.providers = providers;
700+
}
701+
702+
_getProviderForSet(setName) {
703+
return Promise.resolve()
704+
.then(() => Promise.all(
705+
this.providers.map(provider => Promise.all([
706+
Promise.resolve(provider),
707+
provider.hasSet(setName)
708+
]))
709+
))
710+
.then(providerList => providerList
711+
.filter(x => x[1])
712+
.map(x => x[0]))
713+
.then((providers) => {
714+
if (providers.length === 0) {
715+
return Promise.reject(new Error(
716+
`Could not find template set "${setName}"`
717+
));
718+
}
719+
720+
return Promise.resolve(providers[0]);
721+
});
722+
}
723+
724+
_getProviderForTemplate(templatePath) {
725+
const setName = templatePath.split('/')[0];
726+
return this._getProviderForSet(setName);
727+
}
728+
729+
_getSetProviderPairs(setListOrName) {
730+
const initSetList = (typeof setListOrName === 'string') ? [setListOrName] : (setListOrName || []);
731+
732+
return Promise.resolve()
733+
.then(() => (initSetList.length > 0 ? Promise.resolve(initSetList) : this.listSets()))
734+
.then(setList => Promise.all(
735+
setList.map(
736+
setName => this._getProviderForSet(setName)
737+
.then(provider => [setName, provider])
738+
)
739+
));
740+
}
741+
742+
_loadTemplate(templateName) {
743+
return Promise.resolve()
744+
.then(() => this._getProviderForTemplate(templateName))
745+
.then(provider => provider.fetch(templateName));
746+
}
747+
748+
/**
749+
* Delete the template set associated with the supplied set ID
750+
*
751+
* @returns {Promise}
752+
*/
753+
removeSet(setid) {
754+
return this._getProviderForSet(setid)
755+
.then(provider => provider.removeSet(setid));
756+
}
757+
758+
/**
759+
* Get a list of set names known to the provider
760+
*
761+
* @returns {Promise} Promise resolves to a string array
762+
*/
763+
listSets() {
764+
return Promise.all(
765+
this.providers.map(provider => provider.listSets())
766+
)
767+
.then(setLists => [...new Set(setLists.flat())]);
768+
}
769+
770+
/**
771+
* List all templates known to the provider (optionally filtered by the supplied list of set names)
772+
*
773+
* @param {string[]} [setList=[]]
774+
* @returns {Promise} Promise resolves to a string array
775+
*/
776+
list(setList) {
777+
return this._getSetProviderPairs(setList)
778+
.then(pairs => Promise.all(pairs.map(([setName, provider]) => provider.list(setName))))
779+
.then(setLists => setLists.flat());
780+
}
781+
782+
/**
783+
* Get all schema known to the provider (optionally filtered by the supplied set name)
784+
*
785+
* @param {string} [filteredSetName] - only return data for this template set (instead of all template sets)
786+
* @returns {Promise} Promise resolves to an object containing schema
787+
*/
788+
getSchemas(filteredSetName) {
789+
return this._getSetProviderPairs(filteredSetName)
790+
.then(pairs => Promise.all(pairs.map(([setName, provider]) => provider.getSchemas(setName))))
791+
.then(data => Object.assign({}, ...data));
792+
}
793+
794+
/**
795+
* Get all data files known to the provider (optionally filtered by the supplied set name)
796+
*
797+
* @param {string} [filteredSetName] - only return data for this template set (instead of all template sets)
798+
* @returns {Promise} Promise resolves to an object containing data files
799+
*/
800+
getDataFiles(filteredSetName) {
801+
return this._getSetProviderPairs(filteredSetName)
802+
.then(pairs => Promise.all(pairs.map(([setName, provider]) => provider.getDataFiles(setName))))
803+
.then(data => Object.assign({}, ...data));
804+
}
805+
806+
/**
807+
* Clear any cache associated with this provider
808+
*/
809+
invalidateCache() {
810+
super.invalidateCache();
811+
this.providers.forEach(provider => provider.invalidateCache());
812+
}
813+
}
814+
689815
module.exports = {
690816
BaseTemplateProvider,
691817
FsTemplateProvider,
692818
FsSingleTemplateProvider,
693-
DataStoreTemplateProvider
819+
DataStoreTemplateProvider,
820+
CompositeTemplateProvider
694821
};

test/template_provider.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ const StorageMemory = require('@f5devcentral/atg-storage').StorageMemory;
3030
const {
3131
FsTemplateProvider,
3232
FsSingleTemplateProvider,
33-
DataStoreTemplateProvider
33+
DataStoreTemplateProvider,
34+
CompositeTemplateProvider
3435
} = require('../lib/template_provider');
3536

3637
const { GitHubTemplateProvider } = require('../lib/github_provider');
@@ -226,6 +227,7 @@ describe('template provider tests', function () {
226227
describe('DataStoreTemplateProvider', function () {
227228
const testStorage = new StorageMemory();
228229
before(function () {
230+
testStorage.data = {};
229231
return DataStoreTemplateProvider.fromFs(testStorage, templatesPath);
230232
});
231233
const createProvider = filtered => new DataStoreTemplateProvider(testStorage, filtered);
@@ -261,4 +263,18 @@ describe('template provider tests', function () {
261263
)
262264
);
263265
});
266+
describe('CompositeTemplateProvider', function () {
267+
const testStorage = new StorageMemory();
268+
before(function () {
269+
testStorage.data = {};
270+
return DataStoreTemplateProvider.fromFs(testStorage, templatesPath);
271+
});
272+
273+
runSharedTests(
274+
filtered => new CompositeTemplateProvider([
275+
new FsTemplateProvider(templatesPath, filtered),
276+
new DataStoreTemplateProvider(testStorage, filtered)
277+
])
278+
);
279+
});
264280
});

0 commit comments

Comments
 (0)