You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@baremaps.apache.org by bc...@apache.org on 2025/04/14 15:49:51 UTC
(incubator-baremaps) 05/05: Add RPSL schema and tests
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 <bc...@gmail.com>
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 */