Giter Site home page Giter Site logo

medusa's Introduction

medusa - Simpler JDBC DSL

Alt text

Download MIT Licence

medusa is a jdbc-utilities library that is designed to reduce writing code pertaining to jdbc. No more closing of connection manually, no spawning your own preparedStatements. This helps reduce bugs where connection is not closed and bugs where column number are wrong.All this in a lightweight library that leverages Kotlin's ability to write DSLs. Medusa is not an ORM, it is just a utilities library to help you.

Features ๐Ÿš€

  • Minimal use of reflection magic
  • DSL which results in easier usage
  • Asynchronous Transactions support (using Kotlin's coroutines)

Changelog โŒš

[0.0.1 Experimental]

  • Transaction Support
  • Async Transaction
  • DSL for setting of config
  • Standard database operations (query, queryList, insert, exec)
  • TransactionResult type

[0.0.2 Experimental - Breaking API changes]

  • Reduce API differentiation for operation that returns a key and no key. (0.0.2)
  • Extend config to have support for databases that cannot generate keys (0.0.2)
  • Database Connection pooling using HikariCP
  • Removed TransactionResult type
  • Updated to Kotlin 1.3 coroutines, dispatches on Dispatcher.IO by default for transactionAsync

Planned changes/updates

  • Batch processing
  • Proper logger instead of println
  • Compile time generation of kotlin models based on database schema
  • Customizable Connection pool, apart from HikariCP
  • Compile time generation of frequently used SQL statements. Eg. INSERT INTO USER (email, username, passwordhash) VALUES (?,?,?)

Misc TODOs

  • Logo (why not, I can also design no kappa)
  • Website (again, why not lmao)
  • An actual fullstack example using Jetbrain's Ktor
  • Some simple benchmark

Config โš™๏ธ

Gradle

repositories {
    jcenter()
}
dependencies {
  compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.6' //depends on the driver you need
  compile 'com.budinverse.utils:medusa:<latest version>'
}

Setting up your DatabaseConfig via built-in DSL

fun main(args: Array<String>) {
    dbConfig {
        databaseUser = "root"
        databasePassword = "12345"
        databaseUrl = "jdbc:mysql://localhost/medusa_test?useLegacyDatetimeCode=false&serverTimezone=UTC"
        driver = "com.mysql.cj.jdbc.Driver"
        connectionPool = connectionPool {
            minimumIdle = 10
            maximumPoolSize = 15
            addDataSourceProperty("cachePrepStmts", "true")
            addDataSourceProperty("prepStmtCacheSize", "250")
            addDataSourceProperty("prepStmtCacheSqlLimit", "2048")
        }
    }
}

Examples ๐Ÿ“–

Assume that all examples has the following User class

data class User(val id: Int = 0,
                val name: String,
                val age: Int) {
        constructor(resultSet: ResultSet) : this(
                resultSet["id"],
                resultSet["name"],
                resultSet["age"]
        )
    }

Query

A single query

    fun queryPerson(): Person {
        lateinit var personRes: ExecResult.SingleResult<Person>
        transaction {
            personRes = query {
                statement = "SELECT * FROM User WHERE name = ?"
                values = arrayOf("zeon111")
                type = ::Person
            }
        }

        return personRes.transformed // User(id=18, name=Zeon111, age=20)
    }

    

Querying list of objects

    fun queryListPerson(): ArrayList<Person> {
        lateinit var personList: ExecResult.ListResult<Person>
        transaction {
            personList = queryList {
                statement = "SELECT * FROM person"
                type = ::Person
            }
        }

        return personList.transformedList // [User(id=18, name=Zeon111, age=20), User(id=19, name=Zeon222, age=20)]
    }

Insert

    fun insertTest(person: Person) {
        lateinit var ins: ExecResult.SingleResult<Int>
        transaction {
            ins = insert {
                statement = DummyData.insert
                values = arrayOf(person.name, person.age)
                type = {
                    it[1]
                }
            }
        }

        println(ins.transformed) // Auto generated PK
    }    

Update/Delete

For deletion just change the statement

    fun updateTest(person: Person) {
        lateinit var execResult: ExecResult.SingleResult<Person>
        transaction {
            execResult = update {
                statement = "UPDATE person SET name = ?, age = ? WHERE id = ?"
                values = arrayOf(person.name, person.age, 1)
                type = ::Person
            }
        }

    }

Performance ๐Ÿ“Š

As of now, since medusa is still not 1.0 yet, performance is NOT a focus. The focus is to provide and ergonomic API. However if you looking for ballpark of how medusa performs, here they are kappa

Computer: Intel Core i7 3770k @ 4.3Ghz, 16GB @ 2000Mhz RAM, Samsung 850 EVO 500GB, Windows 10 Education, MySQL 8.0

Medusa: Minimum 10, Maximum 15 connections in pool, Coroutines dispatched on Dispatchers.IO from standard library

Insert (asynchronous): Still benchmarking

Query (asynchronous): Still benchmarking

Computer: Macbook Pro (13-inch 2017) Intel Core i5 2.3Ghz, 8GB @ 2133Mhz

Medusa: Minimum 10, Maximum 15 connections in pool, Coroutines dispatched on Dispatchers.IO from standard library

Insert (asynchronous): Still benchmarking

Query (asynchronous): Still benchmarking

medusa's People

Contributors

zeon256 avatar

Watchers

 avatar

medusa's Issues

No way to get data from resultSet if it's piped to results list in TransactionBuilder

java.sql.SQLException: Operation not allowed after ResultSet closed

	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:127)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:95)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:87)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:61)
	at com.mysql.cj.jdbc.result.ResultSetImpl.checkClosed(ResultSetImpl.java:459)
	at com.mysql.cj.jdbc.result.ResultSetImpl.checkRowPos(ResultSetImpl.java:503)
	at com.mysql.cj.jdbc.result.ResultSetImpl.getObject(ResultSetImpl.java:1104)
	at com.budinverse.medusa.utils.ResultSetUtilsKt.get(ResultSetUtils.kt:5)
	at TransactionTest.txn(TransactionTest.kt:132)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)```

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.