Skip to content

Commit

Permalink
Tutorial for selective JOIN.
Browse files Browse the repository at this point in the history
  • Loading branch information
urosjarc committed Apr 4, 2024
1 parent 55cc412 commit b16fb72
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 115 deletions.
168 changes: 111 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<h1 align="center">db-messiah</h1>
<h3 align="center">Kotlin lib. for enterprise database development</h3>
<h3 align="center">
Type safe SQL framework for Kotlin, built on top of JDBC and reflection.<br>
Strong focus on simplicity and minimal developer interference.<br>
</h3>
<p align="center">
+<b>290</b> <a href="https://github.com/urosjarc/db-messiah/blob/master/src/test">unit</a>,
+<b>210</b> <a href="https://github.com/urosjarc/db-messiah/blob/master/src/e2e">e2e</a>,
Expand All @@ -11,6 +14,63 @@
<a href="https://github.com/urosjarc/db-messiah/blob/master/src/tutorials/kotlin/Test_README.kt">tested</a><br>
+<b>86%</b> instruction coverage
</p>
<br>

<p align="center">
Db Messiah scans user provided data classes and all their properties with reflection,<br>
in order to set up database serializer which will then decode user actions like `db.table.create<User>()`<br>
into prepared SQL statements that are type safe, escaped, and free from SQL injections.
</p>

<p align="center">
Because everything is scanned with reflection your data classes will directly represent your whole database structure<br>
without the need of developer interference or any additional work. Here is an example how you would define
database with one table...
</p>

```kotlin
data class TestTable(var id: Int? = null, val column: String)

val db = SqliteService(
config = Properties().apply { this["jdbcUrl"] = "jdbc:sqlite::memory:" },
ser = SqliteSerializer(
tables = listOf(Table(TestTable::id)),
globalSerializers = BasicTS.sqlite
)
)

db.autocommit {
val row = TestTable(column = "col0")
it.table.drop<TestTable>()
it.table.create<TestTable>()
it.table.delete<TestTable>()
it.row.insert(row)
assert(row.id != null)
assert(it.row.select<TestTable>(pk = 1)!! == row)
assert(it.table.select<TestTable>() == listOf(row))
it.table.delete<TestTable>()
}
```

Because of that, it provides very simple solution for writing complex queries.<br>
There are only 4 methods to be remembered: it.<b>name</b>, it.<b>column</b>, it.<b>table</b>, it.<b>input</b><br>
Thats it! Everything else is joust ordinary SQL syntax that you know and love.<br>
This is an example how the most complex query in db-messiah looks like,
it's basically raw SQL with additional features like type safety and SQL injection .
</p>

```kotlin
val result = it.query.get(output = Out::class, input = parent) {
"""
SELECT ${it.column(Child::value)} AS ${it.name(Out::child_value)},
${it.column(Parent::value)} AS ${it.name(Out::parent_value)}
FROM ${it.table<Child>()}
JOIN ${it.table<Parent>()} ON ${it.column(Parent::pk)} = ${it.column(Child::parent_pk)}
WHERE ${it.column(Child::value)} = ${it.input(Parent::value)}
"""
}
```

<br>
<br>
<table width="100%" border="0">
Expand Down Expand Up @@ -40,8 +100,8 @@
```kotlin
/** DEPENDENCIES */

implementation("com.urosjarc:db-messiah:0.0.1") // Required
implementation("com.urosjarc:db-messiah-extra:0.0.1") // Optional
implementation("com.urosjarc:db-messiah:0.0.2") // Required
implementation("com.urosjarc:db-messiah-extra:0.0.2") // Optional
implementation("org.apache.logging.log4j:log4j-slf4j2-impl:2.20.0") //Optional

/** DRIVERS */
Expand Down Expand Up @@ -102,6 +162,10 @@ data class Unsafe(
val pk: UUID = UUID.randomUUID(), // Unsafe UUID manual primary key
val created: Instant = Instant.now() // Support for java.time.*
)

/** QUERY DTO */

data class Out(val child_value: String, val parent_value: String)
```

<br><h3 align="center">Database</h3>
Expand All @@ -111,37 +175,30 @@ data class Unsafe(

val sqliteSerializer = SqliteSerializer(
globalSerializers = BasicTS.sqlite + JavaTimeTS.sqlite + listOf(
/** Serializer for Id<T> */
IdTS.int(construct = { Id<Any>(it) }, deconstruct = { it.value }),
/** Serializer for UId<T> */
IdTS.uuid.sqlite(construct = { UId<Any>(it) })
),
tables = listOf(
Table(Unsafe::pk),
Table(Parent::pk),
Table(
Child::pk,
foreignKeys = listOf(
Child::parent_pk to Parent::class
),
primaryKey = Child::pk,
foreignKeys = listOf(Child::parent_pk to Parent::class),
constraints = listOf(
Child::parent_pk to listOf(C.CASCADE_DELETE, C.CASCADE_UPDATE),
Child::value to listOf(C.UNIQUE)
)
),
),
globalOutputs = listOf(Out::class),
)

/** POSTGRES */

val pgSerializer = PgSerializer(
globalSerializers = BasicTS.sqlite + JavaTimeTS.postgresql,
globalSerializers = BasicTS.postgresql + JavaTimeTS.postgresql,
schemas = listOf(
PgSchema(
name = "name", tables = listOf(
Table(Unsafe::pk),
)
),
PgSchema(name = "other", tables = listOf(Table(Unsafe::pk)))
),
)

Expand Down Expand Up @@ -271,9 +328,8 @@ sqlite.autocommit {
WHERE ${it.column(Child::value)} = ${it.input(Parent::value)}
"""
}
println(moreChildren)
assert(moreChildren == listOf(children[3]))
}

```

<br><h3 align="center">Transactions</h3>
Expand Down Expand Up @@ -396,52 +452,51 @@ For detailed explanation read about <a href="https://logging.apache.org/log4j/2.

<br><br><h2 align="center">Specifications</h3>

| | Schema | Serializer | Service | Basic types | java.time.* types |
|:--------:|:-------------:|:----------------:|:-------------:|:-------------------:|:----------------------:|
| DB2 | Db2Schema | Db2Serializer | Db2Service | BasicTS.db2 | JavaTimeTS.db2 |
| Derby | DerbySchema | DerbySerializer | DerbyService | BasicTS.derby | JavaTimeTS.derby |
| H2 | H2Schema | H2Serializer | H2Service | BasicTS.h2 | JavaTimeTS.h2 |
| Maria | MariaSchema | MariaSerializer | MariaService | BasicTS.maria | JavaTimeTS.maria |
| MS SQL | MssqlSchema | MssqlSerializer | MssqlService | BasicTS.mssql | JavaTimeTS.mssql |
| MySQL | MysqlSchema | MysqlSerializer | MysqlService | BasicTS.mysql | JavaTimeTS.mysql |
| Oracle | OracleSchema | OracleSerializer | OracleService | BasicTS.oracle | JavaTimeTS.oracle |
| Postgres | PgSchema | PgSerializer | PgService | BasicTS. postgresql | JavaTimeTS. postgresql |
| Sqlite | :x: | SqliteSerializer | SqliteService | BasicTS.sqlite | JavaTimeTS.sqlite |
| | Schema | Serializer | Service | Basic types | java.time.* types |
|:--------:|:------------:|:----------------:|:-------------:|:-------------------:|:----------------------:|
| DB2 | Db2Schema | Db2Serializer | Db2Service | BasicTS.db2 | JavaTimeTS.db2 |
| Derby | DerbySchema | DerbySerializer | DerbyService | BasicTS.derby | JavaTimeTS.derby |
| H2 | H2Schema | H2Serializer | H2Service | BasicTS.h2 | JavaTimeTS.h2 |
| Maria | MariaSchema | MariaSerializer | MariaService | BasicTS.maria | JavaTimeTS.maria |
| MS SQL | MssqlSchema | MssqlSerializer | MssqlService | BasicTS.mssql | JavaTimeTS.mssql |
| MySQL | MysqlSchema | MysqlSerializer | MysqlService | BasicTS.mysql | JavaTimeTS.mysql |
| Oracle | OracleSchema | OracleSerializer | OracleService | BasicTS.oracle | JavaTimeTS.oracle |
| Postgres | PgSchema | PgSerializer | PgService | BasicTS. postgresql | JavaTimeTS. postgresql |
| Sqlite | :x: | SqliteSerializer | SqliteService | BasicTS.sqlite | JavaTimeTS.sqlite |

<br><h3 align="center">Features</h3>

| | Escape | Schema | Auto INT PK | Auto UUID PK | UUID column | Many queries | Cascade | Procedure |
| | Escape | Schema | Auto INT PK | Auto UUID PK | UUID column | Many queries | Cascade | Procedure |
|:--------:|:------:|:----------------------:|:------------------:|:------------------:|:------------:|:------------------:|:-------------------------------------:|:----------------------:|
| DB2 | "%s" | :large_orange_diamond: | :white_check_mark: | :x: | CHAR(36) | :x: | :x: | :large_orange_diamond: |
| Derby | "%s" | :white_check_mark: | :white_check_mark: | :x: | CHAR(36) | :x: | :x: | :x: |
| H2 | "%s" | :white_check_mark: | :white_check_mark: | :white_check_mark: | UUID | :x: | :white_check_mark: | :x: |
| Maria | \`%s\` | :white_check_mark: | :white_check_mark: | :x: | UUID | :x: | :x: | :white_check_mark: |
| MS SQL | [%s] | :white_check_mark: | :white_check_mark: | :x: | UNIQUEIDE... | :white_check_mark: | :x: | :white_check_mark: |
| MySQL | \`%s\` | :white_check_mark: | :white_check_mark: | :x: | CHAR(36) | :x: | :x: | :white_check_mark: |
| Oracle | "%s" | :large_orange_diamond: | :white_check_mark: | :x: | VARCHAR2(36) | :x: | :white_check_mark: | :white_check_mark: |
| Postgres | "%s" | :white_check_mark: | :white_check_mark: | :white_check_mark: | UUID | :white_check_mark: | :white_check_mark: :white_check_mark: | :x: |
| Sqlite | "%s" | :x: | :white_check_mark: | :x: | CHAR(36) | :x: | :x: | :x: |
| DB2 | "%s" | :large_orange_diamond: | :white_check_mark: | :x: | CHAR(36) | :x: | :x: | :large_orange_diamond: |
| Derby | "%s" | :white_check_mark: | :white_check_mark: | :x: | CHAR(36) | :x: | :x: | :x: |
| H2 | "%s" | :white_check_mark: | :white_check_mark: | :white_check_mark: | UUID | :x: | :white_check_mark: | :x: |
| Maria | \`%s\` | :white_check_mark: | :white_check_mark: | :x: | UUID | :x: | :x: | :white_check_mark: |
| MS SQL | [%s] | :white_check_mark: | :white_check_mark: | :x: | UNIQUEIDE... | :white_check_mark: | :x: | :white_check_mark: |
| MySQL | \`%s\` | :white_check_mark: | :white_check_mark: | :x: | CHAR(36) | :x: | :x: | :white_check_mark: |
| Oracle | "%s" | :large_orange_diamond: | :white_check_mark: | :x: | VARCHAR2(36) | :x: | :white_check_mark: | :white_check_mark: |
| Postgres | "%s" | :white_check_mark: | :white_check_mark: | :white_check_mark: | UUID | :white_check_mark: | :white_check_mark: :white_check_mark: | :x: |
| Sqlite | "%s" | :x: | :white_check_mark: | :x: | CHAR(36) | :x: | :x: | :x: |

<br><br><h3 align="center">Type system</h3>

| KClass | COLUMN | Databases | db-messiah | db-messiah-extra |
|:---------------:|:------------:|:------------------------------------:|:-----------------------:|:--------------------------:|
| Boolean | BOOL | :white_check_mark: | :white_check_mark: | :x: |
| Char | CHAR | :white_check_mark: | :white_check_mark: | :x: |
| String | VARCHAR(100) | :white_check_mark: | :white_check_mark: | :x: |
| Float | FLOAT | :white_check_mark: | :white_check_mark: | :x: |
| Double | DOUBLE | :white_check_mark: | :white_check_mark: | :x: |
| Byte / UByte | TINYINT | :white_check_mark: | :white_check_mark: | :x: |
| Short / UShort | SMALLINT | :white_check_mark: | :white_check_mark: | :x: |
| Int / Uint | INTEGER | :white_check_mark: | :white_check_mark: | :x: |
| Long / ULong | BIGINT | :white_check_mark: | :white_check_mark: | :x: |
| Instant | DATETIME | Sqlite, Mysql, MSSql, Maria, H2, DB2 | Java :white_check_mark: | kotlinx :white_check_mark: |
| Instant | TIMESTAMP | Derby, Postgres, Oracle | Java :white_check_mark: | kotlinx :white_check_mark: |
| LocalDateTime | :x: | :x: | Java :x: | kotlinx :x: |
| LocalDate | DATE | :white_check_mark: | Java :white_check_mark: | kotlinx :white_check_mark: |
| LocalTime | TIME | :white_check_mark: but Oracle | Java :white_check_mark: | kotlinx :white_check_mark: |
| LocalTime | NUMBER(5, 0) | Oracle | Java :white_check_mark: | kotlinx :white_check_mark: |>

| KClass | COLUMN | Databases | db-messiah | db-messiah-extra |
|:--------------:|:------------:|:------------------------------------:|:-----------------------:|:--------------------------:|
| Boolean | BOOL | :white_check_mark: | :white_check_mark: | :x: |
| Char | CHAR | :white_check_mark: | :white_check_mark: | :x: |
| String | VARCHAR(100) | :white_check_mark: | :white_check_mark: | :x: |
| Float | FLOAT | :white_check_mark: | :white_check_mark: | :x: |
| Double | DOUBLE | :white_check_mark: | :white_check_mark: | :x: |
| Byte / UByte | TINYINT | :white_check_mark: | :white_check_mark: | :x: |
| Short / UShort | SMALLINT | :white_check_mark: | :white_check_mark: | :x: |
| Int / Uint | INTEGER | :white_check_mark: | :white_check_mark: | :x: |
| Long / ULong | BIGINT | :white_check_mark: | :white_check_mark: | :x: |
| Instant | DATETIME | Sqlite, Mysql, MSSql, Maria, H2, DB2 | Java :white_check_mark: | kotlinx :white_check_mark: |
| Instant | TIMESTAMP | Derby, Postgres, Oracle | Java :white_check_mark: | kotlinx :white_check_mark: |
| LocalDateTime | :x: | :x: | Java :x: | kotlinx :x: |
| LocalDate | DATE | :white_check_mark: | Java :white_check_mark: | kotlinx :white_check_mark: |
| LocalTime | TIME | :white_check_mark: but Oracle | Java :white_check_mark: | kotlinx :white_check_mark: |
| LocalTime | NUMBER(5, 0) | Oracle | Java :white_check_mark: | kotlinx :white_check_mark: |>

<br><br><h3 align="center">PRIMARY KEY</h3>
<img width="100%" src="https://github.com/urosjarc/db-messiah/blob/master/docs/constraints/PRIMARY_KEY.png">
Expand All @@ -452,7 +507,6 @@ For detailed explanation read about <a href="https://logging.apache.org/log4j/2.
<br><br><h3 align="center">INSERT BATCH</h3>
<img width="100%" src="https://github.com/urosjarc/db-messiah/blob/master/docs/queries/BATCH_INSERT.png">


<br><br><h3 align="center">UPDATE / DELETE</h3>
<table align="center" width="100%">
<tr>
Expand Down
6 changes: 3 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ publishing {
artifact(javadocJar)
pom {
name = "Db Messiah"
description = "Kotlin lib. for enterprise database development"
description = "Db Messiah, kotlin lib. for enterprise database development "
url = github
issueManagement {
system = "Github"
Expand Down Expand Up @@ -203,8 +203,8 @@ tasks.register<GradleBuild>("readme") {
var readme = File("./src/tutorials/kotlin/Test_README.md").readText()

val dependencies = mutableListOf(
"implementation(\"${project.group}:${project.name}:$version\") // Required",
"implementation(\"${project.group}:${project.name}-extra:$version\") // Optional",
"implementation(\"${project.group}:${project.name}:${project.version}\") // Required",
"implementation(\"${project.group}:${project.name}-extra:${project.version}\") // Optional",
)
dependencies += optionals.map { "implementation(\"$it\") //Optional" }

Expand Down
Loading

0 comments on commit b16fb72

Please sign in to comment.