Initial Development #1

Merged
danieljsummers merged 88 commits from v1-rc into main 2025-04-16 01:29:20 +00:00
13 changed files with 351 additions and 0 deletions
Showing only changes of commit c35c41bf3c - Show all commits

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

14
.idea/compiler.xml generated Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="common" />
<module name="sqlite" />
</profile>
</annotationProcessing>
</component>
</project>

9
.idea/encodings.xml generated Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/common/src/main/kotlin" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/common/src/main/resources" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/sqlite/src/main/kotlin" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/sqlite/src/main/resources" charset="UTF-8" />
</component>
</project>

25
.idea/jarRepositories.xml generated Normal file
View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="mavenCentral" />
<option name="name" value="mavenCentral" />
<option name="url" value="https://repo1.maven.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Central Repository" />
<option name="url" value="https://repo.maven.apache.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>

6
.idea/kotlinc.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="2.1.10" />
</component>
</project>

23
.idea/libraries/KotlinJavaRuntime.xml generated Normal file
View File

@ -0,0 +1,23 @@
<component name="libraryTable">
<library name="KotlinJavaRuntime" type="repository">
<properties maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21" />
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.0.21/kotlin-stdlib-jdk8-2.0.21.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.21/kotlin-stdlib-2.0.21.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.0.21/kotlin-stdlib-jdk7-2.0.21.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.0.21/kotlin-stdlib-jdk8-2.0.21-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.21/kotlin-stdlib-2.0.21-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.0.21/kotlin-stdlib-jdk7-2.0.21-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.0.21/kotlin-stdlib-jdk8-2.0.21-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.21/kotlin-stdlib-2.0.21-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
<root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.0.21/kotlin-stdlib-jdk7-2.0.21-sources.jar!/" />
</SOURCES>
</library>
</component>

15
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/src/common/pom.xml" />
<option value="$PROJECT_DIR$/src/sqlite/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="corretto-21" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/solutions.bitbadger.documents.iml" filepath="$PROJECT_DIR$/.idea/solutions.bitbadger.documents.iml" />
</modules>
</component>
</project>

10
.idea/solutions.bitbadger.documents.iml generated Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="TEST" name="KotlinJavaRuntime" level="project" />
</component>
</module>

6
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

99
src/sqlite/pom.xml Normal file
View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>solutions.bitbadger.documents</groupId>
<artifactId>sqlite</artifactId>
<version>4.0-ALPHA</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.code.style>official</kotlin.code.style>
<kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>
</properties>
<repositories>
<repository>
<id>mavenCentral</id>
<url>https://repo1.maven.org/maven2/</url>
</repository>
</repositories>
<build>
<sourceDirectory>src/main/kotlin</sourceDirectory>
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>2.1.10</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<mainClass>MainKt</mainClass>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test-junit5</artifactId>
<version>2.1.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>2.1.10</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.46.1.2</version>
</dependency>
<dependency>
<groupId>solutions.bitbadger.documents</groupId>
<artifactId>common</artifactId>
<version>4.0-ALPHA</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,26 @@
package solutions.bitbadger.documents.sqlite
import java.sql.Connection
import java.sql.DriverManager
/**
* Configuration for SQLite
*/
object Configuration {
/** The connection string for the SQLite database */
var connectionString: String? = null
/**
* Retrieve a new connection to the SQLite database
*
* @return A new connection to the SQLite database
* @throws IllegalArgumentException If the connection string is not set before calling this
*/
fun dbConn(): Connection {
if (connectionString == null) {
throw IllegalArgumentException("Please provide a connection string before attempting data access")
}
return DriverManager.getConnection(connectionString)
}
}

View File

@ -0,0 +1,102 @@
package solutions.bitbadger.documents.sqlite
import solutions.bitbadger.documents.common.*
import solutions.bitbadger.documents.common.Configuration
import solutions.bitbadger.documents.common.Query
/**
* Queries with specific syntax in SQLite
*/
object Query {
/**
* Create a `WHERE` clause fragment to implement a comparison on fields in a JSON document
*
* @param howMatched How the fields should be matched
* @param fields The fields for the comparisons
* @return A `WHERE` clause implementing the comparisons for the given fields
*/
fun whereByFields(howMatched: FieldMatch, fields: Collection<Field<*>>): String {
val name = ParameterName()
return fields.joinToString(" ${howMatched.sql} ") {
val comp = it.comparison
when (comp.op) {
Op.EXISTS, Op.NOT_EXISTS -> {
"${it.path(Dialect.SQLITE, FieldFormat.SQL)} ${it.comparison.op.sql}"
}
Op.BETWEEN -> {
val p = name.derive(it.parameterName)
"${it.path(Dialect.SQLITE, FieldFormat.SQL)} ${comp.op.sql} ${p}min AND ${p}max"
}
Op.IN -> {
val p = name.derive(it.parameterName)
val values = comp.value as List<*>
val paramNames = values.indices.joinToString(", ") { idx -> "${p}_$idx" }
"${it.path(Dialect.SQLITE, FieldFormat.SQL)} ${comp.op.sql} ($paramNames)"
}
Op.IN_ARRAY -> {
val p = name.derive(it.parameterName)
val (table, values) = comp.value as Pair<String, List<*>>
val paramNames = values.indices.joinToString(", ") { idx -> "${p}_$idx" }
"EXISTS (SELECT 1 FROM json_each($table.data, '$.${it.name}') WHERE value IN ($paramNames)"
}
else -> {
"${it.path(Dialect.SQLITE, FieldFormat.SQL)} ${comp.op.sql} ${name.derive(it.parameterName)}"
}
}
}
}
/**
* Create a `WHERE` clause fragment to implement an ID-based query
*
* @param docId The ID of the document
* @return A `WHERE` clause fragment identifying a document by its ID
*/
fun <TKey> whereById(docId: TKey): String =
whereByFields(FieldMatch.ANY, listOf(Field.equal(Configuration.idField, docId).withParameterName(":id")))
/**
* Create an `UPDATE` statement to patch documents
*
* @param tableName The table to be updated
* @return A query to patch documents
*/
fun patch(tableName: String): String =
"UPDATE $tableName SET data = json_patch(data, json(:data))"
// TODO: fun removeFields(tableName: String, fields: Collection<String>): String
/**
* Create a query by a document's ID
*
* @param statement The SQL statement to be run against a document by its ID
* @param docId The ID of the document targeted
* @returns A query addressing a document by its ID
*/
fun <TKey> byId(statement: String, docId: TKey): String =
Query.statementWhere(statement, whereById(docId))
/**
* Create a query on JSON fields
*
* @param statement The SQL statement to be run against matching fields
* @param howMatched Whether to match any or all of the field conditions
* @param fields The field conditions to be matched
* @return A query addressing documents by field matching conditions
*/
fun byFields(statement: String, howMatched: FieldMatch, fields: Collection<Field<*>>): String =
Query.statementWhere(statement, whereByFields(howMatched, fields))
object Definition {
/**
* SQL statement to create a document table
*
* @param tableName The name of the table (may include schema)
* @return A query to create the table if it does not exist
*/
fun ensureTable(tableName: String): String =
Query.Definition.ensureTableFor(tableName, "TEXT")
}
}