db_schema 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +4 -0
  6. data/Guardfile +17 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +522 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +10 -0
  11. data/bin/setup +8 -0
  12. data/db_schema.gemspec +35 -0
  13. data/lib/db_schema.rb +125 -0
  14. data/lib/db_schema/awesome_print.rb +246 -0
  15. data/lib/db_schema/changes.rb +396 -0
  16. data/lib/db_schema/configuration.rb +29 -0
  17. data/lib/db_schema/definitions.rb +122 -0
  18. data/lib/db_schema/definitions/field.rb +38 -0
  19. data/lib/db_schema/definitions/field/array.rb +19 -0
  20. data/lib/db_schema/definitions/field/base.rb +90 -0
  21. data/lib/db_schema/definitions/field/binary.rb +9 -0
  22. data/lib/db_schema/definitions/field/bit_string.rb +15 -0
  23. data/lib/db_schema/definitions/field/boolean.rb +9 -0
  24. data/lib/db_schema/definitions/field/character.rb +19 -0
  25. data/lib/db_schema/definitions/field/custom.rb +22 -0
  26. data/lib/db_schema/definitions/field/datetime.rb +30 -0
  27. data/lib/db_schema/definitions/field/geometric.rb +33 -0
  28. data/lib/db_schema/definitions/field/json.rb +13 -0
  29. data/lib/db_schema/definitions/field/monetary.rb +9 -0
  30. data/lib/db_schema/definitions/field/network.rb +17 -0
  31. data/lib/db_schema/definitions/field/numeric.rb +30 -0
  32. data/lib/db_schema/definitions/field/range.rb +29 -0
  33. data/lib/db_schema/definitions/field/text_search.rb +13 -0
  34. data/lib/db_schema/definitions/field/uuid.rb +9 -0
  35. data/lib/db_schema/dsl.rb +145 -0
  36. data/lib/db_schema/reader.rb +270 -0
  37. data/lib/db_schema/runner.rb +220 -0
  38. data/lib/db_schema/utils.rb +50 -0
  39. data/lib/db_schema/validator.rb +89 -0
  40. data/lib/db_schema/version.rb +3 -0
  41. metadata +239 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8dbf606aae084d2032ffbfb12940cfee0d0b9ad3
4
+ data.tar.gz: e354a7f339af08dadfba3b2a9bd505be2603778f
5
+ SHA512:
6
+ metadata.gz: 6777fcffd1c201b885ae98ff4b3c44bd64b0d3fcc7585a06ae5a9a966b874a7a96070c4fb428f3762ebf5ea68e4d8ecd688a496d5076328a539e4c348ded62b8
7
+ data.tar.gz: 54a567aeb035b438447b7a70aa0837a6d84974f400f606820b53b4046e192189ab54999c61a439e8a4e7739114936f6f26af4d2ea26ed00002c2290ddcb58e1f
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in db_schema.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,17 @@
1
+ guard :rspec, cmd: 'bundle exec rspec', all_on_start: true do
2
+ require 'guard/rspec/dsl'
3
+ dsl = Guard::RSpec::Dsl.new(self)
4
+
5
+ # RSpec files
6
+ rspec = dsl.rspec
7
+ watch(rspec.spec_helper) { rspec.spec_dir }
8
+ watch(rspec.spec_support) { rspec.spec_dir }
9
+ watch(rspec.spec_files)
10
+
11
+ # Ruby files
12
+ ruby = dsl.ruby
13
+ dsl.watch_spec_files_for(ruby.lib_files)
14
+ watch(%r{lib/db_schema/definitions\.rb}) { rspec.spec_dir }
15
+ watch(%r{lib/db_schema/definitions/.*\.rb}) { rspec.spec_dir }
16
+ watch('lib/db_schema/utils.rb') { rspec.spec_dir }
17
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Vsevolod Romashov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,522 @@
1
+ # DbSchema
2
+
3
+ DbSchema is an opinionated database schema management tool that lets you maintain your DB schema with a single ruby file.
4
+
5
+ It works like this:
6
+
7
+ * you create a `schema.rb` file where you describe the schema you want in a special DSL
8
+ * you make your application load this file as early as possible during the application bootup in development and test environments
9
+ * you create a rake task that loads your `schema.rb` and tell your favorite deployment tool to run it on each deploy
10
+ * each time you need to change the schema you just change the `schema.rb` file and commit it to your VCS
11
+
12
+ As a result you always have an up-to-date database schema. No need to run and rollback migrations, no need to even think about the extra step - DbSchema compares the schema you want with the schema your database has and applies all necessary changes to the latter. This operation is [idempotent](https://en.wikipedia.org/wiki/Idempotence) - if DbSchema sees that the database already has the requested schema it does nothing.
13
+
14
+ *Currently DbSchema only supports PostgreSQL.*
15
+
16
+ ## Reasons to use
17
+
18
+ With DbSchema you almost never need to write migrations by hand and manage a collection of migration files.
19
+ This gives you a list of important benefits:
20
+
21
+ * no more `YouHaveABunchOfPendingMigrations` errors - all needed operations are computed from the differences between the schema definition and the actual database schema
22
+ * no need to write separate :up and :down migrations - this is all handled automatically
23
+ * there is no `structure.sql` with a database dump that constantly changes without reason
24
+
25
+ But the main reason of DbSchema existence is the pain of switching
26
+ between long-running VCS branches with different migrations
27
+ without resetting the database. Have you ever switched
28
+ to a different branch only to see something like this?
29
+
30
+ ![](https://cloud.githubusercontent.com/assets/351591/17085038/7da81118-51d6-11e6-91d9-99885235d037.png)
31
+
32
+ Yeah, you must remember the oldest `NO FILE` migration,
33
+ switch back to the previous branch,
34
+ roll back every migration up to that `NO FILE`,
35
+ then switch the branch again and migrate these `down` migrations.
36
+ Every migration or rollback loads the whole app, resulting in 10+ seconds wasted.
37
+ And at the end of it all you are trying to recall why did you ever
38
+ want to switch to that branch.
39
+
40
+ DbSchema does not rely on migration files and/or `schema_migrations` table in the database
41
+ so it seamlessly changes the schema to the one defined in the branch you switched to.
42
+ There is no step 2.
43
+
44
+ Of course if you are switching from a branch that defines table A to a branch
45
+ that doesn't define table A then you lose that table with all the data in it.
46
+ But you would lose it even with manual migrations.
47
+
48
+ ## Installation
49
+
50
+ Add this line to your application's Gemfile:
51
+
52
+ ``` ruby
53
+ gem 'db_schema'
54
+ ```
55
+
56
+ And then execute:
57
+
58
+ ``` sh
59
+ $ bundle
60
+ ```
61
+
62
+ Or install it yourself as:
63
+
64
+ ``` sh
65
+ $ gem install db_schema
66
+ ```
67
+
68
+ ## Usage
69
+
70
+ You define your schema with a special DSL; you can put it in `db/schema.rb` file or anywhere you want. Be sure to keep this file under version control.
71
+
72
+ DbSchema DSL looks like this:
73
+
74
+ ``` ruby
75
+ DbSchema.describe do |db|
76
+ db.table :users do |t|
77
+ t.primary_key :id
78
+ t.varchar :email, null: false
79
+ t.varchar :password_digest, length: 40
80
+ t.timestamptz :created_at
81
+ t.timestamptz :updated_at
82
+
83
+ t.index :email, unique: true
84
+ end
85
+ end
86
+ ```
87
+
88
+ Before DbSchema connects to the database you need to configure it:
89
+
90
+ ``` ruby
91
+ DbSchema.configure(adapter: 'postgresql', database: 'my_database', user: 'bob', password: 'secret')
92
+ # or in Rails
93
+ DbSchema.configure_from_yaml(Rails.root.join('config', 'database.yml'), Rails.env)
94
+ ```
95
+
96
+ Then you can load your schema definition (it is executable - it instantly applies itself to your database):
97
+
98
+ ``` ruby
99
+ load 'path/to/schema.rb'
100
+ ```
101
+
102
+ In order to get an always-up-to-date database schema in development and test environments you need to load the schema definition when your application is starting up. For instance, in Rails an initializer would be a good place to do that.
103
+
104
+ On the other hand, in production environment this can cause race condition problems as your schema can be applied concurrently by different worker processes (this also applies to staging and any other environments where the application is being run by multi-worker servers); therefore it is wiser to disable schema auto loading in such environments and run it from a rake task on each deploy.
105
+
106
+ Here's an initializer example for a Rails app:
107
+
108
+ ``` ruby
109
+ # config/initializers/db_schema.rb
110
+ DbSchema.configure_from_yaml(Rails.root.join('config', 'database.yml'), Rails.env)
111
+
112
+ if Rails.env.development? || Rails.env.test?
113
+ load Rails.root.join('db', 'schema.rb')
114
+ end
115
+ ```
116
+
117
+ And the rake task:
118
+
119
+ ``` ruby
120
+ # lib/tasks/db_schema.rake
121
+ namespace :db do
122
+ namespace :schema do
123
+ desc 'Apply database schema'
124
+ task apply: :environment do
125
+ load Rails.root.join('db', 'schema.rb')
126
+ end
127
+ end
128
+ end
129
+ ```
130
+
131
+ Then you just call `rake db:schema:apply` from your deploy script before restarting the app.
132
+
133
+ ### DSL
134
+
135
+ Database schema is defined with a block passed to `DbSchema.describe` method.
136
+ This block receives a `db` object on which you can call `#table` to define a table
137
+ and `#enum` to define a custom enum type. Everything that belongs to a specific table
138
+ is described in a block passed to `#table`.
139
+
140
+ ``` ruby
141
+ DbSchema.describe do |db|
142
+ db.table :users do |t|
143
+ t.primary_key :id
144
+ t.varchar :email, null: false
145
+ t.varchar :password, null: false
146
+ t.varchar :name, null: false
147
+ t.integer :age
148
+ t.user_status :status, null: false, default: 'registered'
149
+
150
+ t.index :email, unique: true
151
+ end
152
+
153
+ db.enum :user_status, [:registered, :confirmed_email, :subscriber]
154
+
155
+ db.table :posts do |t|
156
+ t.primary_key :id
157
+ t.integer :user_id, null: false
158
+ t.varchar :title, null: false, length: 50
159
+ t.text :content
160
+ t.array :tags, of: :varchar
161
+
162
+ t.index :user_id
163
+ t.foreign_key :user_id, references: :users
164
+ end
165
+ end
166
+ ```
167
+
168
+ #### Tables
169
+
170
+ Tables are described with the `#table` method; you pass it the name of the table and describe the table structure in the block:
171
+
172
+ ``` ruby
173
+ db.table :users do |t|
174
+ t.varchar :email
175
+ t.varchar :password
176
+ end
177
+ ```
178
+
179
+ ##### Fields
180
+
181
+ You can define a field of any type by calling the corresponding method inside the table block passing it the field name and it's attributes. Most of the attributes are optional.
182
+
183
+ Here's an example table with various kinds of data:
184
+
185
+ ``` ruby
186
+ db.table :people do |t|
187
+ t.varchar :first_name, length: 50, null: false
188
+ t.varchar :last_name, length: 60, null: false
189
+ t.integer :age
190
+ t.numeric :salary, precision: 10, scale: 2
191
+ t.text :about
192
+ t.date :birthday
193
+ t.boolean :developer
194
+ t.inet :ip_address
195
+ t.jsonb :preferences, default: '{}'
196
+ t.array :interests, of: :varchar
197
+ t.numrange :salary_expectations
198
+
199
+ t.timestamptz :created_at
200
+ t.timestamptz :updated_at
201
+ end
202
+ ```
203
+
204
+ Passing `null: false` to the field definition makes it `NOT NULL`; passing some value under the `:default` key makes it the default value. A symbol passed as a default is interpreted as a function call so `t.timestamp :created_at, default: :now` defines a field with a default value of `NOW()`; strings, numbers, timestamps etc are evaluated "as is".
205
+
206
+ Other attributes are type specific, like `:length` for varchars; the following table lists them all (values in parentheses are default attribute values).
207
+
208
+ | Type | Attributes |
209
+ | ------------- | ---------------- |
210
+ | `smallint` | |
211
+ | `integer` | |
212
+ | `bigint` | |
213
+ | `numeric` | precision, scale |
214
+ | `real` | |
215
+ | `float` | |
216
+ | `money` | |
217
+ | `char` | length(1) |
218
+ | `varchar` | length |
219
+ | `text` | |
220
+ | `bytea` | |
221
+ | `timestamp` | |
222
+ | `timestamptz` | |
223
+ | `date` | |
224
+ | `time` | |
225
+ | `timetz` | |
226
+ | `interval` | fields |
227
+ | `boolean` | |
228
+ | `point` | |
229
+ | `line` | |
230
+ | `lseg` | |
231
+ | `box` | |
232
+ | `path` | |
233
+ | `polygon` | |
234
+ | `circle` | |
235
+ | `cidr` | |
236
+ | `inet` | |
237
+ | `macaddr` | |
238
+ | `bit` | length(1) |
239
+ | `varbit` | length |
240
+ | `tsvector` | |
241
+ | `tsquery` | |
242
+ | `uuid` | |
243
+ | `json` | |
244
+ | `jsonb` | |
245
+ | `array` | of |
246
+ | `int4range` | |
247
+ | `int8range` | |
248
+ | `numrange` | |
249
+ | `tsrange` | |
250
+ | `tstzrange` | |
251
+ | `daterange` | |
252
+
253
+ The `of` attribute of the array type is the only required attribute (you need to specify the array element type here); other attributes either have default values or can be omitted at all.
254
+
255
+ You can also use your custom types in the same way: `t.user_status :status` creates a field called `status` with `user_status` type. Custom types are explained in a later section of this document.
256
+
257
+ Primary key is a special case; currently when you create a primary key with DbSchema you get a NOT NULL autoincrementing (by a sequence) integer field with a primary key constraint. There is no way to change the primary key field type or make a complex primary key at the moment; this is planned for future versions of DbSchema.
258
+
259
+ Primary keys are created with the `#primary_key` method:
260
+
261
+ ``` ruby
262
+ db.table :posts do |t|
263
+ t.primary_key :id
264
+ t.varchar :title
265
+ end
266
+ ```
267
+
268
+ **Important: you can't rename a table or a column just by changing it's name in the schema definition - this will result in a column with the old name being deleted and a column with the new name being added; all data in that table or column will be lost.**
269
+
270
+ ##### Indexes
271
+
272
+ Indexes are created using the `#index` method: you pass it the field name you want to index:
273
+
274
+ ``` ruby
275
+ db.table :users do |t|
276
+ t.varchar :email
277
+ t.index :email
278
+ end
279
+ ```
280
+
281
+ Unique indexes are created with `unique: true`:
282
+
283
+ ``` ruby
284
+ t.index :email, unique: true
285
+ ```
286
+
287
+ Passing several field names makes a multiple index:
288
+
289
+ ``` ruby
290
+ db.table :users do |t|
291
+ t.varchar :first_name
292
+ t.varchar :last_name
293
+
294
+ t.index :first_name, :last_name
295
+ end
296
+ ```
297
+
298
+ If you want to specify a custom name for your index, you can pass it in the `:name` option:
299
+
300
+ ``` ruby
301
+ t.index :first_name, :last_name, name: :username_index
302
+ ```
303
+
304
+ Otherwise the index name will be generated as `"#{table_name}_#{field_names.join('_')}_index"` so the index above will be called `users_first_name_last_name_index`.
305
+
306
+ You can specify the order of each field in your index - it's either `ASC` (`:asc`, the default), `DESC` (`:desc`), `ASC NULLS FIRST` (`:asc_nulls_first`), or `DESC NULLS LAST` (`:desc_nulls_last`). It looks like this:
307
+
308
+ ``` ruby
309
+ db.table :some_table do |t|
310
+ t.integer :col1
311
+ t.integer :col2
312
+ t.integer :col3
313
+ t.integer :col4
314
+
315
+ t.index col1: :asc, col2: :desc, col3: :asc_nulls_first, col4: :desc_nulls_last
316
+ end
317
+ ```
318
+
319
+ By default B-tree indexes are created; if you need an index of a different type you can pass it in the `:using` option:
320
+
321
+ ``` ruby
322
+ db.table :users do |t|
323
+ t.array :interests, of: :varchar
324
+ t.index :interests, using: :gin
325
+ end
326
+ ```
327
+
328
+ You can also create a partial index if you pass some condition as SQL string in the `:where` option:
329
+
330
+ ``` ruby
331
+ db.table :users do |t|
332
+ t.varchar :email
333
+ t.index :email, unique: true, where: 'email IS NOT NULL'
334
+ end
335
+ ```
336
+
337
+ Be warned though that you have to specify the condition exactly as PostgreSQL outputs it in `psql` with `\d table_name` command; otherwise your index will be recreated on each DbSchema run. This will be fixed in a later DbSchema version.
338
+
339
+ ##### Foreign keys
340
+
341
+ The `#foreign_key` method defines a foreign key. In it's minimal form it takes a referencing field name and referenced table name:
342
+
343
+ ``` ruby
344
+ db.table :users do |t|
345
+ t.primary_key :id
346
+ t.varchar :name
347
+ end
348
+
349
+ db.table :posts do |t|
350
+ t.integer :user_id
351
+ t.varchar :title
352
+
353
+ t.foreign_key :user_id, references: :users
354
+ end
355
+ ```
356
+
357
+ The syntax above assumes that this foreign key references the primary key. If you need to reference another field you can pass a 2-element array in `:references` option, the first element being table name and the second being field name:
358
+
359
+ ``` ruby
360
+ db.table :users do |t|
361
+ t.varchar :name
362
+ t.index :name, unique: true # you can only reference either primary keys or unique columns
363
+ end
364
+
365
+ db.table :posts do |t|
366
+ t.varchar :username
367
+ t.foreign_key :username, references: [:users, :name]
368
+ end
369
+ ```
370
+
371
+ As with indexes, you can pass your custom name in the `:name` option; default foreign key name looks like `"#{table_name}_#{fkey_fields.first}_fkey"`.
372
+
373
+ You can also define a composite foreign key consisting of (and referencing) multiple columns; just list them all:
374
+
375
+ ``` ruby
376
+ db.table :table_a do |t|
377
+ t.integer :col1
378
+ t.integer :col2
379
+ t.index :col1, :col2, unique: true
380
+ end
381
+
382
+ db.table :table_b do |t|
383
+ t.integer :a_col1
384
+ t.integer :a_col2
385
+ t.foreign_key :a_col1, :a_col2, references: [:table_a, :col1, :col2]
386
+ end
387
+ ```
388
+
389
+ There are 3 more options to the `#foreign_key` method: `:on_update`, `:on_delete` and `:deferrable`. First two define an action that will be taken when a referenced column is changed or the whole referenced row is deleted, respectively; you can set these to one of `:no_action` (the default), `:restrict`, `:cascade`, `:set_null` or `:set_default`. See [PostgreSQL documentation](https://www.postgresql.org/docs/current/static/ddl-constraints.html#DDL-CONSTRAINTS-FK) for more information.
390
+
391
+ Passing `deferrable: true` defines a foreign key that is checked at the end of transaction.
392
+
393
+ ##### Check constraints
394
+
395
+ A check constraint is like a validation on the database side: it checks if the inserted/updated row has valid values.
396
+
397
+ To define a check constraint you can use the `#check` method passing it the constraint name (no auto-generated names here, sorry) and the condition that must be satisfied, in a form of SQL string.
398
+
399
+ ``` ruby
400
+ db.table :users do |t|
401
+ t.primary_key :id
402
+ t.varchar :name
403
+ t.integer :age, null: false
404
+
405
+ t.check :valid_age, 'age >= 18'
406
+ end
407
+ ```
408
+
409
+ As with partial index conditions, for now you have to specify the SQL exactly as `psql` outputs it (otherwise the constraint will be recreated on each run).
410
+
411
+ #### Enum types
412
+
413
+ PostgreSQL allows developers to create custom enum types; value of enum type is one of a fixed set of values stored in the type definition.
414
+
415
+ Enum types are declared with the `#enum` method (note that you must call it from the top level of your schema and not from within some table definition):
416
+
417
+ ``` ruby
418
+ db.enum :user_status, [:registered, :confirmed_email]
419
+ ```
420
+
421
+ Then you can create fields of that type exactly as you would create a field of any built-in type - just call the method with the same name as the type you defined:
422
+
423
+ ``` ruby
424
+ db.table :users do |t|
425
+ t.user_status :status, default: 'registered'
426
+ end
427
+ ```
428
+
429
+ After the enum type is created, you can add more values to it. They don't have to appear in the end of the values list - you can add new values to the middle or even to the beginning of the list:
430
+
431
+ ``` ruby
432
+ db.enum :user_status, [:guest, :registered, :sent_confirmation_email, :confirmed_email, :subscriber]
433
+ ```
434
+
435
+ Reordering and deleting values from enum types is not supported.
436
+
437
+ ### Configuration
438
+
439
+ DbSchema must be configured prior to applying the schema. There are 2 methods you can use for that: `configure` and `configure_from_yaml`.
440
+
441
+ #### DbSchema.configure
442
+
443
+ `configure` is a generic method that receives a hash with all configuration options:
444
+
445
+ ``` ruby
446
+ DbSchema.configure(
447
+ adapter: 'postgresql',
448
+ host: ENV['db_host'],
449
+ port: ENV['db_port'],
450
+ database: ENV['db_name'],
451
+ user: ENV['db_user'],
452
+ password: ENV['db_password']
453
+ )
454
+ ```
455
+
456
+ #### DbSchema.configure_from_yaml
457
+
458
+ `configure_from_yaml` is designed to use with Rails so you don't have to duplicate database connection settings from your `database.yml` in DbSchema configuration. Pass it the full path to your `database.yml` file and your current application environment (`development`, `production` etc), and it will read the db connection settings from that file.
459
+
460
+ ``` ruby
461
+ DbSchema.configure_from_yaml(Rails.root.join('config', 'database.yml'), Rails.env)
462
+ ```
463
+
464
+ If you need to specify other options you can simply pass them as keyword arguments after the environment:
465
+
466
+ ``` ruby
467
+ DbSchema.configure_from_yaml(
468
+ Rails.root.join('config', 'database.yml'),
469
+ Rails.env,
470
+ dry_run: true
471
+ )
472
+ ```
473
+
474
+ #### Configuration options
475
+
476
+ All configuration options are described in the following table:
477
+
478
+ | Option | Default value | Description |
479
+ | ----------- | ------------- | ------------------------------------------------ |
480
+ | adapter | `'postgres'` | Database adapter |
481
+ | host | `'localhost'` | Database host |
482
+ | port | `5432` | Database port |
483
+ | database | (no default) | Database name |
484
+ | user | `nil` | Database user |
485
+ | password | `''` | Database password |
486
+ | log_changes | `true` | When true, schema changes are logged |
487
+ | post_check | `true` | When true, database schema is checked afterwards |
488
+ | dry_run | `false` | When true, no operations are actually made |
489
+
490
+ By default DbSchema logs the changes it applies to your database; you can disable that by setting `log_changes` to false.
491
+
492
+ DbSchema provides an opt-out post-run schema check; it ensures that there are no remaining differences between your `schema.rb` and the actual database schema. If DbSchema still sees any differences it will keep applying them on each run - usually this is harmless (because it does not really change your schema) but in the case of a partial index with a complex condition it may rebuild the index which is an expensive operation on a large table. You can set `post_check` to false if you are 100% sure that your persistent changes are not a problem for you but I strongly recommend that you turn it on from time to time just to make sure nothing dangerous appears in these persistent changes.
493
+
494
+ The `post_check` option is likely to become off by default when DbSchema becomes more stable and battle-tested, and when the partial index problem will be solved.
495
+
496
+ There is also a dry run mode which does not apply the changes to your database - it just logs the necessary changes (if you leave `log_changes` set to `true`). Post check is also skipped in that case.
497
+
498
+ Dry run may be useful while you are building your schema definition for an existing app; adjust your `schema.rb` and apply it in dry run mode until it fits your database and next dry run doesn't report any changes. Don't forget to turn `dry_run` off afterwards!
499
+
500
+ ## Known problems and limitations
501
+
502
+ * primary keys are hardcoded to a single NOT NULL integer field with a postgres sequence attached
503
+ * "partial index problem": some conditions of partial indexes and check constraints can cause
504
+ a false positive result of checking for differences between `schema.rb` and actual database schema,
505
+ resulting in unwanted operations on each run (the worst of them being the recreation of an index
506
+ on a large table)
507
+ * array element type attributes are not supported
508
+ * precision in time & datetime types isn't supported
509
+ * no support for databases other than PostgreSQL
510
+ * no support for renaming tables & columns
511
+
512
+ ## Development
513
+
514
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem onto your local machine, run `bundle exec rake install`.
515
+
516
+ ## Contributing
517
+
518
+ Bug reports and pull requests are welcome on GitHub at [7even/db_schema](https://github.com/7even/db_schema).
519
+
520
+ ## License
521
+
522
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).