From 81ba81a27697285422fc2dc43f8b1eabeb6fb910 Mon Sep 17 00:00:00 2001 From: rijkvanzanten Date: Wed, 16 Jun 2021 16:35:27 -0400 Subject: [PATCH] Add fields support for date functions --- api/src/database/functions/base.ts | 18 ++--- .../database/functions/dialects/postgres.ts | 68 ++++++++++++++----- api/src/database/run-ast.ts | 5 +- .../utils/apply-function-to-column-name.ts | 22 ++++++ api/src/utils/get-column.ts | 10 ++- api/src/utils/strip-function.ts | 1 - 6 files changed, 93 insertions(+), 31 deletions(-) create mode 100644 api/src/utils/apply-function-to-column-name.ts diff --git a/api/src/database/functions/base.ts b/api/src/database/functions/base.ts index 22160987da..21df8e3486 100644 --- a/api/src/database/functions/base.ts +++ b/api/src/database/functions/base.ts @@ -1,12 +1,12 @@ import { Knex } from 'knex'; -export interface IBaseHelper { - year(table: string, column: string): Knex.Raw; - month(table: string, column: string): Knex.Raw; - week(table: string, column: string): Knex.Raw; - day(table: string, column: string): Knex.Raw; - weekday(table: string, column: string): Knex.Raw; - hour(table: string, column: string): Knex.Raw; - minute(table: string, column: string): Knex.Raw; - second(table: string, column: string): Knex.Raw; +export interface HelperFn { + year(table: string, column: string, alias?: string): Knex.Raw; + month(table: string, column: string, alias?: string): Knex.Raw; + week(table: string, column: string, alias?: string): Knex.Raw; + day(table: string, column: string, alias?: string): Knex.Raw; + weekday(table: string, column: string, alias?: string): Knex.Raw; + hour(table: string, column: string, alias?: string): Knex.Raw; + minute(table: string, column: string, alias?: string): Knex.Raw; + second(table: string, column: string, alias?: string): Knex.Raw; } diff --git a/api/src/database/functions/dialects/postgres.ts b/api/src/database/functions/dialects/postgres.ts index 76d057cfb8..464541af8e 100644 --- a/api/src/database/functions/dialects/postgres.ts +++ b/api/src/database/functions/dialects/postgres.ts @@ -1,42 +1,74 @@ import { Knex } from 'knex'; -import { IBaseHelper } from '../base'; +import { HelperFn } from '../base'; -export class HelperPostgres implements IBaseHelper { +export class HelperPostgres implements HelperFn { private knex: Knex; constructor(knex: Knex) { this.knex = knex; } - year(table: string, column: string): Knex.Raw { - return this.knex.raw('EXTRACT(YEAR FROM ??.??) as ??', [table, column, `${column}_year`]); + year(table: string, column: string, alias?: string): Knex.Raw { + if (alias) { + return this.knex.raw('EXTRACT(YEAR FROM ??.??) as ??', [table, column, alias]); + } + + return this.knex.raw('EXTRACT(YEAR FROM ??.??)', [table, column]); } - month(table: string, column: string): Knex.Raw { - return this.knex.raw('EXTRACT(MONTH FROM ??)', [column]); + month(table: string, column: string, alias?: string): Knex.Raw { + if (alias) { + return this.knex.raw('EXTRACT(MONTH FROM ??.??) as ??', [table, column, alias]); + } + + return this.knex.raw('EXTRACT(MONTH FROM ??.??)', [table, column]); } - week(table: string, column: string): Knex.Raw { - return this.knex.raw('EXTRACT(WEEK FROM ??)', [column]); + week(table: string, column: string, alias?: string): Knex.Raw { + if (alias) { + return this.knex.raw('EXTRACT(WEEK FROM ??.??) as ??', [table, column, alias]); + } + + return this.knex.raw('EXTRACT(WEEK FROM ??.??)', [table, column]); } - day(table: string, column: string): Knex.Raw { - return this.knex.raw('EXTRACT(DAY FROM ??)', [column]); + day(table: string, column: string, alias?: string): Knex.Raw { + if (alias) { + return this.knex.raw('EXTRACT(DAY FROM ??.??) as ??', [table, column, alias]); + } + + return this.knex.raw('EXTRACT(DAY FROM ??.??)', [table, column]); } - weekday(table: string, column: string): Knex.Raw { - return this.knex.raw('EXTRACT(DOW FROM ??)', [column]); + weekday(table: string, column: string, alias?: string): Knex.Raw { + if (alias) { + return this.knex.raw('EXTRACT(DOW FROM ??.??) as ??', [table, column, alias]); + } + + return this.knex.raw('EXTRACT(DOW FROM ??.??)', [table, column]); } - hour(table: string, column: string): Knex.Raw { - return this.knex.raw('EXTRACT(HOUR FROM ??)', [column]); + hour(table: string, column: string, alias?: string): Knex.Raw { + if (alias) { + return this.knex.raw('EXTRACT(HOUR FROM ??.??) as ??', [table, column, alias]); + } + + return this.knex.raw('EXTRACT(HOUR FROM ??.??)', [table, column]); } - minute(table: string, column: string): Knex.Raw { - return this.knex.raw('EXTRACT(MINUTE FROM ??)', [column]); + minute(table: string, column: string, alias?: string): Knex.Raw { + if (alias) { + return this.knex.raw('EXTRACT(MINUTE FROM ??.??) as ??', [table, column, alias]); + } + + return this.knex.raw('EXTRACT(MINUTE FROM ??.??)', [table, column]); } - second(table: string, column: string): Knex.Raw { - return this.knex.raw('EXTRACT(SECOND FROM ??)', [column]); + second(table: string, column: string, alias?: string): Knex.Raw { + if (alias) { + return this.knex.raw('EXTRACT(SECOND FROM ??.??) as ??', [table, column, alias]); + } + + return this.knex.raw('EXTRACT(SECOND FROM ??.??)', [table, column]); } } diff --git a/api/src/database/run-ast.ts b/api/src/database/run-ast.ts index 19eb4fed3c..a220f79935 100644 --- a/api/src/database/run-ast.ts +++ b/api/src/database/run-ast.ts @@ -3,6 +3,7 @@ import { clone, cloneDeep, pick, uniq } from 'lodash'; import { PayloadService } from '../services/payload'; import { Item, Query, SchemaOverview } from '../types'; import { AST, FieldNode, NestedCollectionNode } from '../types/ast'; +import { applyFunctionToColumnName } from '../utils/apply-function-to-column-name'; import applyQuery from '../utils/apply-query'; import { getColumn } from '../utils/get-column'; import { stripFunction } from '../utils/strip-function'; @@ -419,7 +420,9 @@ function removeTemporaryFields( ); } - item = fields.length > 0 ? pick(rawItem, fields) : rawItem[primaryKeyField]; + const fieldsWithFunctionsApplied = fields.map((field) => applyFunctionToColumnName(field)); + + item = fields.length > 0 ? pick(rawItem, fieldsWithFunctionsApplied) : rawItem[primaryKeyField]; items.push(item); } diff --git a/api/src/utils/apply-function-to-column-name.ts b/api/src/utils/apply-function-to-column-name.ts new file mode 100644 index 0000000000..e7847950f6 --- /dev/null +++ b/api/src/utils/apply-function-to-column-name.ts @@ -0,0 +1,22 @@ +import { REGEX_BETWEEN_PARENS } from '../constants'; + +/** + * Takes in a column name, and transforms the original name with the generated column name based on + * the applied function. + * + * @example + * + * ```js + * applyFunctionToColumnName('year(date_created)'); + * // => "date_created_year" + * ``` + */ +export function applyFunctionToColumnName(column: string): string { + if (column.includes('(') && column.includes(')')) { + const functionName = column.split('(')[0]; + const columnName = column.match(REGEX_BETWEEN_PARENS)![1]; + return `${columnName}_${functionName}`; + } else { + return column; + } +} diff --git a/api/src/utils/get-column.ts b/api/src/utils/get-column.ts index 1d85a95655..4292b9f3ce 100644 --- a/api/src/utils/get-column.ts +++ b/api/src/utils/get-column.ts @@ -1,6 +1,7 @@ import { Knex } from 'knex'; import { FunctionsHelper } from '../database/functions'; import { REGEX_BETWEEN_PARENS } from '../constants'; +import { applyFunctionToColumnName } from './apply-function-to-column-name'; /** * Return column prefixed by table. If column includes functions (like `year(date_created)`, the @@ -9,9 +10,10 @@ import { REGEX_BETWEEN_PARENS } from '../constants'; * @param knex Current knex / transaction instance * @param collection Collection or alias in which column resides * @param field name of the column + * @param alias Whether or not to add a SQL AS statement * @returns Knex raw instance */ -export function getColumn(knex: Knex, table: string, column: string): Knex.Raw { +export function getColumn(knex: Knex, table: string, column: string, alias = true): Knex.Raw { const fn = FunctionsHelper(knex); if (column.includes('(') && column.includes(')')) { @@ -19,7 +21,11 @@ export function getColumn(knex: Knex, table: string, column: string): Knex.Raw { const columnName = column.match(REGEX_BETWEEN_PARENS)![1]; if (functionName in fn) { - return fn[functionName as keyof typeof fn](table, columnName); + return fn[functionName as keyof typeof fn]( + table, + columnName, + alias ? applyFunctionToColumnName(column) : undefined + ); } else { throw new Error(`Invalid function specified "${functionName}"`); } diff --git a/api/src/utils/strip-function.ts b/api/src/utils/strip-function.ts index 9d4364257f..fab6f7327b 100644 --- a/api/src/utils/strip-function.ts +++ b/api/src/utils/strip-function.ts @@ -5,7 +5,6 @@ import { REGEX_BETWEEN_PARENS } from '../constants'; */ export function stripFunction(field: string): string { if (field.includes('(') && field.includes(')')) { - console.log(field.match(REGEX_BETWEEN_PARENS)); return field.match(REGEX_BETWEEN_PARENS)![1].trim(); } else { return field;