From 17deed412a2b27d90db5bcbdbd6dd06682a75fc3 Mon Sep 17 00:00:00 2001 From: Mason Payne Date: Sat, 23 Jan 2021 01:14:04 -0700 Subject: [PATCH] add support for all crud and list in the service files --- .../{{component}}/{{component}}Service.ets | 1 - src/systemGenService.ts | 2 +- src/views/mapper-creator.ts | 120 ++++++++---------- src/views/service-creator.ts | 46 +++++++ src/views/views-creator.ts | 22 +++- 5 files changed, 119 insertions(+), 72 deletions(-) create mode 100644 src/views/service-creator.ts diff --git a/frame/src/components/{{component}}/{{component}}Service.ets b/frame/src/components/{{component}}/{{component}}Service.ets index 37c0669..fc61ceb 100644 --- a/frame/src/components/{{component}}/{{component}}Service.ets +++ b/frame/src/components/{{component}}/{{component}}Service.ets @@ -7,7 +7,6 @@ class {{Component}}Service { public initialize() { return Promise.resolve(); } - // SYSTEM-BUILDER-{{component}}-service } diff --git a/src/systemGenService.ts b/src/systemGenService.ts index 7b6e78f..9512d96 100644 --- a/src/systemGenService.ts +++ b/src/systemGenService.ts @@ -50,7 +50,7 @@ interface ComponentDef { interface EndpointDef { component: string; table: string; - type: ('list' | 'count' | 'item' | 'distinct' | 'update' | 'create' | 'delete' | 'search'); + type: ('list' | 'count' | 'item' | 'update' | 'create' | 'delete' | 'search'); columns: ColumnRef[]; values?: ValueDef[]; join?: JoinDef[]; diff --git a/src/views/mapper-creator.ts b/src/views/mapper-creator.ts index dfb656e..fa19e3f 100644 --- a/src/views/mapper-creator.ts +++ b/src/views/mapper-creator.ts @@ -22,7 +22,7 @@ function createMapperFunc(view: EndpointDef): string { function buildDeleteItem(view: EndpointDef): string { let func: string = ''; - let funcName = buildFunctionName(view); + let funcName = buildMapperFunctionName(view); let tables: string = `${view.table}`; let {filters, requiredQueryValues, optionalFilterParts} = constructFilters(view); let query: string = `DELETE FROM ${tables}${filters}`; @@ -45,7 +45,7 @@ function buildDeleteItem(view: EndpointDef): string { function buildGetItem(view: EndpointDef): string { let func: string = ''; - let funcName = buildFunctionName(view); + let funcName = buildMapperFunctionName(view); let columns: string = `${view.component}.${view.component}_id, ${view.columns.map(c => `${c.table}.${c.name}`).join(', ')}`; let tables: string = view.join?.length ? buildJoin(view) : `${view.table}`; let {filters, requiredQueryValues, optionalFilterParts} = constructFilters(view); @@ -69,23 +69,60 @@ function buildGetItem(view: EndpointDef): string { function buildCreateFunc(view: EndpointDef): string { let func: string = ''; - let query: string = `INSERT INTO ${view.table} SET `; - func = getCreateOrUpdateFunc(query, view); + let inQuery: string = `INSERT INTO ${view.table} SET `; + let {funcName, query, requiredQueryValues, optionalValuesCode} = getCreateOrUpdateFunc(inQuery, view); + func = ` + public ${funcName}(params: {[key: string]: string}) { + + let query: string = '${query}'; + let queryValues: string[] = [${requiredQueryValues}]; + + // optional params? + ${optionalValuesCode} + return super.runQuery(query, [...queryValues]); + } +`; return func; } function buildUpdateFunc(view: EndpointDef): string { let func: string = ''; - let query: string = `UPDATE ${view.table} SET `; - func = getCreateOrUpdateFunc(query, view); + let inQuery: string = `UPDATE ${view.table} SET `; + let {funcName, query, requiredQueryValues, optionalValuesCode} = getCreateOrUpdateFunc(inQuery, view); + let postQuery = ` WHERE `; + for (let i in view.filters) { + // @ts-ignore + let filter: Filter = view.filters[i]; + if (!postQuery.endsWith('WHERE ')) { + postQuery = postQuery + ` AND `; + } + postQuery = postQuery + `${filter.column.table}.${filter.column.name} = ?`; + if (requiredQueryValues.length) { + requiredQueryValues = requiredQueryValues + `, `; + } + requiredQueryValues = requiredQueryValues + `params.${filter.param}`; + } + + func = ` + public ${funcName}(params: {[key: string]: string}) { + + let query: string = '${query}'; + let queryValues: string[] = [${requiredQueryValues}]; + + // optional params? + ${optionalValuesCode} + + query = query + '${postQuery}'; + return super.runQuery(query, [...queryValues]); + } +`; return func; } -function getCreateOrUpdateFunc(query: string, view: EndpointDef): string { - let func: string = ''; - let funcName = buildFunctionName(view); +function getCreateOrUpdateFunc(query: string, view: EndpointDef) { + let funcName = buildMapperFunctionName(view); let requiredQueryValues: string = ''; let optionalValuesCode: string = ''; for (let i in view.columns) { @@ -108,20 +145,7 @@ function getCreateOrUpdateFunc(query: string, view: EndpointDef): string { `; } } - - func = ` - public ${funcName}(params: {[key: string]: string}) { - - let query: string = '${query}'; - let queryValues: string[] = [${requiredQueryValues}]; - - // optional params? - ${optionalValuesCode} - return super.runQuery(query, [...queryValues]); - } -`; - - return func; + return {funcName, query, requiredQueryValues, optionalValuesCode}; } function constructFilters(view: EndpointDef, isSearch=false) { @@ -165,7 +189,7 @@ function buildGetList(view: EndpointDef, isSearch=false): string { let columns: string = view.type === 'count' ? `count(*)` : `${view.component}.${view.component}_id, ${view.columns.map(c => `${c.table}.${c.name}`).join(', ')}`; let query: string = ''; let tables: string = view.join?.length ? buildJoin(view) : `${view.table}`; - funcName = buildFunctionName(view); + funcName = buildMapperFunctionName(view); let {filters, requiredQueryValues, optionalFilterParts} = constructFilters(view, isSearch); @@ -201,49 +225,6 @@ function buildGetList(view: EndpointDef, isSearch=false): string { return func; } -function buildSearches(view: EndpointDef): {filters: string, requiredFilterValues: string, optionalFiltersCode: string} { - let filtersObj: {filters: string, requiredFilterValues: string, optionalFiltersCode: string} = { - filters: '', - requiredFilterValues: '', - optionalFiltersCode: '' - }; - - let filters: string = ''; - let requiredFilterStrings = []; - let requiredQueryValues = ''; - let optionalFilterParts = ''; - if (view.filters) { - for (let i in view.filters) { - let f: Filter = view.filters[i]; - if (f.required) { - requiredFilterStrings.push(`${f.column.table}.${f.column.name} ${f.comparison} ?`); // e.g. 'table.id = ?' - if (requiredQueryValues.length) { - requiredQueryValues = requiredQueryValues + `, `; - } - requiredQueryValues = requiredQueryValues + `params.${f.param}`; - } else { - /* e.g. - if (eventLog.app) { - query = query + ', app = ?'; - queryValues.push(eventLog.app); - } - */ - optionalFilterParts = optionalFilterParts + ` - if (params.${f.param}) { - query = query + ' OR ${f.column.table}.${f.column.name} ${f.comparison} ?'; - queryValues.push('%' + params.${f.param} + '%'); - }`; - } - } - filters = ` WHERE ${requiredFilterStrings.join(' AND ')}`; - } - - filtersObj.filters = filters; - filtersObj.requiredFilterValues = requiredQueryValues; - filtersObj.optionalFiltersCode = optionalFilterParts; - return filtersObj; -} - function buildJoin(view: EndpointDef): string { if (view.join?.length) { let join = `${view.table}`; @@ -271,7 +252,7 @@ function buildOrderBy(view: EndpointDef): string { return orderBy; } -function buildFunctionName(view: EndpointDef): string { +function buildMapperFunctionName(view: EndpointDef): string { let selector: {[type: string]: (view: EndpointDef) => string} = { 'list': (view: EndpointDef) => `get${pluralize(uppercaseFirstLetter(view.component))}` + (view.type === 'count' ? 'Count' : ''), 'count': (view: EndpointDef) => `get${pluralize(uppercaseFirstLetter(view.component))}` + (view.type === 'count' ? 'Count' : ''), @@ -285,5 +266,6 @@ function buildFunctionName(view: EndpointDef): string { } export { - createMapperFunc + createMapperFunc, + buildMapperFunctionName } \ No newline at end of file diff --git a/src/views/service-creator.ts b/src/views/service-creator.ts new file mode 100644 index 0000000..78fee52 --- /dev/null +++ b/src/views/service-creator.ts @@ -0,0 +1,46 @@ +import {EndpointDef} from "../systemGenService"; +import {lowercaseFirstLetter} from "./helpers"; +import {buildMapperFunctionName} from "./mapper-creator"; + + +function createServiceFunc(view: EndpointDef) { + // TODO: add support for doing things other than talking to the mapper e.g. API calls and cache checks + return buildServiceFunction(view); +} + +function buildServiceFunction(view: EndpointDef): string { + let func: string = ''; + let isListOrSearch: boolean = view.type === 'list' || view.type === 'search'; + let funcName: string = buildServiceFunctionName(view); + // there should never be an 'undefined' item in funcParams but the compiler complained that it was possible + // TODO: funcParams should be sorted by 'required' so the optional params can come last and be left off when calling + let funcParams: (string | undefined)[] = (view.columns?.filter(column => column.param).map(column => column.param) || []).concat(view.filters?.filter(filter => filter.param).map(filter => filter.param) || []); + let columnParams: string[] = view.columns?.filter(column => column.param).map(column => { return '\n ' + column.param + ': ' + column.param; }); + let filterParams: string[] = view.filters?.filter(filter => filter.param).map(filter => { return '\n ' + filter.param + ': ' + filter.param; }) || []; + + if (isListOrSearch) { + funcParams.push('offset'); + funcParams.push('limit'); + } + + func = ` + public ${funcName}(${funcParams.join(', ')}) { + let params = {${columnParams}${columnParams.length ? ',' : ''}${filterParams} + }; + return this.${mapperInstance(view)}.${buildMapperFunctionName(view)}(params${isListOrSearch ? ', offset, limit' : ''}); + } +`; + return func; +} + +function buildServiceFunctionName(view: EndpointDef): string { + return buildMapperFunctionName(view); // the functions should have the same name... I'm pretty sure... +} + +function mapperInstance(view: EndpointDef): string { + return `${lowercaseFirstLetter(view.component)}Mapper`; +} + +export { + createServiceFunc +} \ No newline at end of file diff --git a/src/views/views-creator.ts b/src/views/views-creator.ts index 36a8506..22cc7ff 100644 --- a/src/views/views-creator.ts +++ b/src/views/views-creator.ts @@ -7,6 +7,7 @@ import * as path from 'path'; import * as fs from 'fs'; import {createMapperFunc} from "./mapper-creator"; import {uppercaseFirstLetter, lowercaseFirstLetter} from "./helpers"; +import {createServiceFunc} from "./service-creator"; const ncp = require('ncp').ncp; @@ -35,6 +36,11 @@ function createComponent(component: ComponentDef, systemDef: SystemDef) { addInitializeRoutesCode(component.component, systemDef.name); let serviceFileLocation: string = path.join(process.cwd(), systemDef.name, 'src', 'components', component.component, `${component.component}Service.ts`); let servicePromise = initializeComponentFile(path.join(process.cwd(), systemDef.name, 'src', 'components', component.component, '{{component}}Service.ets'), serviceFileLocation, component.component, systemDef.name); + for (let i in component.endpoints) { + servicePromise = servicePromise.then(() => { + return insertServiceCode(component.endpoints[i], systemDef.name); + }); + } addInitializeServiceCode(component.component, systemDef.name); Promise.all([mapperPromise, routesPromise, servicePromise]).then(() => { console.log(`success creating component ${component.component}`); @@ -98,4 +104,18 @@ function insertMapperCode(view: EndpointDef, outDir: string): Promise { fs.writeFileSync(fileLocation, newMapperFile, 'utf8'); resolve(); }); -} \ No newline at end of file +} + +function insertServiceCode(view: EndpointDef, outDir: string): Promise { + return new Promise((resolve) => { + const separator: string = `// SYSTEM-BUILDER-${view.component}-service`; + let fileLocation = path.join(process.cwd(), outDir, 'src', 'components', view.component, `${view.component}Service.ts`); + let initServiceFile: string = fs.readFileSync(fileLocation, 'utf8'); + let parts = initServiceFile.split(separator); + parts[0] = parts[0] + createServiceFunc(view); + let newServiceFile = parts.join(separator); + fs.writeFileSync(fileLocation, newServiceFile, 'utf8'); + resolve(); + }); +} +