db_leftovers 1.3.3 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog +6 -0
- data/README.md +5 -1
- data/lib/db_leftovers/generic_database_interface.rb +1 -1
- data/lib/db_leftovers/index.rb +25 -4
- data/lib/db_leftovers/postgres_database_interface.rb +7 -3
- data/lib/db_leftovers/version.rb +1 -1
- data/spec/postgres_spec.rb +16 -0
- metadata +3 -2
data/Changelog
ADDED
data/README.md
CHANGED
@@ -44,7 +44,7 @@ Within the DSL file, the following methods are supported:
|
|
44
44
|
|
45
45
|
### index(table\_name, columns, [opts])
|
46
46
|
|
47
|
-
This ensures that you have an index on the given table and column(s). The `columns` parameter can be either a
|
47
|
+
This ensures that you have an index on the given table and column(s). The `columns` parameter can be either a symbol or a list of strings/symbols. (If you pass a single string for the `columns` parameter, it will be treated as the expression for a functional index rather than a column name.) Opts is a hash with the following possible keys:
|
48
48
|
|
49
49
|
* `:name` The name of the index. Defaults to `index_`*table\_name*`_on_`*column\_names*, like the `add_index` method from Rails migrations.
|
50
50
|
|
@@ -54,11 +54,15 @@ This ensures that you have an index on the given table and column(s). The `colum
|
|
54
54
|
|
55
55
|
* `:using` Lets you specify what kind of index to create. Default is `btree`, but if you're on Postgres you might also want `gist`, `gin`, or `hash`.
|
56
56
|
|
57
|
+
* `:function` Lets you specify an expression rather than a list of columns. If you give this option, you should pass an empty list of column names. Alternately, you can pass a string as the column name (rather than a symbol), and db\_leftovers will interpret it as a function.
|
58
|
+
|
57
59
|
#### Examples
|
58
60
|
|
59
61
|
index :books, :author_id
|
60
62
|
index :books, [:publisher_id, :published_at]
|
61
63
|
index :books, :isbn, :unique => true
|
64
|
+
index :authors, [], function: 'lower(name)'
|
65
|
+
index :authors, 'lower(name)'
|
62
66
|
|
63
67
|
### foreign\_key(from\_table, [from\_column], to\_table, [to\_column], [opts])
|
64
68
|
|
data/lib/db_leftovers/index.rb
CHANGED
@@ -3,23 +3,33 @@ module DBLeftovers
|
|
3
3
|
# Just a struct to hold all the info for one index:
|
4
4
|
class Index
|
5
5
|
attr_accessor :table_name, :column_names, :index_name,
|
6
|
-
:where_clause, :using_clause, :unique
|
6
|
+
:where_clause, :using_clause, :unique, :index_function
|
7
7
|
|
8
8
|
def initialize(table_name, column_names, opts={})
|
9
9
|
opts = {
|
10
10
|
:where => nil,
|
11
|
+
:function => nil,
|
11
12
|
:unique => false,
|
12
13
|
:using => nil
|
13
14
|
}.merge(opts)
|
14
15
|
opts.keys.each do |k|
|
15
|
-
raise "Unknown option: #{k}" unless [:where, :unique, :using, :name].include?(k)
|
16
|
+
raise "Unknown option: #{k}" unless [:where, :function, :unique, :using, :name].include?(k)
|
17
|
+
end
|
18
|
+
if column_names.is_a?(String) and opts[:function].nil?
|
19
|
+
opts[:function] = column_names
|
20
|
+
column_names = []
|
16
21
|
end
|
17
22
|
@table_name = table_name.to_s
|
18
23
|
@column_names = [column_names].flatten.map{|x| x.to_s}
|
19
24
|
@where_clause = opts[:where]
|
25
|
+
@index_function = opts[:function]
|
20
26
|
@using_clause = opts[:using]
|
21
27
|
@unique = !!opts[:unique]
|
22
28
|
@index_name = (opts[:name] || choose_name(@table_name, @column_names)).to_s
|
29
|
+
|
30
|
+
raise "Indexes need a table!" unless @table_name
|
31
|
+
raise "Indexes need at least column or an expression!" unless (@column_names.any? or @index_function)
|
32
|
+
raise "Can't have both columns and an expression!" if (@column_names.size > 0 and @index_function)
|
23
33
|
end
|
24
34
|
|
25
35
|
def unique?
|
@@ -31,19 +41,30 @@ module DBLeftovers
|
|
31
41
|
other.column_names == column_names and
|
32
42
|
other.index_name == index_name and
|
33
43
|
other.where_clause == where_clause and
|
44
|
+
other.index_function == index_function and
|
34
45
|
other.using_clause == using_clause and
|
35
46
|
other.unique == unique
|
36
47
|
end
|
37
48
|
|
38
49
|
def to_s
|
39
|
-
"<#{@index_name}: #{@table_name}.[#{column_names.join(",")}] unique=#{@unique}, where=#{@where_clause}, using=#{@using_clause}>"
|
50
|
+
"<#{@index_name}: #{@table_name}.[#{column_names.join(",")}] unique=#{@unique}, where=#{@where_clause}, function=#{@index_function}, using=#{@using_clause}>"
|
40
51
|
end
|
41
52
|
|
42
53
|
private
|
43
54
|
|
44
55
|
def choose_name(table_name, column_names)
|
56
|
+
topic = if column_names.any?
|
57
|
+
column_names.join("_and_")
|
58
|
+
else
|
59
|
+
index_function
|
60
|
+
end
|
61
|
+
ret = "index_#{table_name}_on_#{topic}"
|
62
|
+
ret = ret.gsub(/[^a-zA-Z0-9]/, '_').
|
63
|
+
gsub(/__+/, '_').
|
64
|
+
gsub(/^_/, '').
|
65
|
+
gsub(/_$/, '')
|
45
66
|
# Max length in Postgres is 63; in MySQL 64:
|
46
|
-
|
67
|
+
ret[0,63]
|
47
68
|
end
|
48
69
|
|
49
70
|
end
|
@@ -16,7 +16,8 @@ module DBLeftovers
|
|
16
16
|
ix.indisunique AS is_unique,
|
17
17
|
array_to_string(ix.indkey, ',') AS column_numbers,
|
18
18
|
am.amname AS index_type,
|
19
|
-
pg_get_expr(ix.indpred, ix.indrelid) AS where_clause
|
19
|
+
pg_get_expr(ix.indpred, ix.indrelid) AS where_clause,
|
20
|
+
pg_get_expr(ix.indexprs, ix.indrelid) AS index_function
|
20
21
|
FROM pg_class t,
|
21
22
|
pg_class i,
|
22
23
|
pg_index ix,
|
@@ -37,10 +38,11 @@ module DBLeftovers
|
|
37
38
|
ix.indrelid,
|
38
39
|
ix.indkey,
|
39
40
|
am.amname,
|
40
|
-
ix.indpred
|
41
|
+
ix.indpred,
|
42
|
+
ix.indexprs
|
41
43
|
ORDER BY t.relname, i.relname
|
42
44
|
EOQ
|
43
|
-
@conn.select_rows(sql).each do |indexrelid, indrelid, table_name, index_name, is_unique, column_numbers, index_method, where_clause|
|
45
|
+
@conn.select_rows(sql).each do |indexrelid, indrelid, table_name, index_name, is_unique, column_numbers, index_method, where_clause, index_function|
|
44
46
|
where_clause = remove_outer_parens(where_clause) if where_clause
|
45
47
|
index_method = nil if index_method == 'btree'
|
46
48
|
ret[index_name] = Index.new(
|
@@ -48,6 +50,7 @@ module DBLeftovers
|
|
48
50
|
column_names_for_index(indrelid, column_numbers.split(",")),
|
49
51
|
unique: is_unique == 't',
|
50
52
|
where: where_clause,
|
53
|
+
function: index_function,
|
51
54
|
using: index_method,
|
52
55
|
name: index_name
|
53
56
|
)
|
@@ -128,6 +131,7 @@ module DBLeftovers
|
|
128
131
|
private
|
129
132
|
|
130
133
|
def column_names_for_index(table_id, column_numbers)
|
134
|
+
return [] if column_numbers == ['0']
|
131
135
|
column_numbers.map do |c|
|
132
136
|
sql = <<-EOQ
|
133
137
|
SELECT attname
|
data/lib/db_leftovers/version.rb
CHANGED
data/spec/postgres_spec.rb
CHANGED
@@ -102,6 +102,22 @@ describe DBLeftovers::PostgresDatabaseInterface do
|
|
102
102
|
@db.lookup_all_constraints['books_have_positive_pages'].check.should == 'pages_count > 12'
|
103
103
|
end
|
104
104
|
|
105
|
+
it "should allow functional indexes, specified as a string" do
|
106
|
+
DBLeftovers::Definition.define :db_interface => @db do
|
107
|
+
index :authors, 'lower(name)'
|
108
|
+
end
|
109
|
+
@db.lookup_all_indexes.size.should == 1
|
110
|
+
@db.lookup_all_indexes.keys.sort.should == ['index_authors_on_lower_name']
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should allow functional indexes, specified with an option" do
|
114
|
+
DBLeftovers::Definition.define :db_interface => @db do
|
115
|
+
index :authors, [], function: 'lower(name)'
|
116
|
+
end
|
117
|
+
@db.lookup_all_indexes.size.should == 1
|
118
|
+
@db.lookup_all_indexes.keys.sort.should == ['index_authors_on_lower_name']
|
119
|
+
end
|
120
|
+
|
105
121
|
end
|
106
122
|
end
|
107
123
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: db_leftovers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -69,6 +69,7 @@ extra_rdoc_files: []
|
|
69
69
|
files:
|
70
70
|
- .document
|
71
71
|
- .gitignore
|
72
|
+
- Changelog
|
72
73
|
- Gemfile
|
73
74
|
- Gemfile.lock
|
74
75
|
- LICENSE.txt
|
@@ -111,7 +112,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
111
112
|
version: '0'
|
112
113
|
segments:
|
113
114
|
- 0
|
114
|
-
hash:
|
115
|
+
hash: 1649859164079023412
|
115
116
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
117
|
none: false
|
117
118
|
requirements:
|