Skip to content

Commit c4e4654

Browse files
committed
feat: support make_interval func in pg
1 parent 6610c9f commit c4e4654

4 files changed

Lines changed: 71 additions & 19 deletions

File tree

pegjs/postgresql.pegjs

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5006,8 +5006,37 @@ substring_funcs_clause
50065006
separator
50075007
}
50085008
}
5009+
5010+
make_interval_func_args_item
5011+
= n:('years'i / 'months'i / 'weeks'i / 'days'i / 'hours'i / 'mins'i) __ '=>' __ v:(integer / expr) {
5012+
// => { type: 'func_arg', value: { name: ident_name; symbol: '=>', value: literal_numeric; } }
5013+
return { type: 'func_arg', value: { name: n, symbol: '=>', expr: v } };
5014+
}
5015+
/ n:('secs'i) __ '=>' __ v:(double_float / expr) {
5016+
// => IGNORE
5017+
return { type: 'func_arg', value: { name: n, symbol: '=>', expr: v } };
5018+
}
5019+
5020+
make_interval_func_args
5021+
= head:make_interval_func_args_item tail:(__ COMMA __ make_interval_func_args_item)* {
5022+
// => make_interval_func_args_item[]
5023+
return { type: 'expr_list', value: createList(head, tail) };
5024+
}
5025+
/ expr_list
5026+
5027+
make_interval_func_clause
5028+
= name:'make_interval'i __ LPAREN __ l:make_interval_func_args __ RPAREN {
5029+
// => { type: 'function'; name: proc_func_name; args: make_interval_func_args; }
5030+
return {
5031+
type: 'function',
5032+
name: { name: [{ type: 'origin', value: name }] },
5033+
args: l,
5034+
...getLocationObject(),
5035+
}
5036+
}
5037+
50095038
func_call
5010-
= trim_func_clause / tablefunc_clause / substring_funcs_clause
5039+
= trim_func_clause / tablefunc_clause / substring_funcs_clause / make_interval_func_clause
50115040
/ name:'now'i __ LPAREN __ l:expr_list? __ RPAREN __ 'at'i __ KW_TIME __ 'zone'i __ z:literal_string {
50125041
// => { type: 'function'; name: proc_func_name; args: expr_list; suffix: literal_string; }
50135042
z.prefix = 'at time zone'
@@ -5338,49 +5367,52 @@ line_terminator
53385367
literal_numeric
53395368
= n:number {
53405369
// => number | { type: 'bigint'; value: string; }
5341-
if (n && n.type === 'bigint') return n
5370+
if (n && typeof n === 'object') return n
53425371
return { type: 'number', value: n };
53435372
}
53445373

5345-
number
5346-
= int_:int? frac:frac exp:exp {
5347-
const numStr = (int_ || '') + frac + exp
5374+
integer
5375+
= int_:int exp:exp {
5376+
// => IGNORE
5377+
const numStr = int_ + exp
53485378
return {
53495379
type: 'bigint',
53505380
value: numStr
53515381
}
53525382
}
5353-
/ int_:int? frac:frac {
5383+
/ int_:int {
53545384
// => IGNORE
5355-
const numStr = (int_ || '') + frac
5356-
if (int_ && isBigInt(int_)) return {
5385+
if (isBigInt(int_)) return {
53575386
type: 'bigint',
5358-
value: numStr
5387+
value: int_
53595388
}
5360-
return parseFloat(numStr);
5389+
return { type: 'number', value: parseFloat(int_) };
53615390
}
5362-
/ int_:int exp:exp {
5363-
// => IGNORE
5364-
const numStr = int_ + exp
5391+
double_float
5392+
= int_:int? frac:frac exp:exp {
5393+
const numStr = (int_ || '') + frac + exp
53655394
return {
53665395
type: 'bigint',
53675396
value: numStr
53685397
}
53695398
}
5370-
/ int_:int {
5399+
/ int_:int? frac:frac {
53715400
// => IGNORE
5372-
if (isBigInt(int_)) return {
5401+
const numStr = (int_ || '') + frac
5402+
if (int_ && isBigInt(int_)) return {
53735403
type: 'bigint',
5374-
value: int_
5404+
value: numStr
53755405
}
5376-
return parseFloat(int_);
5406+
return parseFloat(numStr);
53775407
}
5408+
number
5409+
= double_float / integer
53785410

53795411
int
53805412
= digits
53815413
/ digit:digit
53825414
/ op:("-" / "+" ) digits:digits { return op + digits; }
5383-
/ op:("-" / "+" ) digit:digit { return op + digit; }
5415+
/ op:("-" / "+" ) digit:digit { return op + digit; }
53845416

53855417
frac
53865418
= "." digits:digits { return "." + digits; }

src/expr.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { binaryToSQL } from './binary'
66
import { caseToSQL } from './case'
77
import { collateToSQL } from './collate'
88
import { columnDefinitionToSQL, columnRefToSQL, fullTextSearchToSQL } from './column'
9-
import { anyValueFuncToSQL, castToSQL, extractFunToSQL, flattenFunToSQL, funcToSQL, jsonObjectArgToSQL, lambdaToSQL, tablefuncFunToSQL } from './func'
9+
import { anyValueFuncToSQL, castToSQL, extractFunToSQL, flattenFunToSQL, funcArgToSQL, funcToSQL, jsonObjectArgToSQL, lambdaToSQL, tablefuncFunToSQL } from './func'
1010
import { intervalToSQL } from './interval'
1111
import { jsonExprToSQL, jsonVisitorExprToSQL } from './json'
1212
import { selectToSQL } from './select'
@@ -40,6 +40,7 @@ const exprToSQLConvertFn = {
4040
json : jsonExprToSQL,
4141
json_object_arg : jsonObjectArgToSQL,
4242
json_visitor : jsonVisitorExprToSQL,
43+
func_arg : funcArgToSQL,
4344
show : showToSQL,
4445
struct : arrayStructExprToSQL,
4546
tablefunc : tablefuncFunToSQL,

src/func.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ function flattenFunToSQL(stmt) {
8686
return `${toUpper(type)}(${argsStr})`
8787
}
8888

89+
function funcArgToSQL(argExpr) {
90+
const { name, symbol, expr } = argExpr.value
91+
return [name, symbol, exprToSQL(expr)].filter(hasVal).join(' ')
92+
}
93+
8994
function funcToSQL(expr) {
9095
const { args, array_index, name, args_parentheses, parentheses, over, suffix } = expr
9196
const overStr = overToSQL(over)
@@ -132,6 +137,7 @@ export {
132137
castToSQL,
133138
extractFunToSQL,
134139
flattenFunToSQL,
140+
funcArgToSQL,
135141
funcToSQL,
136142
jsonObjectArgToSQL,
137143
lambdaToSQL,

test/postgres.spec.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,6 +1748,19 @@ describe('Postgres', () => {
17481748
'DROP VIEW "view_name"'
17491749
]
17501750
},
1751+
{
1752+
title: 'make interval func',
1753+
sql: [
1754+
`SELECT
1755+
gid,
1756+
'2020-01-01 00:00:00'::TIMESTAMP WITH TIME ZONE + make_interval(secs => (
1757+
(gid - (SELECT min(gid) FROM nyct20))::FLOAT / (SELECT max(gid) - min(gid) FROM nyct20)) * 31536000 -- One year in seconds
1758+
) AS generated_timestamp
1759+
FROM
1760+
nyct20;`,
1761+
`SELECT gid, '2020-01-01 00:00:00'::TIMESTAMP WITH TIME ZONE + MAKE_INTERVAL(secs => ((gid - (SELECT MIN(gid) FROM "nyct20"))::FLOAT / (SELECT MAX(gid) - MIN(gid) FROM "nyct20")) * 31536000) AS "generated_timestamp" FROM "nyct20"`
1762+
]
1763+
},
17511764
]
17521765
function neatlyNestTestedSQL(sqlList){
17531766
sqlList.forEach(sqlInfo => {

0 commit comments

Comments
 (0)