historiographer 1.1.0 → 1.2.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
  SHA256:
3
- metadata.gz: 433e733811c7f23a3044282b54c87832abc944e3f46817d16036c87778f938ff
4
- data.tar.gz: 54e27e8e68ab4512bb5edf146d1c210f9072ad99346d8a1ced37e6766d014d3b
3
+ metadata.gz: e7cb91195d9d049faf9de52f631cd6c64c46c24e3e0d44fba5ea446197986d98
4
+ data.tar.gz: 0236e459a57ec0a4105f9dd9a8e933745f98e9942d2919298e97e6cf7a32c3d3
5
5
  SHA512:
6
- metadata.gz: 1abd0b29fc36c284fb6e8c5da6c884640678ce0dd9b58c089b15056897514f7cd47b8d4117e54b3549d306be6ce0a08c36f772724bc741fd09cf782a174c0415
7
- data.tar.gz: c63eecd58ea1b7ad604d3cf049735b2fed3bdd403aa2c508190a3907b6dfcaf7ecb6094b9ac14bf2fb0d5574e8277a0c2b05ef06d25a8291bfbc3306c419decb
6
+ metadata.gz: 6ddac0ce23e3b5ded4dc95a6c8d2e5b0870bc95e40e89d5d3fbf2e867511cc6320d23f4ac1562191c025d011161afca0f1c107fcb0c9a64d59799183bb31ef5a
7
+ data.tar.gz: ac97602293b1488db300d33178bf1c697f69613e3929c62aa5199c2a11a3d6ae07e4d8a1afb1198a8a41761c6ff09726c4fee5570ef17f35721ff5e8ce8756f5
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.2.0
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: historiographer 1.1.0 ruby lib
5
+ # stub: historiographer 1.2.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "historiographer".freeze
9
- s.version = "1.1.0"
9
+ s.version = "1.2.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib".freeze]
13
13
  s.authors = ["brettshollenberger".freeze]
14
- s.date = "2019-10-11"
14
+ s.date = "2019-10-24"
15
15
  s.description = "Creates separate tables for each history table".freeze
16
16
  s.email = "brett.shollenberger@gmail.com".freeze
17
17
  s.extra_rdoc_files = [
@@ -47,6 +47,8 @@ Gem::Specification.new do |s|
47
47
  "spec/db/migrate/20161121212232_create_users.rb",
48
48
  "spec/db/migrate/20171011194624_create_safe_posts.rb",
49
49
  "spec/db/migrate/20171011194715_create_safe_post_histories.rb",
50
+ "spec/db/migrate/20191024142304_create_thing_with_compound_index.rb",
51
+ "spec/db/migrate/20191024142352_create_thing_with_compound_index_history.rb",
50
52
  "spec/db/schema.rb",
51
53
  "spec/examples.txt",
52
54
  "spec/historiographer_spec.rb",
@@ -16,7 +16,8 @@ module Historiographer
16
16
  # Will automatically add user_id, history_started_at,
17
17
  # and history_ended_at columns
18
18
  #
19
- def histories(except: [], only: [], no_business_columns: false)
19
+ def histories(except: [], only: [], no_business_columns: false, index_names: {})
20
+ index_names.symbolize_keys!
20
21
  original_table_name = self.name.gsub(/_histories$/) {}.pluralize
21
22
  foreign_key = original_table_name.singularize.foreign_key
22
23
 
@@ -32,7 +33,6 @@ module Historiographer
32
33
  original_columns.each do |column|
33
34
  opts = {}
34
35
  opts.merge!(column.as_json.clone)
35
- # opts.merge!(column.type.as_json.clone)
36
36
 
37
37
  send(column.type, column.name, opts.symbolize_keys!)
38
38
  end
@@ -41,38 +41,49 @@ module Historiographer
41
41
  datetime :history_ended_at
42
42
  integer :history_user_id
43
43
 
44
- index :history_started_at
45
- index :history_ended_at
46
- index :history_user_id
47
- index foreign_key
48
-
49
- indices_sql = <<-SQL
50
- SELECT
51
- a.attname AS column_name
52
- FROM
53
- pg_class t,
54
- pg_class i,
55
- pg_index ix,
56
- pg_attribute a
57
- WHERE
58
- t.oid = ix.indrelid
59
- AND i.oid = ix.indexrelid
60
- AND a.attrelid = t.oid
61
- AND a.attnum = ANY(ix.indkey)
62
- AND t.relkind = 'r'
63
- AND t.relname = ?
64
- ORDER BY
65
- t.relname,
66
- i.relname;
67
- SQL
44
+ indices_sql = %q(
45
+ SELECT
46
+ DISTINCT(
47
+ ARRAY_TO_STRING(ARRAY(
48
+ SELECT pg_get_indexdef(idx.indexrelid, k + 1, true)
49
+ FROM generate_subscripts(idx.indkey, 1) as k
50
+ ORDER BY k
51
+ ), ',')
52
+ ) as indkey_names
53
+ FROM pg_class t,
54
+ pg_class i,
55
+ pg_index idx,
56
+ pg_attribute a,
57
+ pg_am am
58
+ WHERE t.oid = idx.indrelid
59
+ AND i.oid = idx.indexrelid
60
+ AND a.attrelid = t.oid
61
+ AND a.attnum = ANY(idx.indkey)
62
+ AND t.relkind = 'r'
63
+ AND t.relname = ?;
64
+ )
68
65
 
69
66
  indices_query_array = [indices_sql, original_table_name]
70
67
  indices_sanitized_query = klass.send(:sanitize_sql_array, indices_query_array)
71
68
 
72
- klass.connection.execute(indices_sanitized_query).to_a.map(&:values).flatten.reject { |i| i == "id" }.each do |index_name|
73
- index index_name.to_sym
69
+ indexes = klass.connection.execute(indices_sanitized_query).to_a.map(&:values).flatten.reject { |i| i == "id" }.map { |i| i.split(",") }.concat([
70
+ foreign_key,
71
+ :history_started_at,
72
+ :history_ended_at,
73
+ :history_user_id
74
+ ])
75
+
76
+ indexes.each do |index_definition|
77
+ index_definition = [index_definition].flatten.map(&:to_sym)
78
+ index_name = index_definition.count == 1 ? index_definition.first : index_definition
79
+
80
+ if index_names.key?(index_name)
81
+ index index_name, name: index_names[index_name]
82
+ else
83
+ index index_name
84
+ end
74
85
  end
75
86
 
76
87
  end
77
88
  end
78
- end
89
+ end
@@ -1,27 +1,26 @@
1
- # default: &default
2
- # adapter: postgresql
3
- # prepared_statements: false
4
- # url: "postgres://localhost/historiographer_development"
5
-
6
- # development:
7
- # <<: *default
8
-
9
- # test:
10
- # adapter: postgresql
11
- # database: historiographer_test
12
-
13
- mysql_default: &mysql_default
14
- adapter: mysql2
15
- encoding: utf8
16
- username: root
17
- password:
18
- host: 127.0.0.1
19
- port: 3306
1
+ default: &default
2
+ adapter: postgresql
3
+ prepared_statements: false
4
+ url: "postgres://localhost/historiographer_development"
20
5
 
21
6
  development:
22
- <<: *mysql_default
23
- database: historiographer_development
7
+ <<: *default
24
8
 
25
9
  test:
26
- <<: *mysql_default
10
+ adapter: postgresql
27
11
  database: historiographer_test
12
+ # mysql_default: &mysql_default
13
+ # adapter: mysql2
14
+ # encoding: utf8
15
+ # username: root
16
+ # password:
17
+ # host: 127.0.0.1
18
+ # port: 3306
19
+
20
+ # development:
21
+ # <<: *mysql_default
22
+ # database: historiographer_development
23
+
24
+ # test:
25
+ # <<: *mysql_default
26
+ # database: historiographer_test
@@ -0,0 +1,10 @@
1
+ class CreateThingWithCompoundIndex < ActiveRecord::Migration[5.2]
2
+ def change
3
+ create_table :thing_with_compound_indices do |t|
4
+ t.string :key
5
+ t.string :value
6
+
7
+ t.index [:key, :value], name: "idx_key_value"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ require "historiographer/postgres_migration"
2
+ class CreateThingWithCompoundIndexHistory < ActiveRecord::Migration[5.2]
3
+ def change
4
+ create_table :thing_with_compound_index_histories do |t|
5
+ t.histories index_names: {
6
+ [:key, :value] => "idx_history_k_v",
7
+ :thing_with_compound_index_id => "idx_k_v_histories"
8
+ }
9
+ end
10
+ end
11
+ end
@@ -10,9 +10,12 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 2017_10_11_194715) do
13
+ ActiveRecord::Schema.define(version: 2019_10_24_142352) do
14
14
 
15
- create_table "author_histories", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
15
+ # These are extensions that must be enabled in order to support this database
16
+ enable_extension "plpgsql"
17
+
18
+ create_table "author_histories", force: :cascade do |t|
16
19
  t.integer "author_id", null: false
17
20
  t.string "full_name", null: false
18
21
  t.text "bio"
@@ -29,7 +32,7 @@ ActiveRecord::Schema.define(version: 2017_10_11_194715) do
29
32
  t.index ["history_user_id"], name: "index_author_histories_on_history_user_id"
30
33
  end
31
34
 
32
- create_table "authors", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
35
+ create_table "authors", force: :cascade do |t|
33
36
  t.string "full_name", null: false
34
37
  t.text "bio"
35
38
  t.datetime "deleted_at"
@@ -38,7 +41,7 @@ ActiveRecord::Schema.define(version: 2017_10_11_194715) do
38
41
  t.index ["deleted_at"], name: "index_authors_on_deleted_at"
39
42
  end
40
43
 
41
- create_table "post_histories", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
44
+ create_table "post_histories", force: :cascade do |t|
42
45
  t.integer "post_id", null: false
43
46
  t.string "title", null: false
44
47
  t.text "body", null: false
@@ -61,7 +64,7 @@ ActiveRecord::Schema.define(version: 2017_10_11_194715) do
61
64
  t.index ["post_id"], name: "index_post_histories_on_post_id"
62
65
  end
63
66
 
64
- create_table "posts", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
67
+ create_table "posts", force: :cascade do |t|
65
68
  t.string "title", null: false
66
69
  t.text "body", null: false
67
70
  t.integer "author_id", null: false
@@ -76,7 +79,7 @@ ActiveRecord::Schema.define(version: 2017_10_11_194715) do
76
79
  t.index ["live_at"], name: "index_posts_on_live_at"
77
80
  end
78
81
 
79
- create_table "safe_post_histories", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
82
+ create_table "safe_post_histories", force: :cascade do |t|
80
83
  t.integer "safe_post_id", null: false
81
84
  t.string "title", null: false
82
85
  t.text "body", null: false
@@ -99,7 +102,7 @@ ActiveRecord::Schema.define(version: 2017_10_11_194715) do
99
102
  t.index ["safe_post_id"], name: "index_safe_post_histories_on_safe_post_id"
100
103
  end
101
104
 
102
- create_table "safe_posts", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
105
+ create_table "safe_posts", force: :cascade do |t|
103
106
  t.string "title", null: false
104
107
  t.text "body", null: false
105
108
  t.integer "author_id", null: false
@@ -114,7 +117,27 @@ ActiveRecord::Schema.define(version: 2017_10_11_194715) do
114
117
  t.index ["live_at"], name: "index_safe_posts_on_live_at"
115
118
  end
116
119
 
117
- create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
120
+ create_table "thing_with_compound_index_histories", force: :cascade do |t|
121
+ t.integer "thing_with_compound_index_id", null: false
122
+ t.string "key"
123
+ t.string "value"
124
+ t.datetime "history_started_at", null: false
125
+ t.datetime "history_ended_at"
126
+ t.integer "history_user_id"
127
+ t.index ["history_ended_at"], name: "index_thing_with_compound_index_histories_on_history_ended_at"
128
+ t.index ["history_started_at"], name: "index_thing_with_compound_index_histories_on_history_started_at"
129
+ t.index ["history_user_id"], name: "index_thing_with_compound_index_histories_on_history_user_id"
130
+ t.index ["key", "value"], name: "idx_history_k_v"
131
+ t.index ["thing_with_compound_index_id"], name: "idx_k_v_histories"
132
+ end
133
+
134
+ create_table "thing_with_compound_indices", force: :cascade do |t|
135
+ t.string "key"
136
+ t.string "value"
137
+ t.index ["key", "value"], name: "idx_key_value"
138
+ end
139
+
140
+ create_table "users", force: :cascade do |t|
118
141
  t.string "name"
119
142
  end
120
143
 
@@ -24,6 +24,13 @@ end
24
24
  class User < ActiveRecord::Base
25
25
  end
26
26
 
27
+ class ThingWithCompoundIndex < ActiveRecord::Base
28
+ include Historiographer
29
+ end
30
+
31
+ class ThingWithCompoundIndexHistory < ActiveRecord::Base
32
+ end
33
+
27
34
  describe Historiographer do
28
35
  before(:all) do
29
36
  @now = Timecop.freeze
@@ -317,6 +324,8 @@ describe Historiographer do
317
324
  body,
318
325
  post_id,
319
326
  author_id,
327
+ created_at,
328
+ updated_at,
320
329
  history_started_at,
321
330
  history_ended_at
322
331
  ) VALUES (
@@ -324,6 +333,8 @@ describe Historiographer do
324
333
  'Text',
325
334
  1,
326
335
  1,
336
+ now(),
337
+ now(),
327
338
  now() - INTERVAL '1 day',
328
339
  NULL
329
340
  ), (
@@ -331,6 +342,8 @@ describe Historiographer do
331
342
  'Different text',
332
343
  1,
333
344
  1,
345
+ now(),
346
+ now(),
334
347
  now() - INTERVAL '12 hours',
335
348
  NULL
336
349
  ), (
@@ -338,6 +351,8 @@ describe Historiographer do
338
351
  'Even more different text',
339
352
  1,
340
353
  1,
354
+ now(),
355
+ now(),
341
356
  now() - INTERVAL '12 hours',
342
357
  NULL
343
358
  )
@@ -407,4 +422,42 @@ describe Historiographer do
407
422
  expect(author.current_history.user.name).to eq username
408
423
  end
409
424
  end
425
+
426
+ describe "Migrations with compound indexes" do
427
+ it "supports renaming compound indexes and migrating them to history tables" do
428
+ indices_sql = %q(
429
+ SELECT
430
+ DISTINCT(
431
+ ARRAY_TO_STRING(ARRAY(
432
+ SELECT pg_get_indexdef(idx.indexrelid, k + 1, true)
433
+ FROM generate_subscripts(idx.indkey, 1) as k
434
+ ORDER BY k
435
+ ), ',')
436
+ ) as indkey_names
437
+ FROM pg_class t,
438
+ pg_class i,
439
+ pg_index idx,
440
+ pg_attribute a,
441
+ pg_am am
442
+ WHERE t.oid = idx.indrelid
443
+ AND i.oid = idx.indexrelid
444
+ AND a.attrelid = t.oid
445
+ AND a.attnum = ANY(idx.indkey)
446
+ AND t.relkind = 'r'
447
+ AND t.relname = ?;
448
+ )
449
+
450
+ indices_query_array = [indices_sql, :thing_with_compound_index_histories]
451
+ indices_sanitized_query = ThingWithCompoundIndexHistory.send(:sanitize_sql_array, indices_query_array)
452
+
453
+ indexes = ThingWithCompoundIndexHistory.connection.execute(indices_sanitized_query).to_a.map(&:values).flatten.map { |i| i.split(",") }
454
+
455
+ expect(indexes).to include(["history_started_at"])
456
+ expect(indexes).to include(["history_ended_at"])
457
+ expect(indexes).to include(["history_user_id"])
458
+ expect(indexes).to include(["id"])
459
+ expect(indexes).to include(["key", "value"])
460
+ expect(indexes).to include(["thing_with_compound_index_id"])
461
+ end
462
+ end
410
463
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: historiographer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - brettshollenberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-10-11 00:00:00.000000000 Z
11
+ date: 2019-10-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -228,6 +228,8 @@ files:
228
228
  - spec/db/migrate/20161121212232_create_users.rb
229
229
  - spec/db/migrate/20171011194624_create_safe_posts.rb
230
230
  - spec/db/migrate/20171011194715_create_safe_post_histories.rb
231
+ - spec/db/migrate/20191024142304_create_thing_with_compound_index.rb
232
+ - spec/db/migrate/20191024142352_create_thing_with_compound_index_history.rb
231
233
  - spec/db/schema.rb
232
234
  - spec/examples.txt
233
235
  - spec/historiographer_spec.rb