Initial Development #1
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal 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
14
.idea/compiler.xml
generated
Normal 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
9
.idea/encodings.xml
generated
Normal 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
25
.idea/jarRepositories.xml
generated
Normal 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
6
.idea/kotlinc.xml
generated
Normal 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
23
.idea/libraries/KotlinJavaRuntime.xml
generated
Normal 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
15
.idea/misc.xml
generated
Normal 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
8
.idea/modules.xml
generated
Normal 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
10
.idea/solutions.bitbadger.documents.iml
generated
Normal 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
6
.idea/vcs.xml
generated
Normal 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
99
src/sqlite/pom.xml
Normal 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>
|
26
src/sqlite/src/main/kotlin/Configuration.kt
Normal file
26
src/sqlite/src/main/kotlin/Configuration.kt
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
102
src/sqlite/src/main/kotlin/Query.kt
Normal file
102
src/sqlite/src/main/kotlin/Query.kt
Normal 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")
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user