https://kotlinlang.org logo
Title
j

joseph_ivie

08/09/2021, 3:20 PM
Working on automatic migrations in Ktorm: https://github.com/kotlin-orm/ktorm-migration
šŸ‘ 2
This is based on the Django ORM's migration system, which has been so solid that the prospect of living without it has been preventing my company from moving to another language for server development for years.
c

christophsturm

08/09/2021, 6:39 PM
it would be really cool if this was agnostic to orms (like ruby on rails migrations are. I don't know if djangos migration work only with djangos orm)
j

joseph_ivie

08/09/2021, 6:43 PM
Each ORM requires its own kind of table definition, and since the whole point is to reuse the ORM's table definitions to generate migrations, making it ORM agnostic would take away a lot of the value.
e

ESchouten

08/09/2021, 7:55 PM
Great! Was looking for this, using flyway right now. Might need to migrate from Exposed to Ktorm 😐
j

joseph_ivie

08/09/2021, 8:04 PM
@ESchouten Glad someone else might use it! Just be warned that there's a lot to be done yet. I'm not entirely certain it is usable right now, as it isn't thoroughly tested and needs a lot of documentation. Since you've shown interest at least, I'll make sure I keep this channel posted on when it is. I can assure you it will be done at some point because my company needs it for our next project.
e

ESchouten

08/09/2021, 8:14 PM
@joseph_ivie Thanks! I'll be keeping an eye on it, was yoyo-ing between Ktorm and Exposed anyways, time to do more research
c

christophsturm

08/10/2021, 5:58 AM
Each ORM requires its own kind of table definition,.... making it ORM agnostic would take away a lot of the value.
well Ruby on Rails has pretty nice migrations that are orm agnostic, so thats debatable. but it seems to be tied to jdbc anyway and I would need something that supports r2dbc.
j

joseph_ivie

08/10/2021, 6:22 AM
Fair enough - it would be nicer to run on something properly asynchronous. I chose Ktorm in the end merely because it was both well supported and I liked its API design. It might be possible to make it consume multiple kinds of table definitions (as in, from multiple ORM libraries) but I think in abstracting it you'd basically just end up rewriting it for each ORM anyways. Maybe I'm misunderstanding, but based on what I'm reading Rails's migrations are specific to its Active Record ORM?
c

christophsturm

08/10/2021, 6:54 AM
in rails migrations are the history of table changes, and theres also a schema.rb(or sql) file that represents the current schema. each migration file consists of things like
change_table :users do
  add_field :user, :int
...
end
at runtime rail (or activerecord) does not do anything with the migration files, it just works with database metadata
there are helpers like `create_join_table`or
add_belongs_to
that are tied to how activerecord works, but the migrations itself are just a ruby dsl for sql schema changes
j

joseph_ivie

08/10/2021, 7:23 AM
Cool, makes sense. Basically the same as what I did. Problem is Ktorm is the thing that translates that DSL into SQL right now, and migration generation comes from Ktorm-specific table declarations right now. The migrations could probably be separated out all right, but not the automatic generation of them. I think there's a Flyway that does migrations without autogeneration if that's what you're looking for.
c

christophsturm

08/10/2021, 7:35 AM
makes sense. I know flyway but I would like something thats more dsl like, and uses kotlin.
k

kqr

08/10/2021, 8:24 AM
liquibase has I think unofficial kotlin support
if I understand it correctly, you would compare existing state of DB to definition in ORM to dynamically generate scripts to get to desired state? in "flyway" way you do deterministing migrations i.e. https://www3.dbmaestro.com/blog/what-is-the-difference-between-state-driven-and-migration-driven-database-deployments
@christophsturm https://github.com/F43nd1r/liquibase-kotlin-dsl (yeah not very active)
c

christophsturm

08/10/2021, 8:33 AM
interesting, thanks!
d

dave08

08/10/2021, 9:10 AM
It looks like ktorm is not as active on github as exposed... Although i also like it's api better...
I had big doubts whether to invest in it if it won't be maintained in the future...
j

joseph_ivie

08/10/2021, 4:40 PM
That's kinda where I'm at after looking into Ktorm some more. The API might be better, but unfortunately, programming is frequently more about picking the thing that's used more often. Gradle might not exist if it weren't for that.
@kqr Actually, this is migration-driven. It virtually runs all of the previous migrations on an empty database and compares that to the current models to autogenerate a new migration.
k

kqr

08/10/2021, 5:06 PM
interesting
j

joseph_ivie

10/05/2021, 9:39 PM
@ESchouten @dave08 Figuring you two in particular might like to know: After some deeper investigation, I've made some extensions to Exposed that clean up its API instead and I'll be moving the migration stuff over to it. https://github.com/lightningkite/exposed-plus
šŸ‘ 1
d

dave08

10/06/2021, 9:13 AM
Looks interesting... I didn't like having to type up all those classes... and the current Entity type forces a dependency on all of exposed in the domain module since it requires an EntityId type... I'll have to see if I have a bit of time to pull out to try it šŸ˜‰.
e

ESchouten

10/06/2021, 1:50 PM
@joseph_ivie Very interesting! Using KSP for things like this seems promising. I myself am not sure if I would want library specific code in my domain models, but I see the opportunities it offers. Besides generating REST endpoints with security rules, another possibility could be Graphql endpoints + data fetchers I'm keeping my eye on this library!
Something this approach does largely fix is human error. I have encountered a lot of wrong or forgotten mapping of domain model properties on database table properties because it's such repetitious work. I ended up writing tests comparing the object being saved to the object returned from the database in order to prevent bugs like these
d

dave08

10/06/2021, 2:04 PM
I also don't like library specific code in the domain module... although it might be possible to overcome by using interfaces there, and implementing them in the data module with the annotations @ESchouten...?
e

ESchouten

10/06/2021, 2:17 PM
@dave08 Interesting approach, definitely is one way to do it, though might add some overhead Just a quick thought: Perhaps we could reference the class in some table configuration DSL and reference ID fields/other fields needing special configuration in some reflective way.
j

joseph_ivie

10/06/2021, 4:20 PM
@dave08 @ESchouten I was considering moving the annotations into their own package, so the domain module only has a dependency on a library with annotations only. Do you think that's good enough, or do you think total separation is necessary?
The key classes would have to be generated inside of the domain module too, unfortunately, but I think it could be limited to just the annotations, a simpler processor, and an interface for foreign keys
Actually, that might be incredibly useful. On the front end, you could create an extension function to request the object the foreign key points to from the server.
e

ESchouten

10/06/2021, 4:40 PM
@joseph_ivie I guess for most people that would be fine, people use JPA as well after all. Personally, the philosophy I use, 'Clean Architecture', is a bit more strict, seeing the database implementation not as a key part of the application but rather as a detail, so using the annotations would go against the principle Example: https://github.com/ESchouten/CleanArchitecture
j

joseph_ivie

10/06/2021, 4:53 PM
It makes sense. Bummer that makes it impossible to make a library like this then - foreign key class generation alone makes it not viable no matter how you would otherwise annotate the class in a separate file.
e

ESchouten

11/02/2021, 5:04 PM
@joseph_ivie thinking again about this again, instead of annotating in the domain classes, couldn't we create a "Table configuration" class?
class UserTable : TableConfiguration(User::class) {
    override fun configure() {
        id(User::id)
    }
}
Might look weird, typed this on mobile
j

joseph_ivie

11/02/2021, 5:08 PM
Yes, but what you can't do is the foreign key generation - I was using KSP to generate data classes representing foreign keys. Our company actually decided after some discussion to use Mongo instead, as it better fit what we were doing for our project, so unfortunately we won't be continuing on
exposed-plus
.