diff --git a/pace-datastore/pace-sqlite-datastore/pom.xml b/pace-datastore/pace-sqlite-datastore/pom.xml
new file mode 100644
index 00000000..ba978875
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/pom.xml
@@ -0,0 +1,88 @@
+
+
+ 4.0.0
+
+ io.github.ci-cmg
+ pace-datastore
+ 0.1.0-SNAPSHOT
+
+
+ pace-sqlite-datastore
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ io.github.ci-cmg
+ pace-common-datastore
+
+
+ org.xerial
+ sqlite-jdbc
+ 3.45.3.0
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.10.1
+ test
+
+
+ commons-io
+ commons-io
+ 2.16.0
+ test
+
+
+ org.mockito
+ mockito-core
+ 5.11.0
+ test
+
+
+
+
+
+ coverage
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+
+
+
+ BUNDLE
+
+
+ LINE
+ COVEREDRATIO
+ 0.90
+
+
+ BRANCH
+ COVEREDRATIO
+ 0.90
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/DetectionTypeSQLiteDatastore.java b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/DetectionTypeSQLiteDatastore.java
new file mode 100644
index 00000000..3ec4d0fe
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/DetectionTypeSQLiteDatastore.java
@@ -0,0 +1,30 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import edu.colorado.cires.pace.data.object.DetectionType;
+import java.nio.file.Path;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+public class DetectionTypeSQLiteDatastore extends SQLiteDatastore {
+
+ protected DetectionTypeSQLiteDatastore(Path sqliteFile) {
+ super(sqliteFile, "DETECTION_TYPES");
+ }
+
+ @Override
+ protected Stream resultSetToStream(ResultSet resultSet) throws SQLException {
+ List detectionTypes = new ArrayList<>(0);
+
+ while (resultSet.next()) {
+ detectionTypes.add(DetectionType.builder()
+ .source(resultSet.getString("SOURCE"))
+ .scienceName(resultSet.getString("SCIENCE_NAME"))
+ .build());
+ }
+
+ return detectionTypes.stream();
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/FileTypeSQLiteDatastore.java b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/FileTypeSQLiteDatastore.java
new file mode 100644
index 00000000..9c16ccf7
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/FileTypeSQLiteDatastore.java
@@ -0,0 +1,29 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import edu.colorado.cires.pace.data.object.FileType;
+import java.nio.file.Path;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+public class FileTypeSQLiteDatastore extends SQLiteDatastore {
+
+ protected FileTypeSQLiteDatastore(Path sqliteFile) {
+ super(sqliteFile, "FILE_TYPES");
+ }
+
+ @Override
+ protected Stream resultSetToStream(ResultSet resultSet) throws SQLException {
+ List fileTypes = new ArrayList<>(0);
+
+ while (resultSet.next()) {
+ fileTypes.add(FileType.builder()
+ .type(resultSet.getString("TYPE"))
+ .build());
+ }
+
+ return fileTypes.stream();
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/InstrumentSQLiteDatastore.java b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/InstrumentSQLiteDatastore.java
new file mode 100644
index 00000000..05a54dbc
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/InstrumentSQLiteDatastore.java
@@ -0,0 +1,49 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import edu.colorado.cires.pace.data.object.FileType;
+import edu.colorado.cires.pace.data.object.Instrument;
+import edu.colorado.cires.pace.datastore.Datastore;
+import edu.colorado.cires.pace.datastore.DatastoreException;
+import java.nio.file.Path;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Stream;
+
+public class InstrumentSQLiteDatastore extends SQLiteDatastore {
+
+ private final Datastore fileTypeDatastore;
+
+ protected InstrumentSQLiteDatastore(Path sqliteFile, Datastore fileTypeDatastore) {
+ super(sqliteFile, "INSTRUMENTS");
+ this.fileTypeDatastore = fileTypeDatastore;
+ }
+
+ @Override
+ protected Stream resultSetToStream(ResultSet resultSet) throws SQLException {
+ List instruments = new ArrayList<>(0);
+
+ while (resultSet.next()) {
+ instruments.add(Instrument.builder()
+ .name(resultSet.getString("Name"))
+ .fileTypes(Arrays.stream(resultSet.getString("FILE_TYPES").split(","))
+ .map(ft -> {
+ try {
+ return fileTypeDatastore.findByUniqueField(ft).orElseThrow(
+ () -> new DatastoreException(String.format(
+ "file type %s not found", ft
+ ), null)
+ );
+ } catch (DatastoreException e) {
+ throw new RuntimeException(e);
+ }
+ })
+ .toList())
+ .build());
+ }
+
+ return instruments.stream();
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/OrganizationsSQLiteDatastore.java b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/OrganizationsSQLiteDatastore.java
new file mode 100644
index 00000000..7118b93b
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/OrganizationsSQLiteDatastore.java
@@ -0,0 +1,38 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import edu.colorado.cires.pace.data.object.Organization;
+import java.nio.file.Path;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+public class OrganizationsSQLiteDatastore extends SQLiteDatastore {
+
+ protected OrganizationsSQLiteDatastore(Path sqliteFile) {
+ super(sqliteFile, "ORGANIZATIONS");
+ }
+
+ @Override
+ protected Stream resultSetToStream(ResultSet resultSet) throws SQLException {
+ List organizations = new ArrayList<>(0);
+
+ while (resultSet.next()) {
+ organizations.add(Organization.builder()
+ .name(resultSet.getString("NAME"))
+ .street(resultSet.getString("STREET"))
+ .city(resultSet.getString("CITY"))
+ .state(resultSet.getString("STATE"))
+ .zip(resultSet.getString("ZIP"))
+ .country(resultSet.getString("COUNTRY"))
+ .email(resultSet.getString("EMAIL"))
+ .phone(resultSet.getString("PHONE"))
+ .uuid(UUID.fromString(resultSet.getString("UUID")))
+ .build());
+ }
+
+ return organizations.stream();
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/PersonSQLiteDatastore.java b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/PersonSQLiteDatastore.java
new file mode 100644
index 00000000..50a404ba
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/PersonSQLiteDatastore.java
@@ -0,0 +1,41 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import edu.colorado.cires.pace.data.object.Person;
+import java.nio.file.Path;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Stream;
+
+public class PersonSQLiteDatastore extends SQLiteDatastore {
+
+ protected PersonSQLiteDatastore(Path sqliteFile) {
+ super(sqliteFile, "PEOPLE");
+ }
+
+ @Override
+ protected Stream resultSetToStream(ResultSet resultSet) throws SQLException {
+ List people = new ArrayList<>(0);
+
+ while (resultSet.next()) {
+ people.add(Person.builder()
+ .name(resultSet.getString("NAME"))
+ .street(resultSet.getString("STREET"))
+ .city(resultSet.getString("CITY"))
+ .state(resultSet.getString("STATE"))
+ .zip(resultSet.getString("ZIP"))
+ .country(resultSet.getString("COUNTRY"))
+ .email(resultSet.getString("EMAIL"))
+ .phone(resultSet.getString("PHONE"))
+ .uuid(UUID.fromString(resultSet.getString("UUID")))
+ .orcid(resultSet.getString("ORCID"))
+ .organization(resultSet.getString("ORGANIZATION"))
+ .position(resultSet.getString("POSITION"))
+ .build());
+ }
+
+ return people.stream();
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/PlatformSQLiteDatastore.java b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/PlatformSQLiteDatastore.java
new file mode 100644
index 00000000..cdb13ec5
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/PlatformSQLiteDatastore.java
@@ -0,0 +1,29 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import edu.colorado.cires.pace.data.object.Platform;
+import java.nio.file.Path;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+public class PlatformSQLiteDatastore extends SQLiteDatastore {
+
+ protected PlatformSQLiteDatastore(Path sqliteFile) {
+ super(sqliteFile, "PLATFORMS");
+ }
+
+ @Override
+ protected Stream resultSetToStream(ResultSet resultSet) throws SQLException {
+ List platforms = new ArrayList<>(0);
+
+ while (resultSet.next()) {
+ platforms.add(Platform.builder()
+ .name(resultSet.getString("NAME"))
+ .build());
+ }
+
+ return platforms.stream();
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/ProjectSQLiteDatastore.java b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/ProjectSQLiteDatastore.java
new file mode 100644
index 00000000..cf104224
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/ProjectSQLiteDatastore.java
@@ -0,0 +1,29 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import edu.colorado.cires.pace.data.object.Project;
+import java.nio.file.Path;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+public class ProjectSQLiteDatastore extends SQLiteDatastore {
+
+ protected ProjectSQLiteDatastore(Path sqliteFile) {
+ super(sqliteFile, "PROJECTS");
+ }
+
+ @Override
+ protected Stream resultSetToStream(ResultSet resultSet) throws SQLException {
+ List projects = new ArrayList<>(0);
+
+ while (resultSet.next()) {
+ projects.add(Project.builder()
+ .name(resultSet.getString("NAME"))
+ .build());
+ }
+
+ return projects.stream();
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/SQLiteDatastore.java b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/SQLiteDatastore.java
new file mode 100644
index 00000000..ef5ac38c
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/SQLiteDatastore.java
@@ -0,0 +1,93 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import edu.colorado.cires.pace.data.object.ObjectWithUniqueField;
+import edu.colorado.cires.pace.datastore.Datastore;
+import edu.colorado.cires.pace.datastore.DatastoreException;
+import java.nio.file.Path;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import jdk.jshell.spi.ExecutionControl.NotImplementedException;
+
+public abstract class SQLiteDatastore implements Datastore {
+
+ private final Path sqliteFile;
+ private final String tableName;
+
+ protected SQLiteDatastore(Path sqliteFile, String tableName) {
+ this.sqliteFile = sqliteFile;
+ this.tableName = tableName;
+ }
+
+ @Override
+ public O save(O object) throws DatastoreException {
+ try {
+ throw new NotImplementedException("save not implemented");
+ } catch (NotImplementedException e) {
+ throw new DatastoreException("Save failed", e);
+ }
+ }
+
+ @Override
+ public void delete(O object) throws DatastoreException {
+ try {
+ throw new NotImplementedException("delete not implemented");
+ } catch (NotImplementedException e) {
+ throw new DatastoreException("Delete failed", e);
+ }
+ }
+
+ @Override
+ public Optional findByUUID(UUID uuid) throws DatastoreException {
+ try {
+ throw new NotImplementedException("findByUUID not implemented");
+ } catch (NotImplementedException e) {
+ throw new DatastoreException("Find by uuid failed", e);
+ }
+ }
+
+ @Override
+ public Optional findByUniqueField(String uniqueField) throws DatastoreException {
+ try {
+ throw new NotImplementedException("findByUniqueField not implemented");
+ } catch (NotImplementedException e) {
+ throw new DatastoreException("Find by unique field failed", e);
+ }
+ }
+
+ @Override
+ public Stream findAll() throws DatastoreException {
+ try (Connection connection = DriverManager.getConnection(String.format("jdbc:sqlite:%s", sqliteFile.toString())); Statement statement = connection.createStatement()) {
+ statement.setQueryTimeout(30);
+
+ return resultSetToStream(
+ statement.executeQuery(String.format("select * from %s", tableName))
+ );
+ } catch (SQLException e) {
+ throw new DatastoreException("Failed to list table rows", e);
+ }
+ }
+
+ protected abstract Stream resultSetToStream(ResultSet resultSet) throws SQLException;
+
+ @Override
+ public String getUniqueFieldName() {
+ return null;
+ }
+
+ @Override
+ public String getClassName() {
+ return null;
+ }
+
+ @Override
+ public Function getUniqueFieldGetter() {
+ return null;
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/SeaSQLiteDatastore.java b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/SeaSQLiteDatastore.java
new file mode 100644
index 00000000..1edefe84
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/SeaSQLiteDatastore.java
@@ -0,0 +1,29 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import edu.colorado.cires.pace.data.object.Sea;
+import java.nio.file.Path;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+public class SeaSQLiteDatastore extends SQLiteDatastore {
+
+ protected SeaSQLiteDatastore(Path sqliteFile) {
+ super(sqliteFile, "SEAS");
+ }
+
+ @Override
+ protected Stream resultSetToStream(ResultSet resultSet) throws SQLException {
+ List seas = new ArrayList<>(0);
+
+ while (resultSet.next()) {
+ seas.add(Sea.builder()
+ .name(resultSet.getString("NAME"))
+ .build());
+ }
+
+ return seas.stream();
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/ShipSQLiteDatastore.java b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/ShipSQLiteDatastore.java
new file mode 100644
index 00000000..a0873821
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/main/java/edu/colorado/cires/pace/datastore/sqlite/ShipSQLiteDatastore.java
@@ -0,0 +1,29 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import edu.colorado.cires.pace.data.object.Ship;
+import java.nio.file.Path;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+public class ShipSQLiteDatastore extends SQLiteDatastore {
+
+ protected ShipSQLiteDatastore(Path sqliteFile) {
+ super(sqliteFile, "SHIPS");
+ }
+
+ @Override
+ protected Stream resultSetToStream(ResultSet resultSet) throws SQLException {
+ List ships = new ArrayList<>(0);
+
+ while (resultSet.next()) {
+ ships.add(Ship.builder()
+ .name(resultSet.getString("NAME"))
+ .build());
+ }
+
+ return ships.stream();
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/DetectionTypeSQLiteDatastoreTest.java b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/DetectionTypeSQLiteDatastoreTest.java
new file mode 100644
index 00000000..8ca8f085
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/DetectionTypeSQLiteDatastoreTest.java
@@ -0,0 +1,26 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import edu.colorado.cires.pace.data.object.DetectionType;
+import java.nio.file.Path;
+
+class DetectionTypeSQLiteDatastoreTest extends SQLiteDatastoreTest {
+
+ @Override
+ protected SQLiteDatastore createDatastore(Path dbPath) {
+ return new DetectionTypeSQLiteDatastore(dbPath);
+ }
+
+ @Override
+ protected int getExpectedRowCount() {
+ return 24;
+ }
+
+ @Override
+ protected void verifyObject(DetectionType object) {
+ assertNull(object.getUuid());
+ assertNotNull(object.getSource());
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/FileTypeSQLiteDatastoreTest.java b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/FileTypeSQLiteDatastoreTest.java
new file mode 100644
index 00000000..4456fb9c
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/FileTypeSQLiteDatastoreTest.java
@@ -0,0 +1,27 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import edu.colorado.cires.pace.data.object.FileType;
+import java.nio.file.Path;
+
+class FileTypeSQLiteDatastoreTest extends SQLiteDatastoreTest {
+
+ @Override
+ protected SQLiteDatastore createDatastore(Path dbPath) {
+ return new FileTypeSQLiteDatastore(dbPath);
+ }
+
+ @Override
+ protected int getExpectedRowCount() {
+ return 5;
+ }
+
+ @Override
+ protected void verifyObject(FileType object) {
+ assertNull(object.getUuid());
+ assertNull(object.getComment());
+ assertNotNull(object.getType());
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/InstrumentSQLiteDatastoreTest.java b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/InstrumentSQLiteDatastoreTest.java
new file mode 100644
index 00000000..46f0e0c5
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/InstrumentSQLiteDatastoreTest.java
@@ -0,0 +1,80 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import edu.colorado.cires.pace.data.object.FileType;
+import edu.colorado.cires.pace.data.object.Instrument;
+import edu.colorado.cires.pace.datastore.Datastore;
+import edu.colorado.cires.pace.datastore.DatastoreException;
+import java.nio.file.Path;
+import java.util.Optional;
+import java.util.UUID;
+import org.junit.jupiter.api.Test;
+
+class InstrumentSQLiteDatastoreTest extends SQLiteDatastoreTest {
+
+ private static final Datastore fileTypeDatastore = mock(Datastore.class);
+
+ private static final FileType wavFileType = FileType.builder()
+ .uuid(UUID.randomUUID())
+ .type("wav")
+ .build();
+ private static final FileType aifFileType = FileType.builder()
+ .uuid(UUID.randomUUID())
+ .type("aif")
+ .build();
+ private static final FileType aiffFileType = FileType.builder()
+ .uuid(UUID.randomUUID())
+ .type("aiff")
+ .build();
+ private static final FileType csvFileType = FileType.builder()
+ .uuid(UUID.randomUUID())
+ .type(".csv")
+ .build();
+ static {
+ try {
+ when(fileTypeDatastore.findByUniqueField("wav")).thenReturn(Optional.of(wavFileType));
+ when(fileTypeDatastore.findByUniqueField("aif")).thenReturn(Optional.of(aifFileType));
+ when(fileTypeDatastore.findByUniqueField("aiff")).thenReturn(Optional.of(aiffFileType));
+ when(fileTypeDatastore.findByUniqueField(".csv")).thenReturn(Optional.of(csvFileType));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ protected SQLiteDatastore createDatastore(Path dbPath) {
+ return new InstrumentSQLiteDatastore(dbPath, fileTypeDatastore);
+ }
+
+ @Override
+ protected int getExpectedRowCount() {
+ return 9;
+ }
+
+ @Override
+ protected void verifyObject(Instrument object) {
+ assertNull(object.getUuid());
+ assertNotNull(object.getName());
+
+ assertNotNull(object.getFileTypes());
+ object.getFileTypes().forEach((ft) -> {
+ assertNotNull(ft.getUuid());
+ assertNotNull(ft.getType());
+ });
+ }
+
+ @Test
+ void testFileTypeNotFound() {
+ Datastore instrumentDatastore = new InstrumentSQLiteDatastore(getDBPath(), mock(FileTypeSQLiteDatastore.class));
+ RuntimeException runtimeException = assertThrows(RuntimeException.class, instrumentDatastore::findAll);
+ assertEquals("file type wav not found", runtimeException.getCause().getMessage());
+ assertInstanceOf(DatastoreException.class, runtimeException.getCause());
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/OrganizationSQLiteDatastoreTest.java b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/OrganizationSQLiteDatastoreTest.java
new file mode 100644
index 00000000..bc66fecf
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/OrganizationSQLiteDatastoreTest.java
@@ -0,0 +1,31 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import edu.colorado.cires.pace.data.object.Organization;
+import java.nio.file.Path;
+
+class OrganizationSQLiteDatastoreTest extends SQLiteDatastoreTest {
+
+ @Override
+ protected String getDBFileName() {
+ return "localData.sqlite";
+ }
+
+ @Override
+ protected SQLiteDatastore createDatastore(Path dbPath) {
+ return new OrganizationsSQLiteDatastore(dbPath);
+ }
+
+ @Override
+ protected int getExpectedRowCount() {
+ return 41;
+ }
+
+ @Override
+ protected void verifyObject(Organization object) {
+ assertNotNull(object.getUuid());
+ assertNotNull(object.getName());
+ assertNotNull(object.getCountry());
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/PersonSQLiteDatastoreTest.java b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/PersonSQLiteDatastoreTest.java
new file mode 100644
index 00000000..0de29689
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/PersonSQLiteDatastoreTest.java
@@ -0,0 +1,30 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import edu.colorado.cires.pace.data.object.Person;
+import java.nio.file.Path;
+
+class PersonSQLiteDatastoreTest extends SQLiteDatastoreTest {
+
+ @Override
+ protected String getDBFileName() {
+ return "localData.sqlite";
+ }
+
+ @Override
+ protected SQLiteDatastore createDatastore(Path dbPath) {
+ return new PersonSQLiteDatastore(dbPath);
+ }
+
+ @Override
+ protected int getExpectedRowCount() {
+ return 39;
+ }
+
+ @Override
+ protected void verifyObject(Person object) {
+ assertNotNull(object.getUuid());
+ assertNotNull(object.getName());
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/PlatformSQLiteDatastoreTest.java b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/PlatformSQLiteDatastoreTest.java
new file mode 100644
index 00000000..517a8ff4
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/PlatformSQLiteDatastoreTest.java
@@ -0,0 +1,26 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import edu.colorado.cires.pace.data.object.Platform;
+import java.nio.file.Path;
+
+class PlatformSQLiteDatastoreTest extends SQLiteDatastoreTest {
+
+ @Override
+ protected SQLiteDatastore createDatastore(Path dbPath) {
+ return new PlatformSQLiteDatastore(dbPath);
+ }
+
+ @Override
+ protected int getExpectedRowCount() {
+ return 6;
+ }
+
+ @Override
+ protected void verifyObject(Platform object) {
+ assertNull(object.getUuid());
+ assertNotNull(object.getName());
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/ProjectSQLiteDatastoreTest.java b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/ProjectSQLiteDatastoreTest.java
new file mode 100644
index 00000000..39ca1d2e
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/ProjectSQLiteDatastoreTest.java
@@ -0,0 +1,31 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import edu.colorado.cires.pace.data.object.Project;
+import java.nio.file.Path;
+
+class ProjectSQLiteDatastoreTest extends SQLiteDatastoreTest {
+
+ @Override
+ protected String getDBFileName() {
+ return "localData.sqlite";
+ }
+
+ @Override
+ protected SQLiteDatastore createDatastore(Path dbPath) {
+ return new ProjectSQLiteDatastore(dbPath);
+ }
+
+ @Override
+ protected int getExpectedRowCount() {
+ return 11;
+ }
+
+ @Override
+ protected void verifyObject(Project object) {
+ assertNull(object.getUuid());
+ assertNotNull(object.getName());
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/SQLiteDatastoreTest.java b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/SQLiteDatastoreTest.java
new file mode 100644
index 00000000..bc942dbe
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/SQLiteDatastoreTest.java
@@ -0,0 +1,82 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import edu.colorado.cires.pace.data.object.ObjectWithUniqueField;
+import edu.colorado.cires.pace.datastore.Datastore;
+import edu.colorado.cires.pace.datastore.DatastoreException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+
+abstract class SQLiteDatastoreTest {
+
+ protected abstract SQLiteDatastore createDatastore(Path dbPath);
+ protected abstract int getExpectedRowCount();
+ protected abstract void verifyObject(O object);
+
+ protected String getDBFileName() {
+ return "sourceData.sqlite";
+ }
+
+ protected Path getDBPath() {
+ return Paths.get("src").resolve("test").resolve("resources").resolve(getDBFileName()).toAbsolutePath();
+ }
+
+ private final SQLiteDatastore datastore = createDatastore(getDBPath());
+
+ @Test
+ void findAll() throws DatastoreException {
+ List objects = datastore.findAll().toList();
+ assertEquals(getExpectedRowCount(), objects.size());
+
+ for (O object : objects) {
+ verifyObject(object);
+ }
+ }
+
+ @Test
+ void save() {
+ assertThrows(DatastoreException.class, () -> datastore.save(null));
+ }
+
+ @Test
+ void delete() {
+ assertThrows(DatastoreException.class, () -> datastore.delete(null));
+ }
+
+ @Test
+ void findByUUID() {
+ assertThrows(DatastoreException.class, () -> datastore.findByUUID(null));
+ }
+
+ @Test
+ void findByUniqueField() {
+ assertThrows(DatastoreException.class, () -> datastore.findByUniqueField(null));
+ }
+
+ @Test
+ void getUniqueFieldName() {
+ assertNull(datastore.getUniqueFieldName());
+ }
+
+ @Test
+ void getClassName() {
+ assertNull(datastore.getClassName());
+ }
+
+ @Test
+ void getUniqueFieldGetter() {
+ assertNull(datastore.getUniqueFieldGetter());
+ }
+
+ @Test
+ void invalidDBFile() {
+ Datastore misconfiguredDatastore = createDatastore(Paths.get("target").resolve("db.sqlite"));
+ Exception exception = assertThrows(DatastoreException.class, misconfiguredDatastore::findAll);
+ assertEquals("Failed to list table rows", exception.getMessage());
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/SeaSQLiteDatastoreTest.java b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/SeaSQLiteDatastoreTest.java
new file mode 100644
index 00000000..acc4c4a9
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/SeaSQLiteDatastoreTest.java
@@ -0,0 +1,26 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import edu.colorado.cires.pace.data.object.Sea;
+import java.nio.file.Path;
+
+class SeaSQLiteDatastoreTest extends SQLiteDatastoreTest {
+
+ @Override
+ protected SQLiteDatastore createDatastore(Path dbPath) {
+ return new SeaSQLiteDatastore(dbPath);
+ }
+
+ @Override
+ protected int getExpectedRowCount() {
+ return 101;
+ }
+
+ @Override
+ protected void verifyObject(Sea object) {
+ assertNull(object.getUuid());
+ assertNotNull(object.getName());
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/ShipSQLiteDatastoreTest.java b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/ShipSQLiteDatastoreTest.java
new file mode 100644
index 00000000..c075c407
--- /dev/null
+++ b/pace-datastore/pace-sqlite-datastore/src/test/java/edu/colorado/cires/pace/datastore/sqlite/ShipSQLiteDatastoreTest.java
@@ -0,0 +1,26 @@
+package edu.colorado.cires.pace.datastore.sqlite;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import edu.colorado.cires.pace.data.object.Ship;
+import java.nio.file.Path;
+
+class ShipSQLiteDatastoreTest extends SQLiteDatastoreTest {
+
+ @Override
+ protected SQLiteDatastore createDatastore(Path dbPath) {
+ return new ShipSQLiteDatastore(dbPath);
+ }
+
+ @Override
+ protected int getExpectedRowCount() {
+ return 9;
+ }
+
+ @Override
+ protected void verifyObject(Ship object) {
+ assertNull(object.getUuid());
+ assertNotNull(object.getName());
+ }
+}
diff --git a/pace-datastore/pace-sqlite-datastore/src/test/resources/localData.sqlite b/pace-datastore/pace-sqlite-datastore/src/test/resources/localData.sqlite
new file mode 100755
index 00000000..0e14a06b
Binary files /dev/null and b/pace-datastore/pace-sqlite-datastore/src/test/resources/localData.sqlite differ
diff --git a/pace-datastore/pace-sqlite-datastore/src/test/resources/sourceData.sqlite b/pace-datastore/pace-sqlite-datastore/src/test/resources/sourceData.sqlite
new file mode 100755
index 00000000..5e557a53
Binary files /dev/null and b/pace-datastore/pace-sqlite-datastore/src/test/resources/sourceData.sqlite differ
diff --git a/pace-datastore/pom.xml b/pace-datastore/pom.xml
index 7ad730d8..bb8b4cf7 100644
--- a/pace-datastore/pom.xml
+++ b/pace-datastore/pom.xml
@@ -14,6 +14,7 @@
pace-common-datastore
pace-json-datastore
+ pace-sqlite-datastore