Skip to content
This repository has been archived by the owner on Apr 19, 2024. It is now read-only.

codebandits/beak

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

69 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Beak

Concourse Download

Beak is a functional Kotlin SQL DSL. It provides a type-safe, exception-free data access layer. Beak builds upon JetBrains' Exposed Kotlin SQL DSL library and the Arrow Kotlin functional programming library.

Alpha Release Considerations

Beak is in early stages of development and is released as alpha software. All aspects of the API are subject to change until our first release.

Currently, Beak is built as extension functions on top of the Exposed library's DAO layer. Beak may remove Exposed as a dependency which would significantly change the API.

Currently, Beak supports H2 and MySQL. We plan to support more databases in the future.

Installation

Add Beak's Maven repository to your build configuration:

https://dl.bintray.com/codebandits/beak

Find example dependency configurations for the latest version here:

Download

Usage

Here is a simple example comparing Exposed's .new {} with Beak's .newOrError {}:

import arrow.core.Either
import arrow.core.flatMap
import io.github.codebandits.beak.DataAccessError
import io.github.codebandits.beak.beakTransaction
import io.github.codebandits.beak.newOrError
import io.github.codebandits.beak.updateByIdOrError
import org.jetbrains.exposed.dao.EntityID
import org.jetbrains.exposed.dao.LongEntity
import org.jetbrains.exposed.dao.LongEntityClass
import org.jetbrains.exposed.dao.LongIdTable
import org.jetbrains.exposed.sql.Database
import org.jetbrains.exposed.sql.SchemaUtils.create
import org.jetbrains.exposed.sql.transactions.transaction

// Setup table objects and entity classes using Exposed's API:
object FeatherTable : LongIdTable("feathers") {
    val type = varchar("type", 255)
}

class FeatherEntity(id: EntityID<Long>) : LongEntity(id) {
    companion object : LongEntityClass<FeatherEntity>(FeatherTable)

    var type by FeatherTable.type
}

fun main(args: Array<String>) {
    Database.connect("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", driver = "org.h2.Driver")

    transaction { create(FeatherTable) }

    // Create a new Feather using Exposed's API.
    // This will throw exceptions when errors are encountered.
    val feather1: FeatherEntity = transaction {
        FeatherEntity.new {
            type = "contour"
        }
    }

    // Create a new Feather using Beak's API.
    // This will return a DataAccessError when errors are encountered.
    val feather2Result: Either<DataAccessError, FeatherEntity> = FeatherEntity.newOrError {
        type = "down"
    }

    // Combine multiple operations in one transaction to link rollbacks for all the data access operations.
    // When the second operations fails the first operation will also be rolled back, returning a DataAccessError.
    val feather3Result: Either<DataAccessError, FeatherEntity> = beakTransaction {
        FeatherEntity.newOrError { type = "down" }
            .flatMap { featherEntity ->
                FeatherEntity.updateByIdOrError(featherEntity.id.value) { type = "x".repeat(500) }
            }
    }

    when (feather3Result) {
        is Either.Right -> println("operation succeeded: ${feather3Result.b}")
        is Either.Left -> println("operation failed: ${feather3Result.a}") // This one prints
    }
}

Error Handling

Beak's data access functions endeavor to never throw exceptions. Instead, they return an Either data type with a DataAccessError as the left hand side. DataAccessError is a sealed class hierarchy of all possible data access errors so you can use functional patterns to efficiently handle all data access failures in your application.

See Railway Oriented Programming for more insight into this error handling approach.

Releases

No releases published

Packages

No packages published

Languages