This is an automated email from the ASF dual-hosted git repository.

bchapuis pushed a commit to branch calcite-schema-ddl
in repository https://gitbox.apache.org/repos/asf/incubator-baremaps.git

commit e37d95e23cea5903d9bccc82d34aa8362f8ac568
Author: Bertil Chapuis <[email protected]>
AuthorDate: Mon Apr 14 17:49:38 2025 +0200

    Add RPSL schema and tests
---
 .../apache/baremaps/calcite/rpsl/RpslSchema.java   | 155 +++++++++++++++++++++
 .../baremaps/calcite/rpsl/RpslSchemaTest.java      | 151 ++++++++++++++++++++
 .../baremaps/calcite/rpsl/RpslTableTest.java       |   2 +-
 .../org/apache/baremaps/iploc/IpLocObjectTest.java |   2 +-
 .../org/apache/baremaps/rpsl/RpslObjectTest.java   |   2 +-
 .../org/apache/baremaps/rpsl/RpslParserTest.java   |   4 +-
 baremaps-testing/data/{ripe => rpsl}/sample.txt    |   0
 .../org/apache/baremaps/testing/TestFiles.java     |   4 +-
 8 files changed, 313 insertions(+), 7 deletions(-)

diff --git 
a/baremaps-calcite/src/main/java/org/apache/baremaps/calcite/rpsl/RpslSchema.java
 
b/baremaps-calcite/src/main/java/org/apache/baremaps/calcite/rpsl/RpslSchema.java
new file mode 100644
index 000000000..e5f98af3c
--- /dev/null
+++ 
b/baremaps-calcite/src/main/java/org/apache/baremaps/calcite/rpsl/RpslSchema.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * 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 org.apache.baremaps.calcite.rpsl;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.schema.Table;
+import org.apache.calcite.schema.impl.AbstractSchema;
+
+/**
+ * A Calcite schema implementation for RPSL data. This schema provides access 
to RPSL files
+ * through the Apache Calcite framework for SQL querying.
+ */
+public class RpslSchema extends AbstractSchema {
+
+  private final File directory;
+  private final Map<String, Table> tableMap;
+  private final RelDataTypeFactory typeFactory;
+
+  /**
+   * Constructs a RpslSchema with the specified directory.
+   *
+   * @param directory the directory containing RPSL files
+   * @param typeFactory the type factory to use for creating tables
+   * @throws IOException if an I/O error occurs
+   */
+  public RpslSchema(File directory, RelDataTypeFactory typeFactory) throws 
IOException {
+    this.directory = Objects.requireNonNull(directory, "Directory cannot be 
null");
+    this.typeFactory = Objects.requireNonNull(typeFactory, "Type factory 
cannot be null");
+    this.tableMap = new HashMap<>();
+
+    // Process files in the directory
+    File[] files = directory.listFiles((dir, name) -> 
+        name.toLowerCase().endsWith(".rpsl") || 
name.toLowerCase().endsWith(".txt"));
+    
+    if (files != null) {
+      for (File file : files) {
+        // Extract the base name without extension (e.g., "routing" from 
"routing.rpsl")
+        String fileName = file.getName();
+        String tableName = fileName;
+        
+        // Remove all extensions (e.g., "routing.rpsl" -> "routing")
+        while (tableName.contains(".")) {
+          int lastDotIndex = tableName.lastIndexOf('.');
+          if (lastDotIndex > 0) {
+            tableName = tableName.substring(0, lastDotIndex);
+          } else {
+            break;
+          }
+        }
+        
+        // Create the table with the file reference
+        tableMap.put(tableName, createTable(file));
+      }
+    }
+  }
+
+  /**
+   * Constructs a RpslSchema with a single file.
+   *
+   * @param file the RPSL file
+   * @param typeFactory the type factory to use for creating tables
+   * @throws IOException if an I/O error occurs
+   */
+  public RpslSchema(File file, RelDataTypeFactory typeFactory, boolean 
isDirectory) throws IOException {
+    if (isDirectory) {
+      // If isDirectory is true, treat the file as a directory
+      this.directory = Objects.requireNonNull(file, "Directory cannot be 
null");
+      this.typeFactory = Objects.requireNonNull(typeFactory, "Type factory 
cannot be null");
+      this.tableMap = new HashMap<>();
+
+      // Process files in the directory
+      File[] files = file.listFiles((dir, name) -> 
+          name.toLowerCase().endsWith(".rpsl") || 
name.toLowerCase().endsWith(".txt"));
+      
+      if (files != null) {
+        for (File rpslFile : files) {
+          // Extract the base name without extension (e.g., "routing" from 
"routing.rpsl")
+          String fileName = rpslFile.getName();
+          String tableName = fileName;
+          
+          // Remove all extensions (e.g., "routing.rpsl" -> "routing")
+          while (tableName.contains(".")) {
+            int lastDotIndex = tableName.lastIndexOf('.');
+            if (lastDotIndex > 0) {
+              tableName = tableName.substring(0, lastDotIndex);
+            } else {
+              break;
+            }
+          }
+          
+          // Create the table with the file reference
+          tableMap.put(tableName, createTable(rpslFile));
+        }
+      }
+    } else {
+      // If isDirectory is false, treat the file as a single file
+      this.directory = Objects.requireNonNull(file, "File cannot be null");
+      this.typeFactory = Objects.requireNonNull(typeFactory, "Type factory 
cannot be null");
+      this.tableMap = new HashMap<>();
+
+      // Extract the base name without extension (e.g., "routing" from 
"routing.rpsl")
+      String fileName = file.getName();
+      String tableName = fileName;
+      
+      // Remove all extensions (e.g., "routing.rpsl" -> "routing")
+      while (tableName.contains(".")) {
+        int lastDotIndex = tableName.lastIndexOf('.');
+        if (lastDotIndex > 0) {
+          tableName = tableName.substring(0, lastDotIndex);
+        } else {
+          break;
+        }
+      }
+      
+      // Create the table with the file reference
+      tableMap.put(tableName, createTable(file));
+    }
+  }
+
+  /**
+   * Creates a table for the given file.
+   *
+   * @param file the RPSL file
+   * @return the created table
+   * @throws IOException if an I/O error occurs
+   */
+  private Table createTable(File file) throws IOException {
+    return new RpslTable(file);
+  }
+
+  @Override
+  protected Map<String, Table> getTableMap() {
+    return tableMap;
+  }
+} 
\ No newline at end of file
diff --git 
a/baremaps-calcite/src/test/java/org/apache/baremaps/calcite/rpsl/RpslSchemaTest.java
 
b/baremaps-calcite/src/test/java/org/apache/baremaps/calcite/rpsl/RpslSchemaTest.java
new file mode 100644
index 000000000..276880127
--- /dev/null
+++ 
b/baremaps-calcite/src/test/java/org/apache/baremaps/calcite/rpsl/RpslSchemaTest.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * 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 org.apache.baremaps.calcite.rpsl;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import org.apache.baremaps.testing.TestFiles;
+import org.apache.calcite.config.CalciteConnectionConfig;
+import org.apache.calcite.config.CalciteConnectionConfigImpl;
+import org.apache.calcite.config.CalciteConnectionProperty;
+import org.apache.calcite.jdbc.CalciteConnection;
+import org.apache.calcite.rel.type.RelDataTypeFactory;
+import org.apache.calcite.schema.SchemaPlus;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+/**
+ * Test class for the RpslSchema implementation.
+ */
+public class RpslSchemaTest {
+
+  @TempDir
+  Path tempDir;
+
+  @BeforeEach
+  public void setup() throws SQLException, IOException {
+    // Create a temporary directory for test files
+    Path testDir = tempDir.resolve("rpsl-test");
+    Files.createDirectories(testDir);
+
+    // Copy the sample RPSL file from TestFiles
+    Path sourceFile = TestFiles.RPSL_TXT;
+    Path targetFile = testDir.resolve("sample.txt");
+    Files.copy(sourceFile, targetFile, StandardCopyOption.REPLACE_EXISTING);
+  }
+
+  @Test
+  public void testSchemaCreation() throws SQLException, IOException {
+    // Create a connection to Calcite
+    Connection connection = DriverManager.getConnection("jdbc:calcite:");
+    CalciteConnection calciteConnection = 
connection.unwrap(CalciteConnection.class);
+    SchemaPlus rootSchema = calciteConnection.getRootSchema();
+
+    // Create and register the RPSL schema
+    RpslSchema schema = new RpslSchema(tempDir.resolve("rpsl-test").toFile(), 
calciteConnection.getTypeFactory());
+    rootSchema.add("rpsl", schema);
+
+    // Verify that the schema contains the expected table
+    assertTrue(rootSchema.getSubSchemaNames().contains("rpsl"));
+    
assertTrue(rootSchema.getSubSchema("rpsl").getTableNames().contains("sample"));
+
+    connection.close();
+  }
+
+  @Test
+  public void testSqlQuery() throws SQLException, IOException {
+    // Create a connection to Calcite
+    Connection connection = DriverManager.getConnection("jdbc:calcite:");
+    CalciteConnection calciteConnection = 
connection.unwrap(CalciteConnection.class);
+    SchemaPlus rootSchema = calciteConnection.getRootSchema();
+
+    // Create and register the RPSL schema
+    RpslSchema schema = new RpslSchema(tempDir.resolve("rpsl-test").toFile(), 
calciteConnection.getTypeFactory());
+    rootSchema.add("rpsl", schema);
+
+    // Execute a simple SQL query - use lowercase for schema and table names
+    try (Statement statement = connection.createStatement()) {
+      ResultSet resultSet = statement.executeQuery(
+          "SELECT * FROM \"rpsl\".\"sample\"");
+
+      // Verify that we get results
+      assertTrue(resultSet.next());
+      
+      // Verify that the result set has the expected columns
+      assertNotNull(resultSet.getMetaData());
+      assertTrue(resultSet.getMetaData().getColumnCount() > 0);
+      
+      // Verify that we can access the data
+      String inetnum = resultSet.getString("inetnum");
+      assertNotNull(inetnum);
+    }
+
+    connection.close();
+  }
+
+  @Test
+  public void testSingleFileSchema() throws SQLException, IOException {
+    // Create a connection to Calcite
+    Connection connection = DriverManager.getConnection("jdbc:calcite:");
+    CalciteConnection calciteConnection = 
connection.unwrap(CalciteConnection.class);
+    SchemaPlus rootSchema = calciteConnection.getRootSchema();
+
+    // Get the sample RPSL file
+    File sampleFile = 
tempDir.resolve("rpsl-test").resolve("sample.txt").toFile();
+
+    // Create and register the RPSL schema with a single file
+    RpslSchema schema = new RpslSchema(sampleFile, 
calciteConnection.getTypeFactory(), false);
+    rootSchema.add("single", schema);
+
+    // Verify that the schema contains the expected table
+    assertTrue(rootSchema.getSubSchemaNames().contains("single"));
+    
assertTrue(rootSchema.getSubSchema("single").getTableNames().contains("sample"));
+
+    // Execute a simple SQL query - use lowercase for schema and table names
+    try (Statement statement = connection.createStatement()) {
+      ResultSet resultSet = statement.executeQuery(
+          "SELECT * FROM \"single\".\"sample\"");
+
+      // Verify that we get results
+      assertTrue(resultSet.next());
+      
+      // Verify that the result set has the expected columns
+      assertNotNull(resultSet.getMetaData());
+      assertTrue(resultSet.getMetaData().getColumnCount() > 0);
+      
+      // Verify that we can access the data
+      String inetnum = resultSet.getString("inetnum");
+      assertNotNull(inetnum);
+    }
+
+    connection.close();
+  }
+} 
\ No newline at end of file
diff --git 
a/baremaps-calcite/src/test/java/org/apache/baremaps/calcite/rpsl/RpslTableTest.java
 
b/baremaps-calcite/src/test/java/org/apache/baremaps/calcite/rpsl/RpslTableTest.java
index 846ce1e08..be7558c34 100644
--- 
a/baremaps-calcite/src/test/java/org/apache/baremaps/calcite/rpsl/RpslTableTest.java
+++ 
b/baremaps-calcite/src/test/java/org/apache/baremaps/calcite/rpsl/RpslTableTest.java
@@ -37,7 +37,7 @@ import org.junit.jupiter.api.Test;
 class RpslTableTest {
 
   private static final File SAMPLE_RPSL_FILE =
-      TestFiles.RIPE_TXT.toFile();
+      TestFiles.RPSL_TXT.toFile();
 
   @Test
   void testSchemaVerification() throws IOException {
diff --git 
a/baremaps-core/src/test/java/org/apache/baremaps/iploc/IpLocObjectTest.java 
b/baremaps-core/src/test/java/org/apache/baremaps/iploc/IpLocObjectTest.java
index 713b6a37f..5d2c58ff9 100644
--- a/baremaps-core/src/test/java/org/apache/baremaps/iploc/IpLocObjectTest.java
+++ b/baremaps-core/src/test/java/org/apache/baremaps/iploc/IpLocObjectTest.java
@@ -61,7 +61,7 @@ class IpLocObjectTest {
   @BeforeAll
   public static void beforeAll() throws Exception {
     // Load the NIC sample objects
-    var file = TestFiles.resolve("baremaps-testing/data/ripe/sample.txt");
+    var file = TestFiles.RPSL_TXT;
     try (var input = Files.newInputStream(file)) {
       rpslObjects = new RpslReader().read(input).toList();
     }
diff --git 
a/baremaps-rpsl/src/test/java/org/apache/baremaps/rpsl/RpslObjectTest.java 
b/baremaps-rpsl/src/test/java/org/apache/baremaps/rpsl/RpslObjectTest.java
index a3cfb75b5..80d0a3a84 100644
--- a/baremaps-rpsl/src/test/java/org/apache/baremaps/rpsl/RpslObjectTest.java
+++ b/baremaps-rpsl/src/test/java/org/apache/baremaps/rpsl/RpslObjectTest.java
@@ -32,7 +32,7 @@ class RpslObjectTest {
 
   @BeforeEach
   public void before() throws IOException {
-    var file = TestFiles.resolve("baremaps-testing/data/ripe/sample.txt");
+    var file = TestFiles.RPSL_TXT;
     try (var input = Files.newInputStream(file)) {
       objects = new RpslReader().read(input).toList();
     }
diff --git 
a/baremaps-rpsl/src/test/java/org/apache/baremaps/rpsl/RpslParserTest.java 
b/baremaps-rpsl/src/test/java/org/apache/baremaps/rpsl/RpslParserTest.java
index cd795c622..48e8feae9 100644
--- a/baremaps-rpsl/src/test/java/org/apache/baremaps/rpsl/RpslParserTest.java
+++ b/baremaps-rpsl/src/test/java/org/apache/baremaps/rpsl/RpslParserTest.java
@@ -30,7 +30,7 @@ class RpslParserTest {
 
   @Test
   void parseObjects() throws IOException {
-    var file = TestFiles.resolve("baremaps-testing/data/ripe/sample.txt");
+    var file = TestFiles.RPSL_TXT;
     try (var input = Files.newInputStream(file)) {
       List<RpslObject> objects = new RpslReader().read(input).toList();
       assertEquals(10, objects.size());
@@ -39,7 +39,7 @@ class RpslParserTest {
 
   @Test
   void parseAttributes() throws IOException {
-    var file = TestFiles.resolve("baremaps-testing/data/ripe/sample.txt");
+    var file = TestFiles.RPSL_TXT;
     try (var input = Files.newInputStream(file)) {
       List<RpslObject> objects = new RpslReader().read(input).toList();
       List<RpslAttribute> attributes = objects.stream()
diff --git a/baremaps-testing/data/ripe/sample.txt 
b/baremaps-testing/data/rpsl/sample.txt
similarity index 100%
rename from baremaps-testing/data/ripe/sample.txt
rename to baremaps-testing/data/rpsl/sample.txt
diff --git 
a/baremaps-testing/src/main/java/org/apache/baremaps/testing/TestFiles.java 
b/baremaps-testing/src/main/java/org/apache/baremaps/testing/TestFiles.java
index 921cd1319..372983fd4 100644
--- a/baremaps-testing/src/main/java/org/apache/baremaps/testing/TestFiles.java
+++ b/baremaps-testing/src/main/java/org/apache/baremaps/testing/TestFiles.java
@@ -101,8 +101,8 @@ public class TestFiles {
   public static final Path POINT_FLATGEOBUF =
       resolve("baremaps-testing/data/flatgeobuf/countries.fgb");
 
-  public static final Path RIPE_TXT =
-      resolve("baremaps-testing/data/ripe/sample.txt");
+  public static final Path RPSL_TXT =
+      resolve("baremaps-testing/data/rpsl/sample.txt");
 
   /* The geometries of the osm-sample/sample.osm.xml file */
 

Reply via email to