add support for searching queries

This commit is contained in:
2021-01-22 23:18:15 -07:00
parent 0026d7ace3
commit c176de3297
3 changed files with 98 additions and 27 deletions

View File

@ -142,6 +142,76 @@ let def: SystemDef = {
}, },
] ]
}, },
{
component: 'task',
table: 'task',
type: 'search',
columns: [
{
name: 'name',
table: 'task'
},
{
name: 'description',
table: 'task'
},
{
name: 'completed',
table: 'task'
},
{
name: 'completed_date',
table: 'task'
},
],
orderBy: [
{
column: {
name: 'modified',
table: 'task'
},
direction: 'desc'
}
],
filters: [
{
param: 'list',
column: {
name: 'list_id',
table: 'task'
},
comparison: '=',
required: true
},
{
param: 'completed',
column: {
name: 'completed',
table: 'task'
},
comparison: '=',
required: false
},
{
param: 'name',
column: {
name: 'name',
table: 'task'
},
comparison: 'LIKE',
required: false
},
{
param: 'description',
column: {
name: 'description',
table: 'task'
},
comparison: 'LIKE',
required: false
},
]
},
{ {
component: 'task', component: 'task',
table: 'task', table: 'task',

View File

@ -67,7 +67,7 @@ interface Order {
interface Filter { interface Filter {
param: string; // the query param used to get the value param: string; // the query param used to get the value
column: ColumnRef; column: ColumnRef;
comparison: '=' | '!=' | '>' | '<' | 'contains'; comparison: '=' | '!=' | '>' | '<' | 'contains' | 'LIKE';
required?: boolean; required?: boolean;
} }

View File

@ -6,6 +6,8 @@ function createMapperFunc(view: EndpointDef): string {
let func: string = ''; let func: string = '';
if (view.type === 'list' || view.type === 'count') { if (view.type === 'list' || view.type === 'count') {
func = buildGetList(view); func = buildGetList(view);
} else if (view.type === 'search') {
func = buildGetList(view, true);
} else if (view.type === 'item') { } else if (view.type === 'item') {
func = buildGetItem(view); func = buildGetItem(view);
} else if (view.type === 'update') { } else if (view.type === 'update') {
@ -22,10 +24,7 @@ function buildDeleteItem(view: EndpointDef): string {
let func: string = ''; let func: string = '';
let funcName = buildFunctionName(view); let funcName = buildFunctionName(view);
let tables: string = `${view.table}`; let tables: string = `${view.table}`;
let filtersObj = buildFilters(view); let {filters, requiredQueryValues, optionalFilterParts} = constructFilters(view);
let filters: string = filtersObj.filters;
let requiredFilterValues: string = filtersObj.requiredFilterValues;
let optionalFilterParts = filtersObj.optionalFiltersCode;
let query: string = `DELETE FROM ${tables}${filters}`; let query: string = `DELETE FROM ${tables}${filters}`;
let funcParams = 'params: {[key: string]: string}'; let funcParams = 'params: {[key: string]: string}';
@ -33,7 +32,7 @@ function buildDeleteItem(view: EndpointDef): string {
public ${funcName}(${funcParams}) { public ${funcName}(${funcParams}) {
let query: string = '${query}'; let query: string = '${query}';
let queryValues: string[] = [${requiredFilterValues}]; let queryValues: string[] = [${requiredQueryValues}];
// optional params? // optional params?
${optionalFilterParts} ${optionalFilterParts}
@ -49,10 +48,7 @@ function buildGetItem(view: EndpointDef): string {
let funcName = buildFunctionName(view); let funcName = buildFunctionName(view);
let columns: string = `${view.component}.${view.component}_id, ${view.columns.map(c => `${c.table}.${c.name}`).join(', ')}`; 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 tables: string = view.join?.length ? buildJoin(view) : `${view.table}`;
let filtersObj = buildFilters(view); let {filters, requiredQueryValues, optionalFilterParts} = constructFilters(view);
let filters: string = filtersObj.filters;
let requiredFilterValues: string = filtersObj.requiredFilterValues;
let optionalFilterParts = filtersObj.optionalFiltersCode;
let query: string = `SELECT ${columns} FROM ${tables}${filters} LIMIT 1`; let query: string = `SELECT ${columns} FROM ${tables}${filters} LIMIT 1`;
let funcParams = 'params: {[key: string]: string}'; let funcParams = 'params: {[key: string]: string}';
@ -60,7 +56,7 @@ function buildGetItem(view: EndpointDef): string {
public ${funcName}(${funcParams}) { public ${funcName}(${funcParams}) {
let query: string = '${query}'; let query: string = '${query}';
let queryValues: string[] = [${requiredFilterValues}]; let queryValues: string[] = [${requiredQueryValues}];
// optional params? // optional params?
${optionalFilterParts} ${optionalFilterParts}
@ -128,17 +124,8 @@ function getCreateOrUpdateFunc(query: string, view: EndpointDef): string {
return func; return func;
} }
function buildGetList(view: EndpointDef): string { function constructFilters(view: EndpointDef, isSearch=false) {
// TODO: optionally allow a raw query definition with predefined params
// This would be so much simpler and easy if it were just the queries wanted
let func: string = '';
let funcName: 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}`;
let filters: string = ''; let filters: string = '';
funcName = buildFunctionName(view);
let requiredFilterStrings = []; let requiredFilterStrings = [];
let requiredQueryValues = ''; let requiredQueryValues = '';
let optionalFilterParts = ''; let optionalFilterParts = '';
@ -160,13 +147,27 @@ function buildGetList(view: EndpointDef): string {
*/ */
optionalFilterParts = optionalFilterParts + ` optionalFilterParts = optionalFilterParts + `
if (params.${f.param}) { if (params.${f.param}) {
query = query + ' AND ${f.column.table}.${f.column.name} ${f.comparison} ?'; query = query + ' ${isSearch ? 'OR' : 'AND'} ${f.column.table}.${f.column.name} ${isSearch ? 'LIKE' : f.comparison} ?';
queryValues.push(params.${f.param}); queryValues.push(${isSearch ? '\'%\' + params.' + f.param + ' + \'%\'' : 'params.' + f.param});
}`; }`;
} }
} }
filters = ` WHERE ${requiredFilterStrings.join(' AND ')}`; filters = ` WHERE ${requiredFilterStrings.join(' AND ')}`;
} }
return {filters, requiredQueryValues, optionalFilterParts};
}
function buildGetList(view: EndpointDef, isSearch=false): string {
// TODO: optionally allow a raw query definition with predefined params
// This would be so much simpler and easy if it were just the queries wanted
let func: string = '';
let funcName: 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);
let {filters, requiredQueryValues, optionalFilterParts} = constructFilters(view, isSearch);
query = `SELECT ${columns} FROM ${tables}${filters}`; query = `SELECT ${columns} FROM ${tables}${filters}`;
let orderByCode = ''; let orderByCode = '';
@ -200,7 +201,7 @@ function buildGetList(view: EndpointDef): string {
return func; return func;
} }
function buildFilters(view: EndpointDef): {filters: string, requiredFilterValues: string, optionalFiltersCode: string} { function buildSearches(view: EndpointDef): {filters: string, requiredFilterValues: string, optionalFiltersCode: string} {
let filtersObj: {filters: string, requiredFilterValues: string, optionalFiltersCode: string} = { let filtersObj: {filters: string, requiredFilterValues: string, optionalFiltersCode: string} = {
filters: '', filters: '',
requiredFilterValues: '', requiredFilterValues: '',
@ -229,8 +230,8 @@ function buildFilters(view: EndpointDef): {filters: string, requiredFilterValues
*/ */
optionalFilterParts = optionalFilterParts + ` optionalFilterParts = optionalFilterParts + `
if (params.${f.param}) { if (params.${f.param}) {
query = query + ' AND ${f.column.table}.${f.column.name} ${f.comparison} ?'; query = query + ' OR ${f.column.table}.${f.column.name} ${f.comparison} ?';
queryValues.push(params.${f.param}); queryValues.push('%' + params.${f.param} + '%');
}`; }`;
} }
} }
@ -278,7 +279,7 @@ function buildFunctionName(view: EndpointDef): string {
'update': (view: EndpointDef) => `update${uppercaseFirstLetter(view.component)}`, 'update': (view: EndpointDef) => `update${uppercaseFirstLetter(view.component)}`,
'create': (view: EndpointDef) => `create${uppercaseFirstLetter(view.component)}`, 'create': (view: EndpointDef) => `create${uppercaseFirstLetter(view.component)}`,
'delete': (view: EndpointDef) => `delete${uppercaseFirstLetter(view.component)}`, 'delete': (view: EndpointDef) => `delete${uppercaseFirstLetter(view.component)}`,
'search': (view: EndpointDef) => `search${uppercaseFirstLetter(view.component)}`, 'search': (view: EndpointDef) => `search${pluralize(uppercaseFirstLetter(view.component))}`,
}; };
return selector[view.type](view); return selector[view.type](view);
} }