Repository: GoogleCloudPlatform/pgadapter
Pull request #382 (2022-10-10 12:32:52)

feat: added support for Django specific statement

codecov[bot]: # [Codecov](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/382?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform) Report
> Merging [#382](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/382?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform) (b407ed8) into [postgresql-dialect](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/commit/86e4f39253214bbb64e34e1e7a63aceaf9c6e516?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform) (86e4f39) will **increase** coverage by `0.01%`.
> The diff coverage is `100.00%`.

> :exclamation: Current head b407ed8 differs from pull request most recent head 922ccf1. Consider uploading reports for the commit 922ccf1 to get more accurate results

```diff
@@                   Coverage Diff                    @@
##             postgresql-dialect     #382      +/-   ##
========================================================
+ Coverage                 86.38%   86.39%   +0.01%     
- Complexity                 1841     1844       +3     
========================================================
  Files                       121      122       +1     
  Lines                      6050     6058       +8     
  Branches                    836      836              
========================================================
+ Hits                       5226     5234       +8     
  Misses                      592      592              
  Partials                    232      232              
```

| Flag | Coverage Δ | |
|---|---|---|
| all_tests | `86.39% <100.00%> (+0.01%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/382?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform) | Coverage Δ | |
|---|---|---|
| [...ud/spanner/pgadapter/utils/ClientAutoDetector.java](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/382/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform#diff-c3JjL21haW4vamF2YS9jb20vZ29vZ2xlL2Nsb3VkL3NwYW5uZXIvcGdhZGFwdGVyL3V0aWxzL0NsaWVudEF1dG9EZXRlY3Rvci5qYXZh) | `93.18% <ø> (ø)` | |
| [...pter/statements/local/DjangoSpecificStatement.java](https://codecov.io/gh/GoogleCloudPlatform/pgadapter/pull/382/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform#diff-c3JjL21haW4vamF2YS9jb20vZ29vZ2xlL2Nsb3VkL3NwYW5uZXIvcGdhZGFwdGVyL3N0YXRlbWVudHMvbG9jYWwvRGphbmdvU3BlY2lmaWNTdGF0ZW1lbnQuamF2YQ==) | `100.00% <100.00%> (ø)` | |

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=GoogleCloudPlatform)


Patch:
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesStatement.java b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesStatement.java
new file mode 100644
index 00000000..f9200501
--- /dev/null
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesStatement.java
@@ -0,0 +1,70 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.cloud.spanner.pgadapter.statements.local;
+
+import com.google.api.core.InternalApi;
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.ResultSets;
+import com.google.cloud.spanner.Type;
+import com.google.cloud.spanner.Type.StructField;
+import com.google.cloud.spanner.connection.StatementResult;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection.QueryResult;
+import com.google.common.collect.ImmutableList;
+
+/*
+ * Django sends this statement to get the list of all the relations present in the database.
+ * After getting that list, Django searches for django_migrations table to check if it can perform migrations
+ * Since we will be returning an empty resultset, Django will not perform migrations as it won't find the django_migrations table.
+ * And this behavior shown by the Django is the intended behaviour because anyway we don't support migrations.
+ * */
+
+@InternalApi
+public class DjangoGetTableNamesStatement implements LocalStatement {
+  public static final DjangoGetTableNamesStatement INSTANCE = new DjangoGetTableNamesStatement();
+
+  private DjangoGetTableNamesStatement() {}
+
+  @Override
+  public String[] getSql() {
+    return new String[] {
+      "\n"
+          + "            SELECT\n"
+          + "                c.relname,\n"
+          + "                CASE\n"
+          + "                    WHEN c.relispartition THEN 'p'\n"
+          + "                    WHEN c.relkind IN ('m', 'v') THEN 'v'\n"
+          + "                    ELSE 't'\n"
+          + "                END\n"
+          + "            FROM pg_catalog.pg_class c\n"
+          + "            LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
+          + "            WHERE c.relkind IN ('f', 'm', 'p', 'r', 'v')\n"
+          + "                AND n.nspname NOT IN ('pg_catalog', 'pg_toast')\n"
+          + "                AND pg_catalog.pg_table_is_visible(c.oid)\n"
+          + "        "
+    };
+  }
+
+  @Override
+  public StatementResult execute(BackendConnection backendConnection) {
+    ResultSet resultSet =
+        ResultSets.forRows(
+            Type.struct(
+                StructField.of("relname", Type.string()), StructField.of("case", Type.string())),
+            ImmutableList.of());
+
+    return new QueryResult(resultSet);
+  }
+}
diff --git a/src/main/java/com/google/cloud/spanner/pgadapter/utils/ClientAutoDetector.java b/src/main/java/com/google/cloud/spanner/pgadapter/utils/ClientAutoDetector.java
index 1cfb94a8..e53fa52d 100644
--- a/src/main/java/com/google/cloud/spanner/pgadapter/utils/ClientAutoDetector.java
+++ b/src/main/java/com/google/cloud/spanner/pgadapter/utils/ClientAutoDetector.java
@@ -16,6 +16,7 @@ package com.google.cloud.spanner.pgadapter.utils;
 
 import com.google.api.core.InternalApi;
 import com.google.cloud.spanner.pgadapter.ConnectionHandler;
+import com.google.cloud.spanner.pgadapter.statements.local.DjangoGetTableNamesStatement;
 import com.google.cloud.spanner.pgadapter.statements.local.ListDatabasesStatement;
 import com.google.cloud.spanner.pgadapter.statements.local.LocalStatement;
 import com.google.cloud.spanner.pgadapter.statements.local.SelectCurrentCatalogStatement;
@@ -39,7 +40,8 @@ public class ClientAutoDetector {
       ImmutableList.of(
           SelectCurrentSchemaStatement.INSTANCE,
           SelectCurrentDatabaseStatement.INSTANCE,
-          SelectCurrentCatalogStatement.INSTANCE);
+          SelectCurrentCatalogStatement.INSTANCE,
+          DjangoGetTableNamesStatement.INSTANCE);
 
   public enum WellKnownClient {
     PSQL {


Test patch:
diff --git a/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesTest.java b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesTest.java
new file mode 100644
index 00000000..17fe8a4e
--- /dev/null
+++ b/src/test/java/com/google/cloud/spanner/pgadapter/statements/local/DjangoGetTableNamesTest.java
@@ -0,0 +1,70 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.cloud.spanner.pgadapter.statements.local;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.mock;
+
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.Type;
+import com.google.cloud.spanner.connection.StatementResult;
+import com.google.cloud.spanner.pgadapter.statements.BackendConnection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class DjangoGetTableNamesTest {
+
+  private String djangoGetTableNamesSql =
+      "\n"
+          + "            SELECT\n"
+          + "                c.relname,\n"
+          + "                CASE\n"
+          + "                    WHEN c.relispartition THEN 'p'\n"
+          + "                    WHEN c.relkind IN ('m', 'v') THEN 'v'\n"
+          + "                    ELSE 't'\n"
+          + "                END\n"
+          + "            FROM pg_catalog.pg_class c\n"
+          + "            LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
+          + "            WHERE c.relkind IN ('f', 'm', 'p', 'r', 'v')\n"
+          + "                AND n.nspname NOT IN ('pg_catalog', 'pg_toast')\n"
+          + "                AND pg_catalog.pg_table_is_visible(c.oid)\n"
+          + "        ";
+
+  @Test
+  public void testGetSql() {
+    DjangoGetTableNamesStatement djangoGetTableNamesStatement =
+        DjangoGetTableNamesStatement.INSTANCE;
+    String djangoGetTableNamesStatementsList[] = djangoGetTableNamesStatement.getSql();
+    assertEquals(1, djangoGetTableNamesStatementsList.length);
+    assertEquals(djangoGetTableNamesSql, djangoGetTableNamesStatementsList[0]);
+  }
+
+  @Test
+  public void testExecute() {
+    BackendConnection backendConnection = mock(BackendConnection.class);
+
+    DjangoGetTableNamesStatement djangoGetTableNamesStatement =
+        DjangoGetTableNamesStatement.INSTANCE;
+    StatementResult statementResult = djangoGetTableNamesStatement.execute(backendConnection);
+    ResultSet resultSet = statementResult.getResultSet();
+    assertFalse(resultSet.next());
+    assertEquals(2, resultSet.getColumnCount());
+    assertEquals(Type.string(), resultSet.getColumnType("relname"));
+    assertEquals(Type.string(), resultSet.getColumnType("case"));
+  }
+}