· 8 years ago · Mar 10, 2018, 03:34 AM
1module Sequel
2 class Model
3 # Create a class for renaming and modifying the model's table info
4 class Migration
5 include Sequel::Schema::SQL
6 attr_reader :db, :table_name
7 def initialize(db, table_name)
8 @db, @table_name = db, table_name
9 end
10
11 def get_column_type(column_name)
12 if (column = db.table_columns(table_name)[column_name.to_s])
13 column[:Type]
14 end
15 end
16
17 def rename_column(names = {})
18 names.each_pair do |old_name, new_name|
19 modify_column(old_name, :name => new_name)
20 end
21 end
22
23 def modify_column(column_name, opts = {})
24 opts[:name] ||= column_name
25 opts[:type] ||= get_column_type(column_name)
26 raise "Can't get column type for #{column_name}" unless opts[:type]
27 db.execute("ALTER TABLE `#{table_name}` CHANGE #{column_name} #{column_definition_sql(opts)}")
28 end
29 end
30
31 # Let the user call "migrate" on a model to bring it up to date
32 class << self
33 def migration
34 Migration.new(db, table_name)
35 end
36
37 # Executes +sql+ if the model's table is not up to date
38 def migrate(sql = nil)
39 if (memory_revision = get_memory_revision) < (table_revision = get_table_revision)
40 set_memory_revision(memory_revision += 1)
41 else
42 db.query(sql) if sql
43 yield migration if block_given?
44 table_revision += 1
45 set_table_revision(table_revision)
46 set_memory_revision(table_revision)
47 end
48 end
49
50 alias :model_migration_drop_table :drop_table
51 def drop_table
52 model_migration_drop_table
53 # Reset the table revision counter when we drop a table
54 set_table_revision(0)
55 end
56
57 def create_table
58 db.create_table_sql_list(*schema.create_info).each {|s| db << s}
59 end
60
61 def start_at_revision(revision = 0) set_memory_revision(revision) end
62
63 protected
64 # Gets the current migration revision stored in memory.
65 def get_memory_revision
66 @memory_revision || 0
67 end
68
69 # Sets the current migration revision stored in memory.
70 def set_memory_revision(revision = 0)
71 @memory_revision = revision
72 end
73
74 # Gets the current migration revision stored in the database. Returns a
75 # tuple: [major, minor] (e.g. [2, 0])
76 def get_table_revision
77 r = table_revisions_dataset.filter(:table_name => table_name.to_s).first
78 r ? r[:major] : 0
79 end
80
81 # Sets the current migration version stored in the database.
82 def set_table_revision(revision = 0)
83 dataset = table_revisions_dataset.filter(:table_name => table_name.to_s)
84 if dataset.first
85 dataset.update(:major => revision, :minor => 0)
86 else
87 dataset << {:table_name => table_name.to_s, :major => revision, :minor => 0}
88 end
89 end
90
91 # Returns the dataset for the table_revisions table. If no such table
92 # exists, it is automatically created.
93 def table_revisions_dataset
94 unless db.table_exists?(:table_revisions)
95 db.create_table(:table_revisions) do
96 primary_key :id
97 text :table_name
98 integer :major, :default => 0
99 integer :minor, :default => 0
100 end
101 end
102 db[:table_revisions]
103 end
104 end
105 end
106end