Granite CLI?
It would be beyond awesome to have a CLI for Granite that allows for easier setup and database management. I know right now Granite::Migrator is kind of hidden and mostly for testing, but if we could make it more useful and expose it via a CLI I think it could really change things. Right now the only ORM (that I know of) with a decent CLI is Avram, but it's pretty well integrated into Lucky and requires the full Lucky CLI rather than having its own thing.
Ideally a good CLI should include the ability to:
- Create and drop a database
- Create migrations and models
- Run migrations
- Do some kind of database seeding
Any thoughts on this? Personally I would find it useful for tourmaline. I could probably work on a PoC.
@watzon Amber's CLI has all of the functionality you mentioned and uses Granite. amber db drop create migrate seed and amber generate model Post title:string body:text published:bool are the commands to do this. It uses micrate under the covers. You might be able to use it as a standalone solution.
@watzon I researched this a little more and the Amber CLI has some dependencies that make it a little difficult to use in stand-alone mode. We might be able to remove some of these dependencies to make this more usable.
Here are the steps to use it as a standalone if you are interested.
Install amber and create a new crystal app:
brew install amber
crystal init app test
cd test
add dependencies to shard.yml:
dependencies:
granite:
github: amberframework/granite
version: ~> 0.21.0
mysql:
github: crystal-lang/crystal-mysql
version: ~> 0.11.1
Install dependencies:
shards install
Create config/application.cr:
require "granite/adapter/mysql"
Granite::Connections << Granite::Adapter::Mysql.new(name: "mysql", url: "mysql://root@localhost:3306/test")
Require it in the src/test.cr application:
require "../config/application.cr"
Create an empty config/environments/development.yml. I think we can remove this dependency:
# empty file
Generate a model:
amber g model User name:string address:text city:string zipcode:string age:integer admin:bool
Create database and migrate:
amber db create migrate
I found a bug that the migration logs are not spitting out but they run. I will add a bug for that in the amber project.
Right, I'm using micrate right now, I'm just not a fan of having to write the SQL queries by hand. The main issue is that the queries aren't always compatible with different adapters because of differences in syntax, datatypes, etc. So if you change the adapter you also have to change all your migrations as well. That's something that could be fixed by creating an abstraction in the form of a "Migration" class that lets you define a schema, and then have it decide the best way to transform that into a migration for the given adapter. It's also just so much more user friendly.
The main reason I don't want to use the amber cli right now is exactly the reasons you mentioned. It, like the lucky cli, is pretty tightly integrated into the framework. If Avram was a little more free standing and had a way to handle migrations without using the lucky cli I'd be using it, but unfortunately it has the same issues.
I see. Unfortunately, the Migrator concept you described will not work in a real production environment. I built this in Granite about three years ago.
It would automatically look at your current schema and generate the proper DML to migrate it to the defined schema in your granite model objects. You would run the migration and the tool would add any new fields for you. It would also migrate the data for you if the name of the field was the same. Next, you would be responsible for migrating data between fields that were renamed. Finally, you would run the migration again but with a --destroy flag to remove any unused fields. It was an extremely DRY solution.
Sounds great, right?
The problem was that databases just don't work this way in the real world. You may have migrated your test database but your beta or production db may be 2 or 3 migrations old. You wouldn't know all the transformations that took place during development without some sort of migration scripts that described the steps. There is no way to know the intent of the developer without migration scripts that I know of.
I found that in practice, migration scripts are a better solution. If you are interested, I can dig up the old code and let you take a swing at it.
Regarding using DSL vs SQL DML, I understand the desire for cleaner code. That is a big factor in easier maintenance. I enjoy rails DSL for migrations and it is clean and easy to read. This is a really important to me. However, I also find myself constantly trying to remember how to define a create statement using the DSL. It's a toss up if I'm more productive using one vs the other.
Finally nothing disturbs me more than working with dev's that don't know SQL. They have never learned how a relational database works. They forget indexes and don't know how to get something into a proper normal form. They don't know how to prevent data integrity issues and never define foreign keys. All of this is because Rails makes the migration scripts DSL too simple and hides the complexity from the developer. Maybe it's just anecdotal evidence and I may be over reacting, but it's disturbing to me.