diff --git a/package.json b/package.json index d422e13f..59c84445 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "proskomma", - "version": "0.7.13", + "version": "0.7.14", "description": "A Scripture Runtime Engine", "main": "dist/index.js", "files": [ diff --git a/src/index.js b/src/index.js index 2ebdc9fc..8f9163dc 100644 --- a/src/index.js +++ b/src/index.js @@ -38,7 +38,7 @@ const executableSchema = }); class Proskomma { - constructor() { + constructor(selectors) { this.processorId = generateId(); this.documents = {}; this.docSetsBySelector = {}; @@ -53,7 +53,7 @@ class Proskomma { introHeading: [], }; this.emptyBlocks = []; - this.selectors = [ + this.selectors = selectors || [ { name: 'lang', type: 'string', @@ -64,6 +64,7 @@ class Proskomma { type: 'string', }, ]; + this.validateSelectorSpec(this.selectors); this.mutex = new Mutex(); this.nextPeriph = 0; this.nextTable = 0; @@ -146,6 +147,28 @@ class Proskomma { } } + validateSelectorSpec(spec) { + for (const specElement of spec) { + if (!specElement['name']) { + throw new Error(`name not found in selector spec element '${JSON.stringify(specElement)}'`); + } + + if (!specElement['type']) { + throw new Error(`type not found in selector spec element '${JSON.stringify(specElement)}'`); + } + + if (!['string', 'integer'].includes(specElement.type)) { + throw new Error(`Type for spec element must be string or number, not ${specElement.type}`); + } + + for (const selectorKey of Object.keys(specElement)) { + if (!['name', 'type', 'regex', 'min', 'max', 'enum'].includes(selectorKey)) { + throw new Error(`Unexpected key '${selectorKey}' in selectorSpec`); + } + } + } + } + selectorString(docSetSelectors) { // In root so it can be easily subclassed return this.selectors.map(s => s.name).map(n => `${docSetSelectors[n]}`).join('_'); @@ -326,7 +349,7 @@ class Proskomma { return false; } - for (const docId of Object.entries(this.documents).filter(([id, doc]) => doc.docSetId === docSetId).map(tup => tup[0])) { + for (const docId of Object.entries(this.documents).filter(tup => tup[1].docSetId === docSetId).map(tup => tup[0])) { this.deleteDocument(docSetId, docId, false, false); } diff --git a/test/code/custom.cjs b/test/code/custom.cjs index 499cc195..74593482 100644 --- a/test/code/custom.cjs +++ b/test/code/custom.cjs @@ -87,4 +87,37 @@ test( console.log(err); } }, -); \ No newline at end of file +); + +test( + 'Specify Selector Spec (${testGroup})', + async function (t) { + try { + t.plan(2); + t.doesNotThrow(() => new Proskomma([ + { + name: 'lang', + type: 'string', + regex: '[a-z]{3}', + }, + { + name: 'abbr', + type: 'string', + }, + ])); + t.throws(() => new Proskomma([ + { + name: 'lang', + type: 'stringz', + regex: '[a-z]{3}', + }, + { + name: 'abbr', + type: 'string', + }, + ]), /stringz/); + } catch (err) { + console.log(err); + } + }, +) diff --git a/test/code/mutate_delete.cjs b/test/code/mutate_delete.cjs index 48a2926c..69bbef92 100644 --- a/test/code/mutate_delete.cjs +++ b/test/code/mutate_delete.cjs @@ -47,7 +47,7 @@ test( `Reload Deleted DocSet (${testGroup})`, async function (t) { try { - t.plan(2); + t.plan(3); const selectors = { lang: 'eng', abbr: 'ust', @@ -57,9 +57,10 @@ test( let result = await pk.gqlQuery(query); query = `mutation { deleteDocSet(docSetId: "${result.data.docSets[0].id}") }`; result = await pk.gqlQuery(query); - query = '{ docSets { id } }'; + query = '{ docSets { id } nDocuments}'; result = await pk.gqlQuery(query); t.equal(result.data.docSets.length, 0); + t.equal(result.data.nDocuments, 0); const content = fse.readFileSync(path.resolve(__dirname, '../test_data/usx/web_rut.usx')); t.doesNotThrow(