Skip to content

Commit 02adf24

Browse files
authored
Support complex expressions inside BETWEEN (#525)
2 parents 08eb2b1 + c2e777f commit 02adf24

File tree

3 files changed

+37
-3
lines changed

3 files changed

+37
-3
lines changed

src/parser/createParser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export function createParser(tokenizer: Tokenizer): Parser {
3939
// but I haven't found a way to get this info from Nearley :(
4040
throw new Error('Parse error: Invalid SQL');
4141
} else {
42-
throw new Error('Parse error: Ambiguous grammar');
42+
throw new Error(`Parse error: Ambiguous grammar\n${JSON.stringify(results, undefined, 2)}`);
4343
}
4444
},
4545
};

src/parser/grammar.ne

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,19 @@ const addComments = (node: AstNode, { leading, trailing }: CommentAttachments):
3838
return node;
3939
};
4040

41+
const addCommentsToArray = (nodes: AstNode[], { leading, trailing }: CommentAttachments): AstNode[] => {
42+
if (leading?.length) {
43+
const [first, ...rest] = nodes;
44+
nodes = [addComments(first, { leading }), ...rest];
45+
}
46+
if (trailing?.length) {
47+
const lead = nodes.slice(0, -1);
48+
const last = nodes[nodes.length-1];
49+
nodes = [...lead, addComments(last, { trailing })];
50+
}
51+
return nodes;
52+
};
53+
4154
%}
4255
@lexer lexer
4356

@@ -137,10 +150,18 @@ set_operation -> %RESERVED_SET_OPERATION free_form_sql:* {%
137150

138151
expression_chain_ -> expression_with_comments_:+ {% id %}
139152

153+
expression_chain -> expression _expression_with_comments:* {%
154+
([expr, chain]) => [expr, ...chain]
155+
%}
156+
140157
expression_with_comments_ -> expression _ {%
141158
([expr, _]) => addComments(expr, { trailing: _ })
142159
%}
143160

161+
_expression_with_comments -> _ expression {%
162+
([_, expr]) => addComments(expr, { leading: _ })
163+
%}
164+
144165
free_form_sql -> ( asteriskless_free_form_sql | asterisk ) {% unwrap %}
145166

146167
asteriskless_free_form_sql ->
@@ -230,11 +251,11 @@ property_access -> expression _ %DOT _ (identifier | array_subscript | all_colum
230251
}
231252
%}
232253

233-
between_predicate -> %BETWEEN _ expression _ %AND _ expression {%
254+
between_predicate -> %BETWEEN _ expression_chain _ %AND _ expression {%
234255
([betweenToken, _1, expr1, _2, andToken, _3, expr2]) => ({
235256
type: NodeType.between_predicate,
236257
betweenKw: toKeywordNode(betweenToken),
237-
expr1: [addComments(expr1, { leading: _1, trailing: _2 })],
258+
expr1: addCommentsToArray(expr1, { leading: _1, trailing: _2 }),
238259
andKw: toKeywordNode(andToken),
239260
expr2: [addComments(expr2, { leading: _3 })],
240261
})

test/features/between.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,17 @@ export default function supportsBetween(format: FormatFn) {
1616
foo BETWEEN /*C1*/ t.bar /*C2*/ AND /*C3*/ t.baz
1717
`);
1818
});
19+
20+
it('supports complex expressions inside BETWEEN', () => {
21+
// Not ideal, but better than crashing
22+
expect(format('foo BETWEEN 1+2 AND 3+4')).toBe('foo BETWEEN 1 + 2 AND 3 + 4');
23+
});
24+
25+
it('supports CASE inside BETWEEN', () => {
26+
expect(format('foo BETWEEN CASE x WHEN 1 THEN 2 END AND 3')).toBe(dedent`
27+
foo BETWEEN CASE x
28+
WHEN 1 THEN 2
29+
END AND 3
30+
`);
31+
});
1932
}

0 commit comments

Comments
 (0)