Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Granite::ORM.migrator to production codes #172

Closed
wants to merge 5 commits into from

Conversation

maiha
Copy link
Contributor

@maiha maiha commented Mar 31, 2018

Dry up codes about creating tables in specs, and put it production code as Granite::ORM.migrator.
This helps users

  • to add tables in specs easily
  • to create tables in experiment and deployment
class User < Granite::ORM::Base
  adapter mysql
  field name : String
end

User.migrator.create
mysql> describe users;
+-------+--------------+------+-----+---------+----------------+
| Field | Type         | Null | Key | Default | Extra          |
+-------+--------------+------+-----+---------+----------------+
| id    | bigint(20)   | NO   | PRI | NULL    | auto_increment |
| name  | varchar(255) | YES  |     | NULL    |                |
+-------+--------------+------+-----+---------+----------------+

implementation

  • mapping rules from crystal class to database type is defined in adapters.
    • Granite::Adapter::Base::Schema::Types
    • Granite::Adapter::Mysql::Schema::Types
    • ...

I just defined rules about basic classes used in current specs.

  • Bool, Float32, Float64, Int32, Int64, String, Time

If migrator is exected with undefined types, it raises a runtime error as below.

Migrator(Granite::Adapter::Mysql) doesn't support 'Time::Span' yet. (Exception)

Best regards,

@faustinoaq faustinoaq requested a review from a team March 31, 2018 22:59
Copy link
Member

@drujensen drujensen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Would like us to consider renaming up -> create and down -> drop to stay inline with drop_and_create. wdyt?

up
end

def down
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about renaming this to drop?

def down
end

def up
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and this to create?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initially, I imagined cooperating with micrate as below, so I choose these names.

-- +micrate Up
User.migrator.up

-- +micrate Down
User.migrator.down

But, I found that micrate can handle only SQL string. Therefore, since there are no constraints now, I think that it is better to change the name as you say. 😺

Copy link
Member

@robacarp robacarp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat idea, and a good contribution. I like the way it cleans up the tests, but I also think it could be useful for removing micrate as a dependency in the future.

module Schema
TYPES = {
"AUTO_Int32" => "INT NOT NULL AUTO_INCREMENT PRIMARY KEY",
"AUTO_Int64" => "BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The capitalization here is unexpected. Why AUTO_Int32?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I'd like to resolve three kinds of crystal objects here.

  1. Auto number (value + metadata like Int32 or Int64 + this is autonumber)
  2. All crystal classes with module name (value like Int32, Foo::Data)
  3. special field variables (value like created_at , updated_at)

Here, since they can be represented by strings itself for the case of 2 and 3, we can use simple Hash(String, String) for the mapping dictionary.
Then, I faced a problem of how to embed the meta information of autonumber in the payload for the case 1.

Although there are various correct and complicated implementations, I prioritized the simplicity of implementation, and I embedded the meta information as "uppercase letters + _" in the string for the time being. 😸

Copy link
Member

@robacarp robacarp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only thing I'd like to see is some test coverage. I know that this code will run as part of the test suite at this time, but it seems like the kind of code that will end up getting used elsewhere as well quickly so I'd like to have coverage over it.

module Schema
TYPES = {
"AUTO_Int32" => "INT NOT NULL AUTO_INCREMENT PRIMARY KEY",
"AUTO_Int64" => "BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add some quick tests for these in the adapter tests? I'd like to have them covered against accidental changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think it would be better to have a test. But I can not image a simple test. But, even now, Int32 and Int64 are used as primary keys in other specs, so I think the code has been covered. 😺

@drujensen
Copy link
Member

@robacarp we will not be replacing micrate with this anytime soon. I used to have this exact logic in granite to automatically perform migrations, but it was too difficult to guess the intent of the developer. For example, you didn't know what data to copy to which field if they renamed a column.

@robacarp
Copy link
Member

robacarp commented Apr 2, 2018

@drujensen Sorry, I wasn't meaning to suggest we'd provide facility for automatic migrations. Only that I can see the maintenance overhead for yet another shard being abandoned by its creator getting adopted by Amber, and absorbing the idea of a migrator into granite doesn't seem far fetched. Should that happen, the namespace Migrator is probably where it'd live.

@drujensen
Copy link
Member

@robacarp gotcha. Don't get me wrong, I loved it when the migrations were built in. It was additive so it never broke anything, but it couldn't do certain things and those limitations would require something like micrate anyway. This PR is a good compromise and really cleans up the code. I am very happy to see this solution. It fits in between the gap that I lost when moving to micrate.


User.migrator.drop_and_create
# => "DROP TABLE IF EXISTS `users`;"
# => "CREATE TABLE `users` (id BIGSERIAL PRIMARY KEY, name VARCHAR(255));"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That should probably be id BIGINT or id INT since BIGSERIAL is PostgreSQL specific.

@drujensen
Copy link
Member

@maiha Something is breaking the Migrator. I updated to the latest master branch and looks like I broke it:

Migrator(Granite::Adapter::Pg) doesn't support '{type: String}' yet. (Exception)
  from spec/spec_models.cr:255:3 in 'create'

Can you take a look when you get a chance?

@maiha
Copy link
Contributor Author

maiha commented Apr 26, 2018

I am sorry, my main business has been very busy since April, and I have not had time to contribute to OSS recently.
Unfortunately, this situation seems to last for half a year, so I will close this PR once. 😢

@maiha maiha closed this Apr 26, 2018
@drujensen
Copy link
Member

@maiha Ok, i will fork this and fix it. Thanks for your contributions! Hope to see you back soon. 🥇

@drujensen drujensen reopened this Apr 27, 2018
@drujensen drujensen closed this May 12, 2018
@faustinoaq faustinoaq removed the pr:wip label May 12, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants