diff --git a/grammar.js b/grammar.js index 88ea0ce..e3b52b2 100644 --- a/grammar.js +++ b/grammar.js @@ -6,6 +6,8 @@ module.exports = grammar({ /\s/, $.comment, $.marginalia, + $.jinja_comment, + $.jinja_statement, ], @@ -59,7 +61,10 @@ module.exports = grammar({ ), // optionally, a single statement without a terminating ; optional( - $.statement, + choice( + $.statement, + $._jinja_template_statement, + ), ), ), @@ -1054,6 +1059,7 @@ module.exports = grammar({ create_table: $ => prec.left( seq( $.keyword_create, + optional($._or_replace), optional( choice( $._temporary, @@ -3433,6 +3439,7 @@ module.exports = grammar({ $.between_expression, $.parenthesized_expression, $.object_id, + $.jinja_expression, ) ), @@ -3662,11 +3669,24 @@ module.exports = grammar({ $._identifier, $._double_quote_string, $._tsql_parameter, + $.jinja_expression, seq("`", $._identifier, "`"), ), _tsql_parameter: $ => seq('@', $._identifier), // support nordic chars and umlaue _identifier: _ => /[A-Za-z_\u00C0-\u017F][0-9A-Za-z_\u00C0-\u017F]*/, + + // Jinja template rules + _jinja_template_statement: $ => seq( + $.jinja_expression, + optional(seq( + optional($._cte), + $._select_statement, + )), + ), + jinja_comment: _ => /\{#[^#]*#*(?:[^}#][^#]*#+)*\}/, + jinja_statement: _ => /\{%[^%]*%+(?:[^}%][^%]*%+)*\}/, + jinja_expression: _ => /\{{2}[^{}](?:\{[^{}]*\})*[^{}]+\}{2}/, } }); diff --git a/package-lock.json b/package-lock.json index ff42d99..eb4660e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@derekstride/tree-sitter-sql", - "version": "0.3.8", + "version": "0.3.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@derekstride/tree-sitter-sql", - "version": "0.3.8", + "version": "0.3.11", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/queries/highlights.scm b/queries/highlights.scm index d64bd9d..6decb53 100644 --- a/queries/highlights.scm +++ b/queries/highlights.scm @@ -34,6 +34,10 @@ (comment) @comment @spell (marginalia) @comment +(jinja_comment) @comment +(jinja_statement) @string +(jinja_expression) @string + ((literal) @number (#match? @number "^[-+]?%d+$")) diff --git a/test/corpus/create.txt b/test/corpus/create.txt index 99eac2a..1d76249 100644 --- a/test/corpus/create.txt +++ b/test/corpus/create.txt @@ -1343,6 +1343,36 @@ CREATE TABLE tableName AS SELECT * FROM otherTable; (object_reference name: (identifier)))))))) +================================================================================ +Create or replace table as select +================================================================================ + +CREATE OR REPLACE TABLE tableName AS SELECT * FROM otherTable; + +-------------------------------------------------------------------------------- + +(program + (statement + (create_table + (keyword_create) + (keyword_or) + (keyword_replace) + (keyword_table) + (object_reference + name: (identifier)) + (keyword_as) + (create_query + (select + (keyword_select) + (select_expression + (term + value: (all_fields)))) + (from + (keyword_from) + (relation + (object_reference + name: (identifier)))))))) + ================================================================================ Create table as select with cte ================================================================================ diff --git a/test/corpus/jinja.txt b/test/corpus/jinja.txt new file mode 100644 index 0000000..603ae26 --- /dev/null +++ b/test/corpus/jinja.txt @@ -0,0 +1,250 @@ +================== +Jinja Comment Simple +================== +{# Single line comment #} +--- + +(program + (jinja_comment)) + +================== +Jinja Comment Multiline +================== +{# +This is a +multi-line +comment +#} +--- + +(program + (jinja_comment)) + +================== +Jinja with SQL comment inside +================== +{# SELECT * from users -- some comment inside the jinja #} +SELECT 1 +--- + +(program + (jinja_comment) + (statement + (select + (keyword_select) + (select_expression + (term + value: (literal)))))) + +================== +Jinja Nested in Jina comment +================== +{# outer {{ inner }} comment #} +--- + +(program + (jinja_comment)) + +================== +Jinja Statement Simple +================== +{% set my_var = 'value' %} +SELECT * FROM my_table +--- + +(program + (jinja_statement) + (statement + (select + (keyword_select) + (select_expression + (term + value: (all_fields)))) + (from + (keyword_from) + (relation + (object_reference + name: (identifier)))))) + +================== +Jinja Statement control flow +================== +SELECT + col1, + {% if condition %} + col2, + {% else %} + col3, + {% endif %} + col4 +FROM + my_table +--- + +(program + (statement + (select + (keyword_select) + (select_expression + (term + (field + (identifier))) + (jinja_statement) + (term + (field + (identifier))) + (jinja_statement) + (term + (field + (identifier))) + (jinja_statement) + (term + (field + (identifier))))) + (from + (keyword_from) + (relation + (object_reference + (identifier)))))) + +================== +Jinja Expression Simple +================== +SELECT {{ my_variable }} FROM my_table +--- + +(program + (statement + (select + (keyword_select) + (select_expression + (term + (jinja_expression)))) + (from + (keyword_from) + (relation + (object_reference + (identifier)))))) + +================== +Jinja Expression Simple no space +================== +SELECT {{my_variable}} FROM my_table +--- + +(program + (statement + (select + (keyword_select) + (select_expression + (term + (jinja_expression)))) + (from + (keyword_from) + (relation + (object_reference + (identifier)))))) + +================== +Jinja Expression as part of a longer expression +================== +SELECT a + {{ b }} FROM d +--- + +(program + (statement + (select + (keyword_select) + (select_expression + (term + value: (binary_expression + left: (field + name: (identifier)) + right: (jinja_expression))))) + (from + (keyword_from) + (relation + (object_reference + name: (identifier)))))) + +================== +Jinja Expression Multiline +================== +SELECT 1 FROM {{ + my_schema.my_table +}} WHERE a = 1 +--- + +(program + (statement + (select + (keyword_select) + (select_expression + (term + value: (literal)))) + (from + (keyword_from) + (relation + (object_reference + name: (identifier + (jinja_expression)))) + (where + (keyword_where) + predicate: (binary_expression + left: (field + name: (identifier)) + right: (literal)))))) + +================== +Jinja Expression Multiline CTAS +================== +{{ ctas_func( + type="temp", + schema="this_schema" +) }} +SELECT 1 FROM my_schema.my_table +WHERE a = 1 +--- + +(program + (jinja_expression) + (select + (keyword_select) + (select_expression + (term + value: (literal)))) + (from + (keyword_from) + (relation + (object_reference + schema: (identifier) + name: (identifier))) + (where + (keyword_where) + predicate: (binary_expression + left: (field + name: (identifier)) + right: (literal))))) + +================================================================================ +Jinja Expression: Alter role rename +================================================================================ + +ALTER ROLE {{ original_name }} RENAME TO {{ new_name }}; + +-------------------------------------------------------------------------------- + +(program + (statement + (alter_role + (keyword_alter) + (keyword_role) + (identifier + (jinja_expression)) + (rename_object + (keyword_rename) + (keyword_to) + (object_reference + (identifier + (jinja_expression))))))) +