historiographer 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/historiographer.gemspec +5 -3
- data/lib/historiographer/history_migration.rb +40 -29
- data/spec/db/database.yml +21 -22
- data/spec/db/migrate/20191024142304_create_thing_with_compound_index.rb +10 -0
- data/spec/db/migrate/20191024142352_create_thing_with_compound_index_history.rb +11 -0
- data/spec/db/schema.rb +31 -8
- data/spec/historiographer_spec.rb +53 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7cb91195d9d049faf9de52f631cd6c64c46c24e3e0d44fba5ea446197986d98
|
4
|
+
data.tar.gz: 0236e459a57ec0a4105f9dd9a8e933745f98e9942d2919298e97e6cf7a32c3d3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6ddac0ce23e3b5ded4dc95a6c8d2e5b0870bc95e40e89d5d3fbf2e867511cc6320d23f4ac1562191c025d011161afca0f1c107fcb0c9a64d59799183bb31ef5a
|
7
|
+
data.tar.gz: ac97602293b1488db300d33178bf1c697f69613e3929c62aa5199c2a11a3d6ae07e4d8a1afb1198a8a41761c6ff09726c4fee5570ef17f35721ff5e8ce8756f5
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
data/historiographer.gemspec
CHANGED
@@ -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.
|
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.
|
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-
|
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
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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" }.
|
73
|
-
|
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
|
data/spec/db/database.yml
CHANGED
@@ -1,27 +1,26 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
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
|
-
<<: *
|
23
|
-
database: historiographer_development
|
7
|
+
<<: *default
|
24
8
|
|
25
9
|
test:
|
26
|
-
|
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,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
|
data/spec/db/schema.rb
CHANGED
@@ -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:
|
13
|
+
ActiveRecord::Schema.define(version: 2019_10_24_142352) do
|
14
14
|
|
15
|
-
|
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",
|
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",
|
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",
|
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",
|
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",
|
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 "
|
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.
|
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
|
+
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
|