From 77cffe8a0bcbef469b3cfcbedf61f78306632056 Mon Sep 17 00:00:00 2001 From: Felipe Zorzo Date: Sun, 29 Sep 2024 23:41:11 -0300 Subject: [PATCH] feat(grammar): Support alternative syntax for json_object (JSON { }) and json_array (JSON [ ]) Reference: "JSON Data Type Constructor" on https://docs.oracle.com/en/database/oracle/oracle-database/23/adjsn/generation.html --- .../oracle-database_23/ParsingErrorCheck.json | 23 +-------------- .../plugins/plsqlopen/api/PlSqlPunctuator.kt | 2 ++ .../api/SingleRowSqlFunctionsGrammar.kt | 28 +++++++++++++------ .../api/expressions/JsonArrayTest.kt | 17 +++++------ .../expressions/JsonObjectExpressionTest.kt | 13 +++++++++ 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/zpa-checks/src/integrationTest/resources/expected/oracle-database_23/ParsingErrorCheck.json b/zpa-checks/src/integrationTest/resources/expected/oracle-database_23/ParsingErrorCheck.json index f38112b1..9ff6d7ee 100644 --- a/zpa-checks/src/integrationTest/resources/expected/oracle-database_23/ParsingErrorCheck.json +++ b/zpa-checks/src/integrationTest/resources/expected/oracle-database_23/ParsingErrorCheck.json @@ -29,33 +29,12 @@ "adjsn/function-JSON_VALUE-3.sql" : [ 4 ], - "adjsn/generation-14.sql" : [ - 2 - ], - "adjsn/generation-17.sql" : [ - 2 - ], - "adjsn/generation-20.sql" : [ - 2 - ], "adjsn/generation-21.sql" : [ 3 ], - "adjsn/generation-25.sql" : [ - 2 - ], "adjsn/generation-28.sql" : [ 2 ], - "adjsn/generation-31.sql" : [ - 2 - ], - "adjsn/generation-33.sql" : [ - 2 - ], - "adjsn/generation-39.sql" : [ - 4 - ], "adjsn/in-memory-json-data-1.sql" : [ 6 ], @@ -3306,7 +3285,7 @@ 4 ], "sqlrf/value-expressions-graph_table-8.sql" : [ - 4 + 5 ], "sqlrf/vector_chunks-1.sql" : [ 14 diff --git a/zpa-core/src/main/kotlin/org/sonar/plugins/plsqlopen/api/PlSqlPunctuator.kt b/zpa-core/src/main/kotlin/org/sonar/plugins/plsqlopen/api/PlSqlPunctuator.kt index e34fb525..6c16b6b1 100644 --- a/zpa-core/src/main/kotlin/org/sonar/plugins/plsqlopen/api/PlSqlPunctuator.kt +++ b/zpa-core/src/main/kotlin/org/sonar/plugins/plsqlopen/api/PlSqlPunctuator.kt @@ -53,6 +53,8 @@ enum class PlSqlPunctuator(override val value: String) : TokenType { CARET("^"), LBRACKET("["), RBRACKET("]"), + LBRACE("{"), + RBRACE("}"), QUESTION_MARK("?"); override fun hasToBeSkippedFromAst(node: AstNode?) = false diff --git a/zpa-core/src/main/kotlin/org/sonar/plugins/plsqlopen/api/SingleRowSqlFunctionsGrammar.kt b/zpa-core/src/main/kotlin/org/sonar/plugins/plsqlopen/api/SingleRowSqlFunctionsGrammar.kt index 08952d91..bfffa210 100644 --- a/zpa-core/src/main/kotlin/org/sonar/plugins/plsqlopen/api/SingleRowSqlFunctionsGrammar.kt +++ b/zpa-core/src/main/kotlin/org/sonar/plugins/plsqlopen/api/SingleRowSqlFunctionsGrammar.kt @@ -36,6 +36,7 @@ enum class SingleRowSqlFunctionsGrammar : GrammarRuleKey { JSON_ARRAY_ENUMERATION_CONTENT, JSON_ARRAY_QUERY_CONTENT, JSON_ARRAY_ELEMENT, + JSON_ARRAY_OPTIONS, JSON_OBJECT_ENTRY, JSON_QUERY_RETURNING_CLAUSE, JSON_QUERY_WRAPPER_CLAUSE, @@ -75,6 +76,7 @@ enum class SingleRowSqlFunctionsGrammar : GrammarRuleKey { JSON_MERGE_OPERATION, JSON_MINUS_OPERATION, JSON_NESTED_PATH_OPERATION, + JSON_OBJECT_OPTIONS, JSON_PREPEND_OPERATION, JSON_REMOVE_OPERATION, JSON_RENAME_OPERATION, @@ -489,11 +491,15 @@ enum class SingleRowSqlFunctionsGrammar : GrammarRuleKey { private fun createJsonFunctions(b: PlSqlGrammarBuilder) { b.rule(JSON_CONSTRUCTOR).define(JSON, LPARENTHESIS, EXPRESSION, RPARENTHESIS) + b.rule(JSON_ARRAY_OPTIONS).define( + b.firstOf(JSON_ARRAY_ENUMERATION_CONTENT, JSON_ARRAY_QUERY_CONTENT) + ).skip() + b.rule(JSON_ARRAY_EXPRESSION).define( - JSON_ARRAY, - LPARENTHESIS, - b.firstOf(JSON_ARRAY_ENUMERATION_CONTENT, JSON_ARRAY_QUERY_CONTENT), - RPARENTHESIS + b.firstOf( + b.sequence(JSON_ARRAY, LPARENTHESIS, JSON_ARRAY_OPTIONS, RPARENTHESIS), + b.sequence(b.optional(JSON), LBRACKET, JSON_ARRAY_OPTIONS, RBRACKET) + ) ) b.rule(JSON_ARRAY_ENUMERATION_CONTENT).define( @@ -557,15 +563,19 @@ enum class SingleRowSqlFunctionsGrammar : GrammarRuleKey { b.optional(STRICT) ) - b.rule(JSON_OBJECT_EXPRESSION).define( - JSON_OBJECT, - LPARENTHESIS, + b.rule(JSON_OBJECT_OPTIONS).define( JSON_OBJECT_ENTRY, b.zeroOrMore(COMMA, JSON_OBJECT_ENTRY), b.optional(JSON_ON_NULL_CLAUSE), b.optional(JSON_RETURNING_CLAUSE), b.optional(STRICT), - b.optional(WITH, UNIQUE, KEYS), - RPARENTHESIS + b.optional(WITH, UNIQUE, KEYS) + ).skip() + + b.rule(JSON_OBJECT_EXPRESSION).define( + b.firstOf( + b.sequence(JSON_OBJECT, LPARENTHESIS, JSON_OBJECT_OPTIONS, RPARENTHESIS), + b.sequence(b.optional(JSON), LBRACE, JSON_OBJECT_OPTIONS, RBRACE) + ) ) b.rule(JSON_OBJECT_ENTRY).define( diff --git a/zpa-core/src/test/kotlin/org/sonar/plugins/plsqlopen/api/expressions/JsonArrayTest.kt b/zpa-core/src/test/kotlin/org/sonar/plugins/plsqlopen/api/expressions/JsonArrayTest.kt index 7222510f..ee6dbb13 100644 --- a/zpa-core/src/test/kotlin/org/sonar/plugins/plsqlopen/api/expressions/JsonArrayTest.kt +++ b/zpa-core/src/test/kotlin/org/sonar/plugins/plsqlopen/api/expressions/JsonArrayTest.kt @@ -74,17 +74,14 @@ class JsonArrayTest : RuleTest() { @Test fun matchesJsonArrayFromQuery() { - /* - * This syntax is listed on the JSON_ARRAY docs for Oracle 23ai: - * https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/JSON_ARRAY.html - * - * However, according to the table "Table C-2 Oracle Support for Optional Features of SQL/Foundation" - * it isn't supported yet: - * T811, Basic SQL/JSON constructor functions - * Oracle fully supports this feature, except for the JSON_ARRAY constructor by query. - * https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/Oracle-Support-for-Optional-Features-of-SQLFoundation2011.html. - */ assertThat(p).matches("json_array(select * from tab null on null returning json strict)") } + @Test + fun matchesAlternativeSyntaxOfJsonArray() { + assertThat(p).matches("json[1] ") + assertThat(p).matches("json[json[1,2,3], 100, 'test', null null on null returning json strict]") + assertThat(p).matches("json[select * from tab]") + } + } diff --git a/zpa-core/src/test/kotlin/org/sonar/plugins/plsqlopen/api/expressions/JsonObjectExpressionTest.kt b/zpa-core/src/test/kotlin/org/sonar/plugins/plsqlopen/api/expressions/JsonObjectExpressionTest.kt index da11bb65..5192afe1 100644 --- a/zpa-core/src/test/kotlin/org/sonar/plugins/plsqlopen/api/expressions/JsonObjectExpressionTest.kt +++ b/zpa-core/src/test/kotlin/org/sonar/plugins/plsqlopen/api/expressions/JsonObjectExpressionTest.kt @@ -76,4 +76,17 @@ class JsonObjectExpressionTest : RuleTest() { strict with unique keys)""") } + @Test + fun matchesAlternativeSyntaxOfJsonObject() { + assertThat(p).matches("json { foo }") + assertThat(p).matches("json { 'k': 'v' }") + assertThat(p).matches( + """json { 'k' value 'v', + 'a': '{}' format json + null on null + returning varchar2(200) + strict with unique keys }""" + ) + } + }