active_record_doctor 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+