active_record_doctor 1.4.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b6e1c0cae1aa647256ff7eafb6a839e1b21efa82
4
- data.tar.gz: 6ca222532fbd13abd9aba412c4dfa3ece725ec94
3
+ metadata.gz: dd6b18b16b7a356e1760befd1d59d7f2b7a77ed3
4
+ data.tar.gz: ea1c526b3080d7c8ee5ae4e4eb9a833e3b797cc4
5
5
  SHA512:
6
- metadata.gz: 06e9c8db1abc13bdc3cadbf7c72b2d6f25d7fa8b87be116227dcb7a59aaf9475cb35f1cca9d5e679ffed123741d77424bf0a4a80e7a72c53c00a004a830f11c6
7
- data.tar.gz: 0501fb31dd03bc30a9d51344f632fcec82e1ee4ceaa7e2e288360676b39c98978e7129a43c5e368098e1c7d16ea332dfcf863db5b2910bb37cb778326ff3f2b5
6
+ metadata.gz: 91035e0b5fa47e0d4e5b84a42f53573efc1c333555978a5130ecf05695b12aa17ffcf542b7e0d4c253332ad52b2688f5645e138bd755e3649ea88b0574e41c63
7
+ data.tar.gz: 137b3c1a9fd054e0b1af8fd1aad40f5b79ce068b0b0db458ca63d0f64cdf4c23342131a775a5f5148aec34e8c8ff2c32fd1e2a31b1bd86a69a3271c07e34b104
data/README.md CHANGED
@@ -5,6 +5,7 @@ can:
5
5
 
6
6
  * index unindexed foreign keys
7
7
  * detect extraneous indexes
8
+ * detect unindexed `deleted_at` columns
8
9
  * detect missing foreign key constraints
9
10
  * detect models referencing undefined tables
10
11
 
@@ -101,6 +102,24 @@ example, if there's a unique index on `users.login` and a non-unique index on
101
102
  `users.login, users.domain` then the tool will _not_ suggest dropping
102
103
  `users.login` as it could violate the uniqueness assumption.
103
104
 
105
+ ### Detecting Unindexed `deleted_at` Columns
106
+
107
+ If you soft-delete some models (e.g. with `paranoia`) then you need to modify
108
+ your indexes to include only non-deleted rows. Otherwise they will include
109
+ logically non-existent rows. This will make them larger and slower to use. Most
110
+ of the time they should only cover columns satisfying `deleted_at IS NULL`.
111
+
112
+ `active_record_doctor` can automatically detect indexes on tables with a
113
+ `deleted_at` column. Just run:
114
+
115
+ ```
116
+ rake active_record_doctor:unindexed_soft_delete
117
+ ```
118
+
119
+ This will print a list of indexes that don't have the `deleted_at IS NULL`
120
+ clause. Currently, `active_record_doctor` cannot automatically generate
121
+ appropriate migrations. You need to do that manually.
122
+
104
123
  ### Detecting Missing Foreign Key Constraints
105
124
 
106
125
  If `users.profile_id` references a row in `profiles` then this can be expressed
@@ -44,6 +44,15 @@ module ActiveRecordDoctor
44
44
  @io.puts(" #{model.name} (the table #{model.table_name} is undefined)")
45
45
  end
46
46
  end
47
+
48
+ def print_unindexed_deleted_at(indexes)
49
+ return if indexes.empty?
50
+
51
+ @io.puts('The following indexes should include `deleted_at IS NULL`:')
52
+ indexes.each do |index|
53
+ @io.puts(" #{index}")
54
+ end
55
+ end
47
56
  end
48
57
  end
49
58
  end
@@ -0,0 +1,40 @@
1
+ require "active_record_doctor/compatibility"
2
+ require "active_record_doctor/printers/io_printer"
3
+
4
+ module ActiveRecordDoctor
5
+ module Tasks
6
+ class UnindexedDeletedAt
7
+ include Compatibility
8
+
9
+ def self.run
10
+ new.run
11
+ end
12
+
13
+ def initialize(printer: ActiveRecordDoctor::Printers::IOPrinter.new)
14
+ @printer = printer
15
+ end
16
+
17
+ def run
18
+ @printer.print_unindexed_deleted_at(unindexed_deleted_at)
19
+ end
20
+
21
+ private
22
+
23
+ def unindexed_deleted_at
24
+ connection.tables.select do |table|
25
+ connection.columns(table).map(&:name).include?('deleted_at')
26
+ end.flat_map do |table|
27
+ connection.indexes(table).reject do |index|
28
+ index.where =~ /\bdeleted_at\s+IS\s+NULL\b/i
29
+ end.map do |index|
30
+ index.name
31
+ end
32
+ end
33
+ end
34
+
35
+ def connection
36
+ @connection ||= ActiveRecord::Base.connection
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,3 +1,3 @@
1
1
  module ActiveRecordDoctor
2
- VERSION = "1.4.1"
2
+ VERSION = "1.5.0"
3
3
  end
@@ -2,6 +2,7 @@ require "active_record_doctor/tasks/unindexed_foreign_keys"
2
2
  require "active_record_doctor/tasks/extraneous_indexes"
3
3
  require "active_record_doctor/tasks/missing_foreign_keys"
4
4
  require "active_record_doctor/tasks/undefined_table_references"
5
+ require "active_record_doctor/tasks/unindexed_deleted_at"
5
6
 
6
7
  namespace :active_record_doctor do
7
8
  task :unindexed_foreign_keys => :environment do
@@ -19,4 +20,8 @@ namespace :active_record_doctor do
19
20
  task :undefined_table_references => :environment do
20
21
  exit(ActiveRecordDoctor::Tasks::UndefinedTableReferences.run)
21
22
  end
23
+
24
+ task :unindexed_soft_delete => :environment do
25
+ ActiveRecordDoctor::Tasks::UnindexedDeletedAt.run
26
+ end
22
27
  end
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+
3
+ require 'active_record_doctor/tasks/unindexed_deleted_at'
4
+
5
+ class ActiveRecordDoctor::Tasks::UnindexedDeletedAtTest < ActiveSupport::TestCase
6
+ def test_unindexed_deleted_at_are_reported
7
+ result = run_task
8
+
9
+ assert_equal(['index_profiles_on_first_name_and_last_name'], result)
10
+ end
11
+
12
+ private
13
+
14
+ def run_task
15
+ printer = SpyPrinter.new
16
+ ActiveRecordDoctor::Tasks::UnindexedDeletedAt.new(printer: printer).run
17
+ printer.unindexed_deleted_at
18
+ end
19
+ end
@@ -4,10 +4,12 @@ class CreateEmployers < BaseMigration
4
4
  def change
5
5
  create_table :employers do |t|
6
6
  t.string :name
7
+ t.datetime :deleted_at
7
8
 
8
9
  t.timestamps null: false
9
10
  end
10
11
 
11
- add_index :employers, :id
12
+ add_index :employers, :id, where: 'deleted_at IS NULL'
13
+ add_index :employers, :name, where: 'deleted_at IS NULL'
12
14
  end
13
15
  end
@@ -5,8 +5,11 @@ class CreateProfiles < BaseMigration
5
5
  create_table :profiles do |t|
6
6
  t.string :first_name
7
7
  t.string :last_name
8
+ t.datetime :deleted_at
8
9
 
9
10
  t.timestamps null: false
10
11
  end
12
+
13
+ add_index :profiles, [:first_name, :last_name]
11
14
  end
12
15
  end
@@ -27,19 +27,24 @@ ActiveRecord::Schema.define(version: 20160604081452) do
27
27
 
28
28
  create_table "employers", force: :cascade do |t|
29
29
  t.string "name"
30
+ t.datetime "deleted_at"
30
31
  t.datetime "created_at", null: false
31
32
  t.datetime "updated_at", null: false
32
33
  end
33
34
 
34
- add_index "employers", ["id"], name: "index_employers_on_id", using: :btree
35
+ add_index "employers", ["id"], name: "index_employers_on_id", where: "(deleted_at IS NULL)", using: :btree
36
+ add_index "employers", ["name"], name: "index_employers_on_name", where: "(deleted_at IS NULL)", using: :btree
35
37
 
36
38
  create_table "profiles", force: :cascade do |t|
37
39
  t.string "first_name"
38
40
  t.string "last_name"
41
+ t.datetime "deleted_at"
39
42
  t.datetime "created_at", null: false
40
43
  t.datetime "updated_at", null: false
41
44
  end
42
45
 
46
+ add_index "profiles", ["first_name", "last_name"], name: "index_profiles_on_first_name_and_last_name", using: :btree
47
+
43
48
  create_table "users", force: :cascade do |t|
44
49
  t.string "email"
45
50
  t.string "first_name"
@@ -134,3 +134,399 @@ FOREIGN KEY ("employer_id")
134
134
   (7.3ms) INSERT INTO "schema_migrations" (version) VALUES ('20160213101232')
135
135
   (1.9ms) INSERT INTO "schema_migrations" (version) VALUES ('20160213101221')
136
136
  ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
137
+ SQL (0.2ms) CREATE EXTENSION IF NOT EXISTS "plpgsql"
138
+  (67.5ms) CREATE TABLE "comments" ("id" serial primary key, "commentable_id" integer, "commentable_type" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
139
+  (16.0ms) CREATE INDEX "index_comments_on_commentable_type_and_commentable_id" ON "comments" USING btree ("commentable_type", "commentable_id")
140
+  (41.3ms) CREATE TABLE "employers" ("id" serial primary key, "name" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
141
+  (18.7ms) CREATE INDEX "index_employers_on_id" ON "employers" USING btree ("id")
142
+  (55.8ms) CREATE TABLE "profiles" ("id" serial primary key, "first_name" character varying, "last_name" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
143
+  (38.8ms) CREATE TABLE "users" ("id" serial primary key, "email" character varying, "first_name" character varying, "last_name" character varying, "profile_id" integer, "employer_id" integer, "country_code" character varying NOT NULL, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
144
+  (18.2ms) CREATE INDEX "index_users_on_email" ON "users" USING btree ("email")
145
+  (18.4ms) CREATE UNIQUE INDEX "unique_index_on_users_email" ON "users" USING btree ("email")
146
+  (18.3ms) CREATE INDEX "index_users_on_employer_id_and_country_code" ON "users" USING btree ("employer_id", "country_code")
147
+  (21.4ms) CREATE INDEX "index_users_on_last_name_and_first_name_and_email" ON "users" USING btree ("last_name", "first_name", "email")
148
+  (12.6ms) CREATE INDEX "index_users_on_last_name_and_first_name" ON "users" USING btree ("last_name", "first_name")
149
+  (18.4ms) CREATE UNIQUE INDEX "unique_index_on_users_last_name_and_first_name" ON "users" USING btree ("last_name", "first_name")
150
+  (21.3ms) CREATE INDEX "index_users_on_last_name" ON "users" USING btree ("last_name")
151
+  (9.1ms) ALTER TABLE "users" ADD CONSTRAINT "fk_rails_e0dbdd604c"
152
+ FOREIGN KEY ("employer_id")
153
+ REFERENCES "employers" ("id")
154
+ 
155
+  (27.5ms) CREATE TABLE "schema_migrations" ("version" character varying NOT NULL)
156
+  (33.9ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
157
+  (0.3ms) SELECT version FROM "schema_migrations"
158
+  (7.7ms) INSERT INTO "schema_migrations" (version) VALUES ('20160604081452')
159
+  (7.7ms) INSERT INTO "schema_migrations" (version) VALUES ('20160213101213')
160
+  (7.6ms) INSERT INTO "schema_migrations" (version) VALUES ('20160213101232')
161
+  (2.0ms) INSERT INTO "schema_migrations" (version) VALUES ('20160213101221')
162
+ SQL (0.1ms) CREATE EXTENSION IF NOT EXISTS "plpgsql"
163
+  (51.2ms) CREATE TABLE "comments" ("id" serial primary key, "commentable_id" integer, "commentable_type" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
164
+  (21.0ms) CREATE INDEX "index_comments_on_commentable_type_and_commentable_id" ON "comments" USING btree ("commentable_type", "commentable_id")
165
+  (29.1ms) CREATE TABLE "employers" ("id" serial primary key, "name" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
166
+  (18.5ms) CREATE INDEX "index_employers_on_id" ON "employers" USING btree ("id")
167
+  (35.1ms) CREATE TABLE "profiles" ("id" serial primary key, "first_name" character varying, "last_name" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
168
+  (29.1ms) CREATE TABLE "users" ("id" serial primary key, "email" character varying, "first_name" character varying, "last_name" character varying, "profile_id" integer, "employer_id" integer, "country_code" character varying NOT NULL, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
169
+  (20.7ms) CREATE INDEX "index_users_on_email" ON "users" USING btree ("email")
170
+  (23.1ms) CREATE UNIQUE INDEX "unique_index_on_users_email" ON "users" USING btree ("email")
171
+  (28.7ms) CREATE INDEX "index_users_on_employer_id_and_country_code" ON "users" USING btree ("employer_id", "country_code")
172
+  (24.1ms) CREATE INDEX "index_users_on_last_name_and_first_name_and_email" ON "users" USING btree ("last_name", "first_name", "email")
173
+  (23.8ms) CREATE INDEX "index_users_on_last_name_and_first_name" ON "users" USING btree ("last_name", "first_name")
174
+  (24.2ms) CREATE UNIQUE INDEX "unique_index_on_users_last_name_and_first_name" ON "users" USING btree ("last_name", "first_name")
175
+  (18.0ms) CREATE INDEX "index_users_on_last_name" ON "users" USING btree ("last_name")
176
+  (9.3ms) ALTER TABLE "users" ADD CONSTRAINT "fk_rails_e0dbdd604c"
177
+ FOREIGN KEY ("employer_id")
178
+ REFERENCES "employers" ("id")
179
+ 
180
+  (23.9ms) CREATE TABLE "schema_migrations" ("version" character varying NOT NULL)
181
+  (12.4ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
182
+  (0.3ms) SELECT version FROM "schema_migrations"
183
+  (7.6ms) INSERT INTO "schema_migrations" (version) VALUES ('20160604081452')
184
+  (2.1ms) INSERT INTO "schema_migrations" (version) VALUES ('20160213101213')
185
+  (2.1ms) INSERT INTO "schema_migrations" (version) VALUES ('20160213101232')
186
+  (7.7ms) INSERT INTO "schema_migrations" (version) VALUES ('20160213101221')
187
+ ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations".* FROM "schema_migrations"
188
+  (49.4ms) CREATE TABLE "schema_migrations" ("version" character varying NOT NULL) 
189
+  (22.0ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
190
+ ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
191
+ Migrating to CreateEmployers (20160213101213)
192
+  (0.1ms) BEGIN
193
+  (28.2ms) CREATE TABLE "employers" ("id" serial primary key, "name" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
194
+  (10.7ms) CREATE INDEX "index_employers_on_id" ON "employers" ("id")
195
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160213101213"]]
196
+  (15.0ms) COMMIT
197
+ Migrating to CreateUsers (20160213101221)
198
+  (0.2ms) BEGIN
199
+  (34.9ms) CREATE TABLE "users" ("id" serial primary key, "email" character varying, "first_name" character varying, "last_name" character varying, "profile_id" integer, "employer_id" integer, "country_code" character varying NOT NULL, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
200
+  (0.8ms) ALTER TABLE "users" ADD CONSTRAINT "fk_rails_e0dbdd604c"
201
+ FOREIGN KEY ("employer_id")
202
+ REFERENCES "employers" ("id")
203
+ 
204
+  (20.2ms) CREATE INDEX "index_users_on_last_name_and_first_name_and_email" ON "users" ("last_name", "first_name", "email")
205
+  (16.5ms) CREATE INDEX "index_users_on_last_name_and_first_name" ON "users" ("last_name", "first_name")
206
+  (16.2ms) CREATE UNIQUE INDEX "unique_index_on_users_last_name_and_first_name" ON "users" ("last_name", "first_name")
207
+  (19.7ms) CREATE INDEX "index_users_on_last_name" ON "users" ("last_name")
208
+  (16.6ms) CREATE INDEX "index_users_on_email" ON "users" ("email")
209
+  (22.2ms) CREATE UNIQUE INDEX "unique_index_on_users_email" ON "users" ("email")
210
+  (10.7ms) CREATE INDEX "index_users_on_employer_id_and_country_code" ON "users" ("employer_id", "country_code")
211
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160213101221"]]
212
+  (8.0ms) COMMIT
213
+ Migrating to CreateProfiles (20160213101232)
214
+  (0.2ms) BEGIN
215
+  (30.6ms) CREATE TABLE "profiles" ("id" serial primary key, "first_name" character varying, "last_name" character varying, "deleted_at" timestamp, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
216
+ SQL (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160213101232"]]
217
+  (8.4ms) COMMIT
218
+ Migrating to CreateComments (20160604081452)
219
+  (0.1ms) BEGIN
220
+  (44.5ms) CREATE TABLE "comments" ("id" serial primary key, "commentable_id" integer, "commentable_type" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
221
+  (13.7ms) CREATE INDEX "index_comments_on_commentable_type_and_commentable_id" ON "comments" ("commentable_type", "commentable_id")
222
+ SQL (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160604081452"]]
223
+  (7.6ms) COMMIT
224
+ ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
225
+  (1.3ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
226
+ FROM pg_constraint c
227
+ JOIN pg_class t1 ON c.conrelid = t1.oid
228
+ JOIN pg_class t2 ON c.confrelid = t2.oid
229
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
230
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
231
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
232
+ WHERE c.contype = 'f'
233
+ AND t1.relname = 'comments'
234
+ AND t3.nspname = ANY (current_schemas(false))
235
+ ORDER BY c.conname
236
+ 
237
+  (1.1ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
238
+ FROM pg_constraint c
239
+ JOIN pg_class t1 ON c.conrelid = t1.oid
240
+ JOIN pg_class t2 ON c.confrelid = t2.oid
241
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
242
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
243
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
244
+ WHERE c.contype = 'f'
245
+ AND t1.relname = 'employers'
246
+ AND t3.nspname = ANY (current_schemas(false))
247
+ ORDER BY c.conname
248
+
249
+  (1.2ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
250
+ FROM pg_constraint c
251
+ JOIN pg_class t1 ON c.conrelid = t1.oid
252
+ JOIN pg_class t2 ON c.confrelid = t2.oid
253
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
254
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
255
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
256
+ WHERE c.contype = 'f'
257
+ AND t1.relname = 'profiles'
258
+ AND t3.nspname = ANY (current_schemas(false))
259
+ ORDER BY c.conname
260
+ 
261
+  (1.3ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
262
+ FROM pg_constraint c
263
+ JOIN pg_class t1 ON c.conrelid = t1.oid
264
+ JOIN pg_class t2 ON c.confrelid = t2.oid
265
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
266
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
267
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
268
+ WHERE c.contype = 'f'
269
+ AND t1.relname = 'users'
270
+ AND t3.nspname = ANY (current_schemas(false))
271
+ ORDER BY c.conname
272
+
273
+  (33.8ms) CREATE TABLE "schema_migrations" ("version" character varying NOT NULL) 
274
+  (18.4ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
275
+ ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
276
+ Migrating to CreateEmployers (20160213101213)
277
+  (0.1ms) BEGIN
278
+  (26.3ms) CREATE TABLE "employers" ("id" serial primary key, "name" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
279
+  (18.7ms) CREATE INDEX "index_employers_on_id" ON "employers" ("id")
280
+ SQL (0.3ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160213101213"]]
281
+  (19.9ms) COMMIT
282
+ Migrating to CreateUsers (20160213101221)
283
+  (0.2ms) BEGIN
284
+  (34.0ms) CREATE TABLE "users" ("id" serial primary key, "email" character varying, "first_name" character varying, "last_name" character varying, "profile_id" integer, "employer_id" integer, "country_code" character varying NOT NULL, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
285
+  (1.4ms) ALTER TABLE "users" ADD CONSTRAINT "fk_rails_e0dbdd604c"
286
+ FOREIGN KEY ("employer_id")
287
+ REFERENCES "employers" ("id")
288
+ 
289
+  (22.6ms) CREATE INDEX "index_users_on_last_name_and_first_name_and_email" ON "users" ("last_name", "first_name", "email")
290
+  (11.1ms) CREATE INDEX "index_users_on_last_name_and_first_name" ON "users" ("last_name", "first_name")
291
+  (10.7ms) CREATE UNIQUE INDEX "unique_index_on_users_last_name_and_first_name" ON "users" ("last_name", "first_name")
292
+  (17.1ms) CREATE INDEX "index_users_on_last_name" ON "users" ("last_name")
293
+  (11.2ms) CREATE INDEX "index_users_on_email" ON "users" ("email")
294
+  (15.9ms) CREATE UNIQUE INDEX "unique_index_on_users_email" ON "users" ("email")
295
+  (16.5ms) CREATE INDEX "index_users_on_employer_id_and_country_code" ON "users" ("employer_id", "country_code")
296
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160213101221"]]
297
+  (8.9ms) COMMIT
298
+ Migrating to CreateProfiles (20160213101232)
299
+  (0.2ms) BEGIN
300
+  (27.5ms) CREATE TABLE "profiles" ("id" serial primary key, "first_name" character varying, "last_name" character varying, "deleted_at" timestamp, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
301
+  (19.9ms) CREATE INDEX "index_profiles_on_first_name_and_last_name" ON "profiles" ("first_name", "last_name")
302
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160213101232"]]
303
+  (8.1ms) COMMIT
304
+ Migrating to CreateComments (20160604081452)
305
+  (0.1ms) BEGIN
306
+  (35.9ms) CREATE TABLE "comments" ("id" serial primary key, "commentable_id" integer, "commentable_type" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
307
+  (13.4ms) CREATE INDEX "index_comments_on_commentable_type_and_commentable_id" ON "comments" ("commentable_type", "commentable_id")
308
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160604081452"]]
309
+  (2.6ms) COMMIT
310
+ ActiveRecord::SchemaMigration Load (0.1ms) SELECT "schema_migrations".* FROM "schema_migrations"
311
+  (1.6ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
312
+ FROM pg_constraint c
313
+ JOIN pg_class t1 ON c.conrelid = t1.oid
314
+ JOIN pg_class t2 ON c.confrelid = t2.oid
315
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
316
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
317
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
318
+ WHERE c.contype = 'f'
319
+ AND t1.relname = 'comments'
320
+ AND t3.nspname = ANY (current_schemas(false))
321
+ ORDER BY c.conname
322
+
323
+  (1.4ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
324
+ FROM pg_constraint c
325
+ JOIN pg_class t1 ON c.conrelid = t1.oid
326
+ JOIN pg_class t2 ON c.confrelid = t2.oid
327
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
328
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
329
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
330
+ WHERE c.contype = 'f'
331
+ AND t1.relname = 'employers'
332
+ AND t3.nspname = ANY (current_schemas(false))
333
+ ORDER BY c.conname
334
+ 
335
+  (1.5ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
336
+ FROM pg_constraint c
337
+ JOIN pg_class t1 ON c.conrelid = t1.oid
338
+ JOIN pg_class t2 ON c.confrelid = t2.oid
339
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
340
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
341
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
342
+ WHERE c.contype = 'f'
343
+ AND t1.relname = 'profiles'
344
+ AND t3.nspname = ANY (current_schemas(false))
345
+ ORDER BY c.conname
346
+
347
+  (1.6ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
348
+ FROM pg_constraint c
349
+ JOIN pg_class t1 ON c.conrelid = t1.oid
350
+ JOIN pg_class t2 ON c.confrelid = t2.oid
351
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
352
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
353
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
354
+ WHERE c.contype = 'f'
355
+ AND t1.relname = 'users'
356
+ AND t3.nspname = ANY (current_schemas(false))
357
+ ORDER BY c.conname
358
+ 
359
+  (24.1ms) CREATE TABLE "schema_migrations" ("version" character varying NOT NULL) 
360
+  (13.0ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
361
+ ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations".* FROM "schema_migrations"
362
+ Migrating to CreateEmployers (20160213101213)
363
+  (0.1ms) BEGIN
364
+  (34.6ms) CREATE TABLE "employers" ("id" serial primary key, "name" character varying, "deleted_at" timestamp, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
365
+  (14.1ms) CREATE INDEX "index_employers_on_id" ON "employers" ("id")
366
+  (19.3ms) CREATE INDEX "index_employers_on_name" ON "employers" ("name") WHERE deleted_at IS NULL
367
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160213101213"]]
368
+  (12.3ms) COMMIT
369
+ Migrating to CreateUsers (20160213101221)
370
+  (0.1ms) BEGIN
371
+  (31.0ms) CREATE TABLE "users" ("id" serial primary key, "email" character varying, "first_name" character varying, "last_name" character varying, "profile_id" integer, "employer_id" integer, "country_code" character varying NOT NULL, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
372
+  (1.3ms) ALTER TABLE "users" ADD CONSTRAINT "fk_rails_e0dbdd604c"
373
+ FOREIGN KEY ("employer_id")
374
+ REFERENCES "employers" ("id")
375
+
376
+  (16.3ms) CREATE INDEX "index_users_on_last_name_and_first_name_and_email" ON "users" ("last_name", "first_name", "email")
377
+  (10.3ms) CREATE INDEX "index_users_on_last_name_and_first_name" ON "users" ("last_name", "first_name")
378
+  (23.0ms) CREATE UNIQUE INDEX "unique_index_on_users_last_name_and_first_name" ON "users" ("last_name", "first_name")
379
+  (19.1ms) CREATE INDEX "index_users_on_last_name" ON "users" ("last_name")
380
+  (10.5ms) CREATE INDEX "index_users_on_email" ON "users" ("email")
381
+  (15.8ms) CREATE UNIQUE INDEX "unique_index_on_users_email" ON "users" ("email")
382
+  (20.0ms) CREATE INDEX "index_users_on_employer_id_and_country_code" ON "users" ("employer_id", "country_code")
383
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160213101221"]]
384
+  (8.3ms) COMMIT
385
+ Migrating to CreateProfiles (20160213101232)
386
+  (0.2ms) BEGIN
387
+  (28.0ms) CREATE TABLE "profiles" ("id" serial primary key, "first_name" character varying, "last_name" character varying, "deleted_at" timestamp, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
388
+  (18.9ms) CREATE INDEX "index_profiles_on_first_name_and_last_name" ON "profiles" ("first_name", "last_name")
389
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160213101232"]]
390
+  (11.4ms) COMMIT
391
+ Migrating to CreateComments (20160604081452)
392
+  (0.2ms) BEGIN
393
+  (22.1ms) CREATE TABLE "comments" ("id" serial primary key, "commentable_id" integer, "commentable_type" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
394
+  (16.7ms) CREATE INDEX "index_comments_on_commentable_type_and_commentable_id" ON "comments" ("commentable_type", "commentable_id")
395
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160604081452"]]
396
+  (2.1ms) COMMIT
397
+ ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
398
+  (1.6ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
399
+ FROM pg_constraint c
400
+ JOIN pg_class t1 ON c.conrelid = t1.oid
401
+ JOIN pg_class t2 ON c.confrelid = t2.oid
402
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
403
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
404
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
405
+ WHERE c.contype = 'f'
406
+ AND t1.relname = 'comments'
407
+ AND t3.nspname = ANY (current_schemas(false))
408
+ ORDER BY c.conname
409
+ 
410
+  (1.4ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
411
+ FROM pg_constraint c
412
+ JOIN pg_class t1 ON c.conrelid = t1.oid
413
+ JOIN pg_class t2 ON c.confrelid = t2.oid
414
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
415
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
416
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
417
+ WHERE c.contype = 'f'
418
+ AND t1.relname = 'employers'
419
+ AND t3.nspname = ANY (current_schemas(false))
420
+ ORDER BY c.conname
421
+
422
+  (1.5ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
423
+ FROM pg_constraint c
424
+ JOIN pg_class t1 ON c.conrelid = t1.oid
425
+ JOIN pg_class t2 ON c.confrelid = t2.oid
426
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
427
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
428
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
429
+ WHERE c.contype = 'f'
430
+ AND t1.relname = 'profiles'
431
+ AND t3.nspname = ANY (current_schemas(false))
432
+ ORDER BY c.conname
433
+ 
434
+  (1.6ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
435
+ FROM pg_constraint c
436
+ JOIN pg_class t1 ON c.conrelid = t1.oid
437
+ JOIN pg_class t2 ON c.confrelid = t2.oid
438
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
439
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
440
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
441
+ WHERE c.contype = 'f'
442
+ AND t1.relname = 'users'
443
+ AND t3.nspname = ANY (current_schemas(false))
444
+ ORDER BY c.conname
445
+
446
+  (45.0ms) CREATE TABLE "schema_migrations" ("version" character varying NOT NULL) 
447
+  (36.1ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
448
+ ActiveRecord::SchemaMigration Load (0.3ms) SELECT "schema_migrations".* FROM "schema_migrations"
449
+ Migrating to CreateEmployers (20160213101213)
450
+  (0.1ms) BEGIN
451
+  (23.3ms) CREATE TABLE "employers" ("id" serial primary key, "name" character varying, "deleted_at" timestamp, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
452
+  (18.6ms) CREATE INDEX "index_employers_on_id" ON "employers" ("id") WHERE deleted_at IS NULL
453
+  (26.1ms) CREATE INDEX "index_employers_on_name" ON "employers" ("name") WHERE deleted_at IS NULL
454
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160213101213"]]
455
+  (9.6ms) COMMIT
456
+ Migrating to CreateUsers (20160213101221)
457
+  (0.2ms) BEGIN
458
+  (34.7ms) CREATE TABLE "users" ("id" serial primary key, "email" character varying, "first_name" character varying, "last_name" character varying, "profile_id" integer, "employer_id" integer, "country_code" character varying NOT NULL, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
459
+  (1.3ms) ALTER TABLE "users" ADD CONSTRAINT "fk_rails_e0dbdd604c"
460
+ FOREIGN KEY ("employer_id")
461
+ REFERENCES "employers" ("id")
462
+
463
+  (15.0ms) CREATE INDEX "index_users_on_last_name_and_first_name_and_email" ON "users" ("last_name", "first_name", "email")
464
+  (27.7ms) CREATE INDEX "index_users_on_last_name_and_first_name" ON "users" ("last_name", "first_name")
465
+  (11.2ms) CREATE UNIQUE INDEX "unique_index_on_users_last_name_and_first_name" ON "users" ("last_name", "first_name")
466
+  (16.5ms) CREATE INDEX "index_users_on_last_name" ON "users" ("last_name")
467
+  (19.7ms) CREATE INDEX "index_users_on_email" ON "users" ("email")
468
+  (15.9ms) CREATE UNIQUE INDEX "unique_index_on_users_email" ON "users" ("email")
469
+  (12.8ms) CREATE INDEX "index_users_on_employer_id_and_country_code" ON "users" ("employer_id", "country_code")
470
+ SQL (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160213101221"]]
471
+  (8.0ms) COMMIT
472
+ Migrating to CreateProfiles (20160213101232)
473
+  (0.2ms) BEGIN
474
+  (29.6ms) CREATE TABLE "profiles" ("id" serial primary key, "first_name" character varying, "last_name" character varying, "deleted_at" timestamp, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL) 
475
+  (11.0ms) CREATE INDEX "index_profiles_on_first_name_and_last_name" ON "profiles" ("first_name", "last_name")
476
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160213101232"]]
477
+  (8.4ms) COMMIT
478
+ Migrating to CreateComments (20160604081452)
479
+  (0.1ms) BEGIN
480
+  (33.1ms) CREATE TABLE "comments" ("id" serial primary key, "commentable_id" integer, "commentable_type" character varying, "created_at" timestamp NOT NULL, "updated_at" timestamp NOT NULL)
481
+  (10.6ms) CREATE INDEX "index_comments_on_commentable_type_and_commentable_id" ON "comments" ("commentable_type", "commentable_id")
482
+ SQL (0.2ms) INSERT INTO "schema_migrations" ("version") VALUES ($1) [["version", "20160604081452"]]
483
+  (11.8ms) COMMIT
484
+ ActiveRecord::SchemaMigration Load (0.2ms) SELECT "schema_migrations".* FROM "schema_migrations"
485
+  (1.6ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
486
+ FROM pg_constraint c
487
+ JOIN pg_class t1 ON c.conrelid = t1.oid
488
+ JOIN pg_class t2 ON c.confrelid = t2.oid
489
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
490
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
491
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
492
+ WHERE c.contype = 'f'
493
+ AND t1.relname = 'comments'
494
+ AND t3.nspname = ANY (current_schemas(false))
495
+ ORDER BY c.conname
496
+ 
497
+  (1.4ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
498
+ FROM pg_constraint c
499
+ JOIN pg_class t1 ON c.conrelid = t1.oid
500
+ JOIN pg_class t2 ON c.confrelid = t2.oid
501
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
502
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
503
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
504
+ WHERE c.contype = 'f'
505
+ AND t1.relname = 'employers'
506
+ AND t3.nspname = ANY (current_schemas(false))
507
+ ORDER BY c.conname
508
+
509
+  (1.5ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
510
+ FROM pg_constraint c
511
+ JOIN pg_class t1 ON c.conrelid = t1.oid
512
+ JOIN pg_class t2 ON c.confrelid = t2.oid
513
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
514
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
515
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
516
+ WHERE c.contype = 'f'
517
+ AND t1.relname = 'profiles'
518
+ AND t3.nspname = ANY (current_schemas(false))
519
+ ORDER BY c.conname
520
+ 
521
+  (1.6ms) SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete
522
+ FROM pg_constraint c
523
+ JOIN pg_class t1 ON c.conrelid = t1.oid
524
+ JOIN pg_class t2 ON c.confrelid = t2.oid
525
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
526
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
527
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
528
+ WHERE c.contype = 'f'
529
+ AND t1.relname = 'users'
530
+ AND t3.nspname = ANY (current_schemas(false))
531
+ ORDER BY c.conname
532
+