activerecord-covering-index 0.1.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 +7 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/Appraisals +11 -0
- data/Gemfile +3 -0
- data/README.md +97 -0
- data/Rakefile +6 -0
- data/activerecord-covering-index.gemspec +29 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/activerecord-covering-index.rb +15 -0
- data/lib/activerecord-covering-index/abstract_adapter.rb +9 -0
- data/lib/activerecord-covering-index/index_definition.rb +36 -0
- data/lib/activerecord-covering-index/postgresql_adapter.rb +125 -0
- data/lib/activerecord-covering-index/schema_creation.rb +36 -0
- data/lib/activerecord-covering-index/schema_dumper.rb +13 -0
- data/lib/activerecord-covering-index/version.rb +3 -0
- metadata +123 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ab81849fab4e6f4f806285e0260d6cd85dcf3b30ea6ca6ddf34246eade1d75ee
|
4
|
+
data.tar.gz: 154b89bcb99f80e44872b07d2192f799cc211e9e91c2ef8542881e2d0e97374b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a5c108baf5d51576070829e94af6789591f212ff712631b96f48948a85a17da8c31f8d6411eb1ed78833052a636000b0947fc2e51d0328481b49ed9eb221bda6
|
7
|
+
data.tar.gz: f658f0294875aeb8d9e482f4cad5485a27c9375e7d8a8d8240a969516ff510f0be8e854101faf4431cdca1308ce3b2f763c193be9557c582b968d4cb423123c5
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Appraisals
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# activerecord-covering-index
|
2
|
+
|
3
|
+
Extends ActiveRecord/Rails to support [covering indexes](https://www.postgresql.org/docs/11/indexes-index-only-scans.html) in PostgreSQL using the `INCLUDE` clause.
|
4
|
+
|
5
|
+
From the [PostgreSQL documentation](https://www.postgresql.org/docs/11/sql-createindex.html):
|
6
|
+
|
7
|
+
> The optional INCLUDE clause specifies a list of columns which will be included in the index as non-key columns. A non-key column cannot be used in an index scan search qualification, and it is disregarded for purposes of any uniqueness or exclusion constraint enforced by the index. However, an index-only scan can return the contents of non-key columns without having to visit the index's table, since they are available directly from the index entry. Thus, addition of non-key columns allows index-only scans to be used for queries that otherwise could not use them.
|
8
|
+
|
9
|
+
## Compatibility
|
10
|
+
|
11
|
+
- ActiveRecord 5.2, 6.0 and 6.1
|
12
|
+
- PostgreSQL 11 and later
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
```ruby
|
19
|
+
gem 'activerecord-covering-index'
|
20
|
+
```
|
21
|
+
|
22
|
+
And then execute:
|
23
|
+
|
24
|
+
$ bundle install
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
In a migration, use the `include` option with `add_index`:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
class IndexUsersOnName < ActiveRecord::Migration[6.1]
|
32
|
+
def change
|
33
|
+
add_index :users, :name, include: :email
|
34
|
+
end
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
Or within a `create_table` block:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
class CreateUsers < ActiveRecord::Migration[6.1]
|
42
|
+
def change
|
43
|
+
create_table :users do |t|
|
44
|
+
t.string :name
|
45
|
+
t.string :email
|
46
|
+
t.timestamps
|
47
|
+
|
48
|
+
t.index :name, include: :email
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
```
|
53
|
+
|
54
|
+
You can also `include` multiple columns:
|
55
|
+
|
56
|
+
```ruby
|
57
|
+
add_index :users, :name, include: [:email, :updated_at]
|
58
|
+
```
|
59
|
+
|
60
|
+
Or combine `include` with other index options:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
add_index :users, :name, include: :email, where: 'email IS NOT NULL', unique: true
|
64
|
+
```
|
65
|
+
|
66
|
+
## Caveats
|
67
|
+
|
68
|
+
Non-key columns are not included in the name Rails generates for an index. For example, the following two indexes will receive the same name, which causes the second to raise a `PG::DuplicateTable` error:
|
69
|
+
|
70
|
+
```ruby
|
71
|
+
add_index :users, :name
|
72
|
+
add_index :users, :name, include: :email
|
73
|
+
```
|
74
|
+
|
75
|
+
To avoid collisions, you can specify a different name:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
add_index :users, :name, include: :email, name: 'index_users_on_name_include_email'
|
79
|
+
```
|
80
|
+
|
81
|
+
## Development
|
82
|
+
|
83
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
84
|
+
|
85
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
86
|
+
|
87
|
+
## Contributing
|
88
|
+
|
89
|
+
Bug reports and merge requests are welcome on GitLab at https://gitlab.com/schlock/activerecord-covering-index.
|
90
|
+
|
91
|
+
## License
|
92
|
+
|
93
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
94
|
+
|
95
|
+
## Credits
|
96
|
+
|
97
|
+
The gem was adapted from https://github.com/rails/rails/pull/37515, created by [@sebastian-palma](https://github.com/sebastian-palma).
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'lib/activerecord-covering-index/version'
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "activerecord-covering-index"
|
5
|
+
spec.version = ActiverecordCoveringIndex::VERSION
|
6
|
+
spec.authors = ["Tiger Watson"]
|
7
|
+
spec.email = ["tigerwnz@gmail.com"]
|
8
|
+
|
9
|
+
spec.summary = %q{Create covering indexes in Rails with PostgreSQL}
|
10
|
+
spec.description = %q{Extends ActiveRecord to support covering indexes in PostgreSQL using the INCLUDE clause.}
|
11
|
+
spec.homepage = "https://gitlab.com/schlock/activerecord-covering-index"
|
12
|
+
spec.license = "MIT"
|
13
|
+
|
14
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
15
|
+
|
16
|
+
# Specify which files should be added to the gem when it is released.
|
17
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
18
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
19
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(.gitlab|spec|gemfiles)/}) }
|
20
|
+
end
|
21
|
+
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_dependency "activerecord", ">= 5.2", "< 7"
|
25
|
+
spec.add_dependency "pg"
|
26
|
+
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.10"
|
28
|
+
spec.add_development_dependency "appraisal", "~> 2.4"
|
29
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "activerecord-covering-index"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require "active_record/connection_adapters/postgresql_adapter"
|
3
|
+
|
4
|
+
require 'activerecord-covering-index/version'
|
5
|
+
require 'activerecord-covering-index/abstract_adapter'
|
6
|
+
require 'activerecord-covering-index/postgresql_adapter'
|
7
|
+
require 'activerecord-covering-index/schema_creation'
|
8
|
+
require 'activerecord-covering-index/index_definition'
|
9
|
+
require 'activerecord-covering-index/schema_dumper'
|
10
|
+
|
11
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, ActiverecordCoveringIndex::AbstractAdapter)
|
12
|
+
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.send(:prepend, ActiverecordCoveringIndex::PostgreSQLAdapter)
|
13
|
+
ActiveRecord::ConnectionAdapters::SchemaCreation.send(:prepend, ActiverecordCoveringIndex::SchemaCreation)
|
14
|
+
ActiveRecord::ConnectionAdapters::IndexDefinition.send(:prepend, ActiverecordCoveringIndex::IndexDefinition)
|
15
|
+
ActiveRecord::SchemaDumper.send(:prepend, ActiverecordCoveringIndex::SchemaDumper)
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiverecordCoveringIndex
|
4
|
+
module IndexDefinition
|
5
|
+
def self.prepended(base)
|
6
|
+
base.attr_reader :include
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(
|
10
|
+
table, name,
|
11
|
+
unique = false,
|
12
|
+
columns = [],
|
13
|
+
lengths: {},
|
14
|
+
orders: {},
|
15
|
+
opclasses: {},
|
16
|
+
where: nil,
|
17
|
+
type: nil,
|
18
|
+
using: nil,
|
19
|
+
comment: nil,
|
20
|
+
include: []
|
21
|
+
)
|
22
|
+
@table = table
|
23
|
+
@name = name
|
24
|
+
@unique = unique
|
25
|
+
@columns = columns
|
26
|
+
@lengths = concise_options(lengths)
|
27
|
+
@orders = concise_options(orders)
|
28
|
+
@opclasses = concise_options(opclasses)
|
29
|
+
@where = where
|
30
|
+
@type = type
|
31
|
+
@using = using
|
32
|
+
@comment = comment
|
33
|
+
@include = include
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiverecordCoveringIndex
|
4
|
+
module PostgreSQLAdapter
|
5
|
+
def supports_covering_index?
|
6
|
+
if respond_to?(:database_version) # ActiveRecord 6+
|
7
|
+
database_version >= 110_000
|
8
|
+
else
|
9
|
+
postgresql_version >= 110_000
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_index_options(table_name, column_name, name: nil, if_not_exists: false, internal: false, **options)
|
14
|
+
options.assert_valid_keys(:unique, :length, :order, :opclass, :where, :type, :using, :comment, :algorithm, :include)
|
15
|
+
|
16
|
+
options[:name] = name if name
|
17
|
+
options[:internal] = internal
|
18
|
+
non_key_columns = options.delete(:include)
|
19
|
+
|
20
|
+
original_index_options = super(table_name, column_name, **options)
|
21
|
+
|
22
|
+
if original_index_options.first.is_a?(String)
|
23
|
+
index_name, index_type, index_columns, index_options, algorithm, using, comment = original_index_options
|
24
|
+
|
25
|
+
if non_key_columns && supports_covering_index?
|
26
|
+
non_key_columns = [non_key_columns] if non_key_columns.is_a?(Symbol)
|
27
|
+
non_key_columns = quoted_columns_for_index(non_key_columns, {}).join(", ")
|
28
|
+
|
29
|
+
index_options = " INCLUDE (#{non_key_columns})" + index_options
|
30
|
+
end
|
31
|
+
|
32
|
+
[index_name, index_type, index_columns, index_options, algorithm, using, comment]
|
33
|
+
else
|
34
|
+
index, algorithm, if_not_exists = original_index_options
|
35
|
+
|
36
|
+
index_with_include = ActiveRecord::ConnectionAdapters::IndexDefinition.new(
|
37
|
+
index.table,
|
38
|
+
index.name,
|
39
|
+
index.unique,
|
40
|
+
index.columns,
|
41
|
+
lengths: index.lengths,
|
42
|
+
orders: index.orders,
|
43
|
+
opclasses: index.opclasses,
|
44
|
+
where: index.where,
|
45
|
+
type: index.type,
|
46
|
+
using: index.using,
|
47
|
+
comment: index.comment,
|
48
|
+
include: non_key_columns
|
49
|
+
)
|
50
|
+
|
51
|
+
[index_with_include, algorithm, if_not_exists]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def indexes(table_name)
|
56
|
+
scope = quoted_scope(table_name)
|
57
|
+
|
58
|
+
result = query(<<~SQL, "SCHEMA")
|
59
|
+
SELECT distinct i.relname, d.indisunique, d.indkey, pg_get_indexdef(d.indexrelid), t.oid,
|
60
|
+
pg_catalog.obj_description(i.oid, 'pg_class') AS comment, d.indnkeyatts
|
61
|
+
FROM pg_class t
|
62
|
+
INNER JOIN pg_index d ON t.oid = d.indrelid
|
63
|
+
INNER JOIN pg_class i ON d.indexrelid = i.oid
|
64
|
+
LEFT JOIN pg_namespace n ON n.oid = i.relnamespace
|
65
|
+
WHERE i.relkind IN ('i', 'I')
|
66
|
+
AND d.indisprimary = 'f'
|
67
|
+
AND t.relname = #{scope[:name]}
|
68
|
+
AND n.nspname = #{scope[:schema]}
|
69
|
+
ORDER BY i.relname
|
70
|
+
SQL
|
71
|
+
|
72
|
+
result.map do |row|
|
73
|
+
index_name = row[0]
|
74
|
+
unique = row[1]
|
75
|
+
indkey = row[2].split(" ").map(&:to_i)
|
76
|
+
inddef = row[3]
|
77
|
+
oid = row[4]
|
78
|
+
comment = row[5]
|
79
|
+
indnkeyatts = row[6]
|
80
|
+
|
81
|
+
using, expressions, _, where = inddef.scan(/ USING (\w+?) \((.+?)\)(?: INCLUDE \((.+?)\))?(?: WHERE (.+))?\z/m).flatten
|
82
|
+
|
83
|
+
orders = {}
|
84
|
+
opclasses = {}
|
85
|
+
|
86
|
+
columns = Hash[query(<<~SQL, "SCHEMA")].values_at(*indkey)
|
87
|
+
SELECT a.attnum, a.attname
|
88
|
+
FROM pg_attribute a
|
89
|
+
WHERE a.attrelid = #{oid}
|
90
|
+
AND a.attnum IN (#{indkey.join(",")})
|
91
|
+
SQL
|
92
|
+
|
93
|
+
non_key_columns = columns.pop(columns.count - indnkeyatts)
|
94
|
+
|
95
|
+
if indkey.include?(0)
|
96
|
+
columns = expressions
|
97
|
+
else
|
98
|
+
# add info on sort order (only desc order is explicitly specified, asc is the default)
|
99
|
+
# and non-default opclasses
|
100
|
+
expressions.scan(/(?<column>\w+)"?\s?(?<opclass>\w+_ops)?\s?(?<desc>DESC)?\s?(?<nulls>NULLS (?:FIRST|LAST))?/).each do |column, opclass, desc, nulls|
|
101
|
+
opclasses[column] = opclass.to_sym if opclass
|
102
|
+
if nulls
|
103
|
+
orders[column] = [desc, nulls].compact.join(" ")
|
104
|
+
else
|
105
|
+
orders[column] = :desc if desc
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
ActiveRecord::ConnectionAdapters::IndexDefinition.new(
|
111
|
+
table_name,
|
112
|
+
index_name,
|
113
|
+
unique,
|
114
|
+
columns,
|
115
|
+
orders: orders,
|
116
|
+
opclasses: opclasses,
|
117
|
+
where: where,
|
118
|
+
using: using.to_sym,
|
119
|
+
comment: comment.presence,
|
120
|
+
include: non_key_columns
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiverecordCoveringIndex
|
4
|
+
module SchemaCreation
|
5
|
+
def self.prepended(base)
|
6
|
+
attr_opts = { to: :@conn }
|
7
|
+
attr_opts[:private] = true if ActiveRecord::VERSION::MAJOR >= 6
|
8
|
+
|
9
|
+
base.delegate :supports_covering_index?, **attr_opts
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def visit_CreateIndexDefinition(o)
|
15
|
+
index = o.index
|
16
|
+
|
17
|
+
sql = ["CREATE"]
|
18
|
+
sql << "UNIQUE" if index.unique
|
19
|
+
sql << "INDEX"
|
20
|
+
sql << "IF NOT EXISTS" if o.if_not_exists
|
21
|
+
sql << o.algorithm if o.algorithm
|
22
|
+
sql << index.type if index.type
|
23
|
+
sql << "#{quote_column_name(index.name)} ON #{quote_table_name(index.table)}"
|
24
|
+
sql << "USING #{index.using}" if supports_index_using? && index.using
|
25
|
+
sql << "(#{quoted_columns(index)})"
|
26
|
+
sql << "INCLUDE (#{quoted_index_includes(index.include)})" if supports_covering_index? && index.include
|
27
|
+
sql << "WHERE #{index.where}" if supports_partial_index? && index.where
|
28
|
+
|
29
|
+
sql.join(" ")
|
30
|
+
end
|
31
|
+
|
32
|
+
def quoted_index_includes(columns)
|
33
|
+
String === columns ? columns : quoted_columns_for_index(Array(columns), {})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiverecordCoveringIndex
|
4
|
+
module SchemaDumper
|
5
|
+
private
|
6
|
+
|
7
|
+
def index_parts(index)
|
8
|
+
index_parts = super
|
9
|
+
index_parts << "include: #{index.include.inspect}" if index.include.present?
|
10
|
+
index_parts
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
metadata
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: activerecord-covering-index
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tiger Watson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-08-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '5.2'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '7'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '5.2'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '7'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: pg
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.10'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '3.10'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: appraisal
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '2.4'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '2.4'
|
75
|
+
description: Extends ActiveRecord to support covering indexes in PostgreSQL using
|
76
|
+
the INCLUDE clause.
|
77
|
+
email:
|
78
|
+
- tigerwnz@gmail.com
|
79
|
+
executables: []
|
80
|
+
extensions: []
|
81
|
+
extra_rdoc_files: []
|
82
|
+
files:
|
83
|
+
- ".gitignore"
|
84
|
+
- ".rspec"
|
85
|
+
- Appraisals
|
86
|
+
- Gemfile
|
87
|
+
- README.md
|
88
|
+
- Rakefile
|
89
|
+
- activerecord-covering-index.gemspec
|
90
|
+
- bin/console
|
91
|
+
- bin/setup
|
92
|
+
- lib/activerecord-covering-index.rb
|
93
|
+
- lib/activerecord-covering-index/abstract_adapter.rb
|
94
|
+
- lib/activerecord-covering-index/index_definition.rb
|
95
|
+
- lib/activerecord-covering-index/postgresql_adapter.rb
|
96
|
+
- lib/activerecord-covering-index/schema_creation.rb
|
97
|
+
- lib/activerecord-covering-index/schema_dumper.rb
|
98
|
+
- lib/activerecord-covering-index/version.rb
|
99
|
+
homepage: https://gitlab.com/schlock/activerecord-covering-index
|
100
|
+
licenses:
|
101
|
+
- MIT
|
102
|
+
metadata:
|
103
|
+
homepage_uri: https://gitlab.com/schlock/activerecord-covering-index
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '0'
|
113
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
requirements: []
|
119
|
+
rubygems_version: 3.1.4
|
120
|
+
signing_key:
|
121
|
+
specification_version: 4
|
122
|
+
summary: Create covering indexes in Rails with PostgreSQL
|
123
|
+
test_files: []
|