db_leftovers 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.html ADDED
@@ -0,0 +1,102 @@
1
+ <h1>db_leftovers</h1>
2
+
3
+ <p>db_leftovers lets you define indexes and foreign keys for your Rails app
4
+ in one place using an easy-to-read DSL,
5
+ then run a rake task to bring your database up-to-date.
6
+ I wrote this because I didn't want indexes and foreign keys scattered throughout my migrations or buried in my <code>schema.rb</code>, and I wanted a command I could run to ensure that they matched across my development, test, staging, and production databases.
7
+ This was particularly a problem for Heroku projects, because <code>db:push</code> and <code>db:pull</code> do not transfer your foreign keys.
8
+ But now that it's written, I'm finding it useful on non-Heroku projects as well.</p>
9
+
10
+ <p>At present db_leftovers works only on PostgreSQL databases,
11
+ but it could easily be extended to cover other RDBMSes.</p>
12
+
13
+ <h2>Configuration File</h2>
14
+
15
+ <p>db_leftovers reads a file named <code>config/db_leftovers.rb</code> to find out which indexes and foreign keys you want in your database. This file is a DSL implemented in Ruby, sort of like <code>config/routes.rb</code>. There are only a few methods:</p>
16
+
17
+ <h3>index table_name, columns, [opts]</h3>
18
+
19
+ <p>This ensures that you have an index on the given table and column(s). The <code>columns</code> parameter can be either a string or a list of strings. Opts is a hash with the following possible keys:</p>
20
+
21
+ <ul>
22
+ <li><p><code>:name</code> The name of the index. Defaults to <code>index_</code><em>table_name</em><code>_on_</code><em>column_names</em>, like the <code>add_index</code> method from Rails migrations.</p></li>
23
+ <li><p><code>:unique</code> Set this to <code>true</code> if you'd like a unique index.</p></li>
24
+ <li><p><code>:where</code> Accepts SQL to include in the <code>WHERE</code> part of the <code>CREATE INDEX</code> command, in case you want to limit the index to a subset of the table's rows.</p></li>
25
+ </ul>
26
+
27
+ <h4>Examples</h4>
28
+
29
+ <pre><code>index :books, :author_id
30
+ index :books, [:publisher_id, :published_at]
31
+ index :books, :isbn, :unique =&gt; true
32
+ </code></pre>
33
+
34
+ <h3>foreign_key from_table, from_column, to_table, [to_column, [opts]]</h3>
35
+
36
+ <p>This ensures that you have a foreign key relating the given tables and columns.
37
+ All parameters are strings except <code>opts</code>, which is a hash.
38
+ If you don't pass anything for <code>opts</code>, you can leave off the <code>to_column</code> parameter, and it will default to <code>:id</code>.
39
+ These options are supported:</p>
40
+
41
+ <ul>
42
+ <li><code>:set_null</code> Indicates that the foreign key should be set to null if the referenced row is deleted.</li>
43
+ <li><code>:cascade</code> Indicates that the referencing row should be deleted if the referenced row is deleted.</li>
44
+ </ul>
45
+
46
+ <p>These options are mutually exclusive. They should probably be consolidated into a single option like <code>:on_delete</code>.</p>
47
+
48
+ <h4>Examples</h4>
49
+
50
+ <pre><code>foreign_key :books, :author_id, :authors, :id
51
+ foreign_key :books, :publisher_id, :publishers
52
+ foreign_key :pages, :book_id, :books, :id, :cascade =&gt; true
53
+ </code></pre>
54
+
55
+ <h3>table table_name, &amp;block</h3>
56
+
57
+ <p>The <code>table</code> call is just a convenience so you can group all a table's indexes and foreign keys together and not keep repeating the table name. You use it like this:</p>
58
+
59
+ <pre><code>table :books do
60
+ index :author_id
61
+ foreign_key :publisher_id, :publishers
62
+ end
63
+ </code></pre>
64
+
65
+ <p>You can repeat <code>table</code> calls for the same table several times if you like. This lets you put your indexes in one place and your foreign keys in another.</p>
66
+
67
+ <h2>Running db_leftovers</h2>
68
+
69
+ <p>db_leftovers comes with a Rake task named <code>db:leftovers</code>. So you can update your database to match your config file by saying this:</p>
70
+
71
+ <pre><code>rake db:leftovers
72
+ </code></pre>
73
+
74
+ <h2>Known Issues</h2>
75
+
76
+ <ul>
77
+ <li><p>db_leftovers only supports PostgreSQL databases.
78
+ If you want to add support for something else, just send me a pull request!</p></li>
79
+ <li><p>db_leftovers will not notice if an index/foreign key definition changes.
80
+ Right now it only checks for existence/non-existence.</p></li>
81
+ <li><p>If your database is mostly up-to-date, then running the Rake task will spam
82
+ you with messages about how this index and that foreign key already exist.
83
+ These should be hidden by default and shown only if you request a higher
84
+ verbosity.</p></li>
85
+ </ul>
86
+
87
+ <h2>Contributing to db_leftovers</h2>
88
+
89
+ <ul>
90
+ <li>Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet</li>
91
+ <li>Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it</li>
92
+ <li>Fork the project</li>
93
+ <li>Start a feature/bugfix branch</li>
94
+ <li>Commit and push until you are happy with your contribution</li>
95
+ <li>Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.</li>
96
+ <li>Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.</li>
97
+ </ul>
98
+
99
+ <h2>Copyright</h2>
100
+
101
+ <p>Copyright (c) 2012 Paul A. Jungwirth. See LICENSE.txt for
102
+ further details.</p>
data/README.md ADDED
@@ -0,0 +1,104 @@
1
+ db\_leftovers
2
+ =============
3
+
4
+ db\_leftovers lets you define indexes and foreign keys for your Rails app
5
+ in one place using an easy-to-read DSL,
6
+ then run a rake task to bring your database up-to-date.
7
+ I wrote this because I didn't want indexes and foreign keys scattered throughout my migrations or buried in my `schema.rb`, and I wanted a command I could run to ensure that they matched across my development, test, staging, and production databases.
8
+ This was particularly a problem for Heroku projects, because `db:push` and `db:pull` do not transfer your foreign keys.
9
+ But now that it's written, I'm finding it useful on non-Heroku projects as well.
10
+
11
+ At present db\_leftovers works only on PostgreSQL databases,
12
+ but it could easily be extended to cover other RDBMSes.
13
+
14
+ Configuration File
15
+ ------------------
16
+
17
+ db\_leftovers reads a file named `config/db_leftovers.rb` to find out which indexes and foreign keys you want in your database. This file is a DSL implemented in Ruby, sort of like `config/routes.rb`. There are only a few methods:
18
+
19
+ ### index table\_name, columns, [opts]
20
+
21
+ This ensures that you have an index on the given table and column(s). The `columns` parameter can be either a string or a list of strings. Opts is a hash with the following possible keys:
22
+
23
+ * `:name` The name of the index. Defaults to `index_`*table\_name*`_on_`*column\_names*, like the `add_index` method from Rails migrations.
24
+
25
+ * `:unique` Set this to `true` if you'd like a unique index.
26
+
27
+ * `:where` Accepts SQL to include in the `WHERE` part of the `CREATE INDEX` command, in case you want to limit the index to a subset of the table's rows.
28
+
29
+ #### Examples
30
+
31
+ index :books, :author_id
32
+ index :books, [:publisher_id, :published_at]
33
+ index :books, :isbn, :unique => true
34
+
35
+ ### foreign\_key from\_table, from\_column, to\_table, [to\_column, [opts]]
36
+
37
+ This ensures that you have a foreign key relating the given tables and columns.
38
+ All parameters are strings except `opts`, which is a hash.
39
+ If you don't pass anything for `opts`, you can leave off the `to_column` parameter, and it will default to `:id`.
40
+ These options are supported:
41
+
42
+ * `:set_null` Indicates that the foreign key should be set to null if the referenced row is deleted.
43
+ * `:cascade` Indicates that the referencing row should be deleted if the referenced row is deleted.
44
+
45
+ These options are mutually exclusive. They should probably be consolidated into a single option like `:on_delete`.
46
+
47
+ #### Examples
48
+
49
+ foreign_key :books, :author_id, :authors, :id
50
+ foreign_key :books, :publisher_id, :publishers
51
+ foreign_key :pages, :book_id, :books, :id, :cascade => true
52
+
53
+ ### table table\_name, &block
54
+
55
+ The `table` call is just a convenience so you can group all a table's indexes and foreign keys together and not keep repeating the table name. You use it like this:
56
+
57
+ table :books do
58
+ index :author_id
59
+ foreign_key :publisher_id, :publishers
60
+ end
61
+
62
+ You can repeat `table` calls for the same table several times if you like. This lets you put your indexes in one place and your foreign keys in another.
63
+
64
+
65
+ Running db\_leftovers
66
+ ---------------------
67
+
68
+ db\_leftovers comes with a Rake task named `db:leftovers`. So you can update your database to match your config file by saying this:
69
+
70
+ rake db:leftovers
71
+
72
+
73
+ Known Issues
74
+ ------------
75
+
76
+ * db\_leftovers only supports PostgreSQL databases.
77
+ If you want to add support for something else, just send me a pull request!
78
+
79
+ * db\_leftovers will not notice if an index/foreign key definition changes.
80
+ Right now it only checks for existence/non-existence.
81
+
82
+ * If your database is mostly up-to-date, then running the Rake task will spam
83
+ you with messages about how this index and that foreign key already exist.
84
+ These should be hidden by default and shown only if you request a higher
85
+ verbosity.
86
+
87
+
88
+ Contributing to db\_leftovers
89
+ -----------------------------
90
+
91
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
92
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
93
+ * Fork the project
94
+ * Start a feature/bugfix branch
95
+ * Commit and push until you are happy with your contribution
96
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
97
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
98
+
99
+ Copyright
100
+ ---------
101
+
102
+ Copyright (c) 2012 Paul A. Jungwirth. See LICENSE.txt for
103
+ further details.
104
+
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ - Write the README
2
+ - Support altering index and foreign keys if their definition changes
3
+ - don't show "{index,fk} already exists" unless you set the verbosity higher
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
data/db_leftovers.gemspec CHANGED
@@ -5,28 +5,35 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "db_leftovers"
8
- s.version = "0.2.0"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Paul A. Jungwirth"]
12
- s.date = "2012-01-17"
12
+ s.date = "2012-01-20"
13
13
  s.description = " Define indexes and foreign keys for your Rails app\n in one place using an easy-to-read DSL,\n then run a rake task to bring your database up-to-date.\n"
14
14
  s.email = "pj@illuminatedcomputing.com"
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE.txt",
17
- "README.rdoc"
17
+ "README.html",
18
+ "README.md",
19
+ "TODO"
18
20
  ]
19
21
  s.files = [
20
22
  ".document",
21
23
  "Gemfile",
22
24
  "Gemfile.lock",
23
25
  "LICENSE.txt",
24
- "README.rdoc",
26
+ "README.md",
25
27
  "Rakefile",
26
28
  "VERSION",
27
29
  "db_leftovers.gemspec",
28
30
  "lib/db_leftovers.rb",
31
+ "lib/db_leftovers/database_interface.rb",
32
+ "lib/db_leftovers/definition.rb",
29
33
  "lib/db_leftovers/dsl.rb",
34
+ "lib/db_leftovers/foreign_key.rb",
35
+ "lib/db_leftovers/index.rb",
36
+ "lib/db_leftovers/table_dsl.rb",
30
37
  "lib/tasks/leftovers.rake",
31
38
  "spec/db_leftovers_spec.rb",
32
39
  "spec/spec_helper.rb"
@@ -0,0 +1,88 @@
1
+ module DBLeftovers
2
+
3
+ class DatabaseInterface
4
+
5
+ def lookup_all_indexes
6
+ ret = {}
7
+ sql = <<-EOQ
8
+ SELECT n.nspname as "Schema", c.relname as "Name",
9
+ CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' END as "Type",
10
+ u.usename as "Owner",
11
+ c2.relname as "Table"
12
+ FROM pg_catalog.pg_class c
13
+ JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid
14
+ JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid
15
+ LEFT JOIN pg_catalog.pg_user u ON u.usesysid = c.relowner
16
+ LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
17
+ WHERE c.relkind IN ('i','')
18
+ AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
19
+ AND pg_catalog.pg_table_is_visible(c.oid)
20
+ AND c.relname NOT LIKE '%_pkey'
21
+ AND c2.relname NOT IN ('delayed_jobs', 'schema_migrations')
22
+ ORDER BY 1,2;
23
+ EOQ
24
+ ActiveRecord::Base.connection.select_rows(sql).each do |schema, index_name, object_type, owner, table_name|
25
+ ret[index_name] = table_name
26
+ end
27
+ return ret
28
+ end
29
+
30
+ def lookup_all_foreign_keys
31
+ ret = {}
32
+ sql = <<-EOQ
33
+ SELECT t.constraint_name, t.table_name, k.column_name, t.constraint_type, c.table_name, c.column_name
34
+ FROM information_schema.table_constraints t,
35
+ information_schema.constraint_column_usage c,
36
+ information_schema.key_column_usage k
37
+ WHERE t.constraint_name = c.constraint_name
38
+ AND k.constraint_name = c.constraint_name
39
+ AND t.constraint_type = 'FOREIGN KEY'
40
+ EOQ
41
+ ActiveRecord::Base.connection.select_rows(sql).each do |constr_name, from_table, from_column, constr_type, to_table, to_column|
42
+ ret[constr_name] = ForeignKey.new(constr_name, from_table, from_column, to_table, to_column)
43
+ end
44
+ return ret
45
+ end
46
+
47
+ def execute_add_index(idx)
48
+ unique = idx.unique? ? 'UNIQUE' : ''
49
+ where = idx.where_clause.present? ? "WHERE #{idx.where_clause}" : ''
50
+
51
+ sql = <<-EOQ
52
+ CREATE #{unique} INDEX #{idx.index_name}
53
+ ON #{idx.table_name}
54
+ (#{idx.column_names.join(', ')})
55
+ #{where}
56
+ EOQ
57
+ execute_sql(sql)
58
+ end
59
+
60
+ def execute_drop_index(table_name, index_name)
61
+ sql = <<-EOQ
62
+ DROP INDEX #{index_name}
63
+ EOQ
64
+ execute_sql(sql)
65
+ end
66
+
67
+ def execute_add_foreign_key(fk)
68
+ on_delete = "ON DELETE CASCADE" if fk.cascade
69
+ on_delete = "ON DELETE SET NULL" if fk.set_null
70
+ execute_sql %{ALTER TABLE #{fk.from_table}
71
+ ADD CONSTRAINT #{fk.constraint_name}
72
+ FOREIGN KEY (#{fk.from_column})
73
+ REFERENCES #{fk.to_table} (#{fk.to_column})
74
+ #{on_delete}}
75
+ end
76
+
77
+ def execute_drop_foreign_key(constraint_name, from_table, from_column)
78
+ execute_sql %{ALTER TABLE #{from_table}
79
+ DROP CONSTRAINT #{constraint_name}}
80
+ end
81
+
82
+ def execute_sql(sql)
83
+ ActiveRecord::Base.connection.execute(sql)
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,16 @@
1
+ module DBLeftovers
2
+
3
+ class Definition
4
+ def self.define(opts={}, &block)
5
+ opts = {
6
+ :do_indexes => true,
7
+ :do_foreign_keys => true
8
+ }.merge(opts)
9
+ dsl = DSL.new
10
+ dsl.define(&block)
11
+ dsl.record_indexes if opts[:do_indexes]
12
+ dsl.record_foreign_keys if opts[:do_foreign_keys]
13
+ end
14
+ end
15
+
16
+ end
@@ -1,97 +1,5 @@
1
1
  module DBLeftovers
2
2
 
3
- class Definition
4
- def self.define(opts={}, &block)
5
- opts = {
6
- :do_indexes => true,
7
- :do_foreign_keys => true
8
- }.merge(opts)
9
- dsl = DSL.new
10
- dsl.define(&block)
11
- dsl.record_indexes if opts[:do_indexes]
12
- dsl.record_foreign_keys if opts[:do_foreign_keys]
13
- end
14
- end
15
-
16
-
17
- private
18
-
19
- # Just a struct to hold all the info for one index:
20
- class Index
21
- attr_accessor :table_name, :column_names, :index_name,
22
- :where_clause, :unique
23
-
24
- def initialize(table_name, column_names, opts={})
25
- opts = {
26
- :where => nil,
27
- :unique => false,
28
- }.merge(opts)
29
- opts.keys.each do |k|
30
- raise "Unknown option: #{k}" unless [:where, :unique, :name].include?(k)
31
- end
32
- @table_name = table_name.to_s
33
- @column_names = [column_names].flatten.map{|x| x.to_s}
34
- @where_clause = opts[:where]
35
- @unique = opts[:unique]
36
- @index_name = opts[:name] || choose_name(@table_name, @column_names)
37
- end
38
-
39
- def unique?
40
- @unique
41
- end
42
-
43
- private
44
-
45
- def choose_name(table_name, column_names)
46
- "index_#{table_name}_on_#{column_names.join('_and_')}"
47
- end
48
-
49
- end
50
-
51
-
52
- class ForeignKey
53
- attr_accessor :constraint_name, :from_table, :from_column, :to_table, :to_column, :set_null, :cascade
54
-
55
- def initialize(constraint_name, from_table, from_column, to_table, to_column, opts={})
56
- opts = {
57
- :set_null => false,
58
- :cascade => false
59
- }.merge(opts)
60
- opts.keys.each do |k|
61
- raise "Unknown option: #{k}" unless [:set_null, :cascade].include?(k)
62
- end
63
- @constraint_name = constraint_name
64
- @from_table = from_table
65
- @from_column = from_column
66
- @to_table = to_table
67
- @to_column = to_column
68
-
69
- @set_null = opts[:set_null]
70
- @cascade = opts[:cascade]
71
-
72
- raise "ON DELETE can't be both set_null and cascade" if @set_null and @cascade
73
- end
74
- end
75
-
76
- class TableDSL
77
- def initialize(dsl, table_name)
78
- @dsl = dsl
79
- @table_name = table_name
80
- end
81
-
82
- def define(&block)
83
- instance_eval(&block)
84
- end
85
-
86
- def index(column_names, opts={})
87
- @dsl.index(@table_name, column_names, opts)
88
- end
89
-
90
- def foreign_key(from_column, to_table, to_column='id', opts={})
91
- @dsl.foreign_key(@table_name, from_column, to_table, to_column, opts)
92
- end
93
- end
94
-
95
3
  class DSL
96
4
  def initialize
97
5
  @db = DatabaseInterface.new
@@ -201,89 +109,4 @@ module DBLeftovers
201
109
 
202
110
  end
203
111
 
204
- class DatabaseInterface
205
-
206
- def lookup_all_indexes
207
- ret = {}
208
- sql = <<-EOQ
209
- SELECT n.nspname as "Schema", c.relname as "Name",
210
- CASE c.relkind WHEN 'r' THEN 'table' WHEN 'v' THEN 'view' WHEN 'i' THEN 'index' WHEN 'S' THEN 'sequence' WHEN 's' THEN 'special' END as "Type",
211
- u.usename as "Owner",
212
- c2.relname as "Table"
213
- FROM pg_catalog.pg_class c
214
- JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid
215
- JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid
216
- LEFT JOIN pg_catalog.pg_user u ON u.usesysid = c.relowner
217
- LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
218
- WHERE c.relkind IN ('i','')
219
- AND n.nspname NOT IN ('pg_catalog', 'pg_toast')
220
- AND pg_catalog.pg_table_is_visible(c.oid)
221
- AND c.relname NOT LIKE '%_pkey'
222
- AND c2.relname NOT IN ('delayed_jobs', 'schema_migrations')
223
- ORDER BY 1,2;
224
- EOQ
225
- ActiveRecord::Base.connection.select_rows(sql).each do |schema, index_name, object_type, owner, table_name|
226
- ret[index_name] = table_name
227
- end
228
- return ret
229
- end
230
-
231
- def lookup_all_foreign_keys
232
- ret = {}
233
- sql = <<-EOQ
234
- SELECT t.constraint_name, t.table_name, k.column_name, t.constraint_type, c.table_name, c.column_name
235
- FROM information_schema.table_constraints t,
236
- information_schema.constraint_column_usage c,
237
- information_schema.key_column_usage k
238
- WHERE t.constraint_name = c.constraint_name
239
- AND k.constraint_name = c.constraint_name
240
- AND t.constraint_type = 'FOREIGN KEY'
241
- EOQ
242
- ActiveRecord::Base.connection.select_rows(sql).each do |constr_name, from_table, from_column, constr_type, to_table, to_column|
243
- ret[constr_name] = ForeignKey.new(constr_name, from_table, from_column, to_table, to_column)
244
- end
245
- return ret
246
- end
247
-
248
- def execute_add_index(idx)
249
- unique = idx.unique? ? 'UNIQUE' : ''
250
- where = idx.where_clause.present? ? "WHERE #{idx.where_clause}" : ''
251
-
252
- sql = <<-EOQ
253
- CREATE #{unique} INDEX #{idx.index_name}
254
- ON #{idx.table_name}
255
- (#{idx.column_names.join(', ')})
256
- #{where}
257
- EOQ
258
- execute_sql(sql)
259
- end
260
-
261
- def execute_drop_index(table_name, index_name)
262
- sql = <<-EOQ
263
- DROP INDEX #{index_name}
264
- EOQ
265
- execute_sql(sql)
266
- end
267
-
268
- def execute_add_foreign_key(fk)
269
- on_delete = "ON DELETE CASCADE" if fk.cascade
270
- on_delete = "ON DELETE SET NULL" if fk.set_null
271
- execute_sql %{ALTER TABLE #{fk.from_table}
272
- ADD CONSTRAINT #{fk.constraint_name}
273
- FOREIGN KEY (#{fk.from_column})
274
- REFERENCES #{fk.to_table} (#{fk.to_column})
275
- #{on_delete}}
276
- end
277
-
278
- def execute_drop_foreign_key(constraint_name, from_table, from_column)
279
- execute_sql %{ALTER TABLE #{from_table}
280
- DROP CONSTRAINT #{constraint_name}}
281
- end
282
-
283
- def execute_sql(sql)
284
- ActiveRecord::Base.connection.execute(sql)
285
- end
286
-
287
- end
288
-
289
112
  end
@@ -0,0 +1,27 @@
1
+ module DBLeftovers
2
+
3
+ class ForeignKey
4
+ attr_accessor :constraint_name, :from_table, :from_column, :to_table, :to_column, :set_null, :cascade
5
+
6
+ def initialize(constraint_name, from_table, from_column, to_table, to_column, opts={})
7
+ opts = {
8
+ :set_null => false,
9
+ :cascade => false
10
+ }.merge(opts)
11
+ opts.keys.each do |k|
12
+ raise "Unknown option: #{k}" unless [:set_null, :cascade].include?(k)
13
+ end
14
+ @constraint_name = constraint_name
15
+ @from_table = from_table
16
+ @from_column = from_column
17
+ @to_table = to_table
18
+ @to_column = to_column
19
+
20
+ @set_null = opts[:set_null]
21
+ @cascade = opts[:cascade]
22
+
23
+ raise "ON DELETE can't be both set_null and cascade" if @set_null and @cascade
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,35 @@
1
+ module DBLeftovers
2
+
3
+ # Just a struct to hold all the info for one index:
4
+ class Index
5
+ attr_accessor :table_name, :column_names, :index_name,
6
+ :where_clause, :unique
7
+
8
+ def initialize(table_name, column_names, opts={})
9
+ opts = {
10
+ :where => nil,
11
+ :unique => false,
12
+ }.merge(opts)
13
+ opts.keys.each do |k|
14
+ raise "Unknown option: #{k}" unless [:where, :unique, :name].include?(k)
15
+ end
16
+ @table_name = table_name.to_s
17
+ @column_names = [column_names].flatten.map{|x| x.to_s}
18
+ @where_clause = opts[:where]
19
+ @unique = opts[:unique]
20
+ @index_name = opts[:name] || choose_name(@table_name, @column_names)
21
+ end
22
+
23
+ def unique?
24
+ @unique
25
+ end
26
+
27
+ private
28
+
29
+ def choose_name(table_name, column_names)
30
+ "index_#{table_name}_on_#{column_names.join('_and_')}"
31
+ end
32
+
33
+ end
34
+
35
+ end
@@ -0,0 +1,22 @@
1
+ module DBLeftovers
2
+
3
+ class TableDSL
4
+ def initialize(dsl, table_name)
5
+ @dsl = dsl
6
+ @table_name = table_name
7
+ end
8
+
9
+ def define(&block)
10
+ instance_eval(&block)
11
+ end
12
+
13
+ def index(column_names, opts={})
14
+ @dsl.index(@table_name, column_names, opts)
15
+ end
16
+
17
+ def foreign_key(from_column, to_table, to_column='id', opts={})
18
+ @dsl.foreign_key(@table_name, from_column, to_table, to_column, opts)
19
+ end
20
+ end
21
+
22
+ end
data/lib/db_leftovers.rb CHANGED
@@ -1,4 +1,9 @@
1
+ require 'db_leftovers/database_interface.rb'
2
+ require 'db_leftovers/index.rb'
3
+ require 'db_leftovers/foreign_key.rb'
4
+ require 'db_leftovers/table_dsl.rb'
1
5
  require 'db_leftovers/dsl.rb'
6
+ require 'db_leftovers/definition.rb'
2
7
 
3
8
  module DBLeftovers
4
9
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: db_leftovers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-01-17 00:00:00.000000000Z
12
+ date: 2012-01-20 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
16
- requirement: &86541750 !ruby/object:Gem::Requirement
16
+ requirement: &80697560 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 3.0.0
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *86541750
24
+ version_requirements: *80697560
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &86541450 !ruby/object:Gem::Requirement
27
+ requirement: &80697230 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 2.3.0
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *86541450
35
+ version_requirements: *80697230
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: bundler
38
- requirement: &86541140 !ruby/object:Gem::Requirement
38
+ requirement: &80696850 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: 1.0.0
44
44
  type: :development
45
45
  prerelease: false
46
- version_requirements: *86541140
46
+ version_requirements: *80696850
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: jeweler
49
- requirement: &86540780 !ruby/object:Gem::Requirement
49
+ requirement: &80691820 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: 1.6.4
55
55
  type: :development
56
56
  prerelease: false
57
- version_requirements: *86540780
57
+ version_requirements: *80691820
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: rcov
60
- requirement: &86540450 !ruby/object:Gem::Requirement
60
+ requirement: &80691390 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,7 +65,7 @@ dependencies:
65
65
  version: '0'
66
66
  type: :development
67
67
  prerelease: false
68
- version_requirements: *86540450
68
+ version_requirements: *80691390
69
69
  description: ! " Define indexes and foreign keys for your Rails app\n in
70
70
  one place using an easy-to-read DSL,\n then run a rake task to bring your
71
71
  database up-to-date.\n"
@@ -74,21 +74,30 @@ executables: []
74
74
  extensions: []
75
75
  extra_rdoc_files:
76
76
  - LICENSE.txt
77
- - README.rdoc
77
+ - README.html
78
+ - README.md
79
+ - TODO
78
80
  files:
79
81
  - .document
80
82
  - Gemfile
81
83
  - Gemfile.lock
82
84
  - LICENSE.txt
83
- - README.rdoc
85
+ - README.md
84
86
  - Rakefile
85
87
  - VERSION
86
88
  - db_leftovers.gemspec
87
89
  - lib/db_leftovers.rb
90
+ - lib/db_leftovers/database_interface.rb
91
+ - lib/db_leftovers/definition.rb
88
92
  - lib/db_leftovers/dsl.rb
93
+ - lib/db_leftovers/foreign_key.rb
94
+ - lib/db_leftovers/index.rb
95
+ - lib/db_leftovers/table_dsl.rb
89
96
  - lib/tasks/leftovers.rake
90
97
  - spec/db_leftovers_spec.rb
91
98
  - spec/spec_helper.rb
99
+ - README.html
100
+ - TODO
92
101
  homepage: http://github.com/pjungwir/db_leftovers
93
102
  licenses:
94
103
  - MIT
@@ -104,7 +113,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
104
113
  version: '0'
105
114
  segments:
106
115
  - 0
107
- hash: 347591153
116
+ hash: -934339327
108
117
  required_rubygems_version: !ruby/object:Gem::Requirement
109
118
  none: false
110
119
  requirements:
data/README.rdoc DELETED
@@ -1,19 +0,0 @@
1
- = db_leftovers
2
-
3
- Description goes here.
4
-
5
- == Contributing to db_leftovers
6
-
7
- * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
8
- * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
9
- * Fork the project
10
- * Start a feature/bugfix branch
11
- * Commit and push until you are happy with your contribution
12
- * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
13
- * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
14
-
15
- == Copyright
16
-
17
- Copyright (c) 2012 Paul A. Jungwirth. See LICENSE.txt for
18
- further details.
19
-