pgrel 0.1.1 → 0.1.2
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 +4 -4
- data/.travis.yml +1 -1
- data/README.md +5 -5
- data/gemfiles/rails5.gemfile +1 -0
- data/lib/pgrel/active_record/store_chain.rb +67 -24
- data/lib/pgrel/active_record/store_chain/hstore_chain.rb +0 -29
- data/lib/pgrel/active_record/store_chain/jsonb_chain.rb +1 -29
- data/lib/pgrel/version.rb +1 -1
- data/spec/pgrel/hstore_spec.rb +2 -1
- metadata +3 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 5a4870c7384f1433c46da0d1515243c3753e928d
         | 
| 4 | 
            +
              data.tar.gz: 446c7ccfd60abe33f7422cd2252dfa8d9bb47281
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 39575efbbe02500b4a3534e4a188b845305911e96fbd33f01a68a7eaad0fa4185261727da4a7e9bf498f506af5ee63de9a147024f5b16b283a91776ee568346c
         | 
| 7 | 
            +
              data.tar.gz: 63c370d875d0442c14a680d846cf34c7ccdb2f03ca25d061fbe6eae2772cf5bc5b2b9dcf16febb0543ffee61ec3c00c8cfd076c0e7dcea861925d2217790a05c
         | 
    
        data/.travis.yml
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            [](https://travis-ci.org/palkan/pgrel)
         | 
| 1 | 
            +
            [](https://rubygems.org/gems/pgrel) [](https://travis-ci.org/palkan/pgrel)
         | 
| 2 2 |  | 
| 3 3 | 
             
            ## Pgrel
         | 
| 4 4 |  | 
| @@ -25,10 +25,10 @@ Query by key value: | |
| 25 25 |  | 
| 26 26 | 
             
            ```ruby
         | 
| 27 27 | 
             
            Hstore.where.store(:tags, a: 1, b: 2)
         | 
| 28 | 
            -
            #=> select * from hstores where tags | 
| 28 | 
            +
            #=> select * from hstores where tags @> '"a"=>"1","b"=>"2"'
         | 
| 29 29 |  | 
| 30 30 | 
             
            Hstore.where.store(:tags, a: [1, 2])
         | 
| 31 | 
            -
            #=> select * from hstores where tags | 
| 31 | 
            +
            #=> select * from hstores where (tags @> '"a"=>"1"' or tags @> '"a"=>"2"')
         | 
| 32 32 | 
             
            ```
         | 
| 33 33 |  | 
| 34 34 | 
             
            Keys existence:
         | 
| @@ -61,14 +61,14 @@ Hstore.where.store(:tags).contained(a: 1, b: 2) | |
| 61 61 |  | 
| 62 62 | 
             
            All queries for Hstore also available for JSONB.
         | 
| 63 63 |  | 
| 64 | 
            -
            **NOTE**. Querying by array value always resolves to ` | 
| 64 | 
            +
            **NOTE**. Querying by array value always resolves to `(... or ...)` statement. 
         | 
| 65 65 | 
             
            Thus it's impossible to query json array value, e.g.:
         | 
| 66 66 |  | 
| 67 67 | 
             
            ```ruby
         | 
| 68 68 | 
             
            Model.create!(tags: {main: ['a', 'b']})
         | 
| 69 69 |  | 
| 70 70 | 
             
            Model.where.store(:tags, main: ['a', 'b']).empty? == true
         | 
| 71 | 
            -
            #=> select * from models where  tags | 
| 71 | 
            +
            #=> select * from models where  (tags @> '{\"main\":\"a\"}' or tags @> '{\"main\":\"b\"}')
         | 
| 72 72 | 
             
            ```
         | 
| 73 73 |  | 
| 74 74 | 
             
            Path query:
         | 
    
        data/gemfiles/rails5.gemfile
    CHANGED
    
    
| @@ -22,7 +22,7 @@ module ActiveRecord | |
| 22 22 | 
             
                  #   data = {a: 1}
         | 
| 23 23 | 
             
                  #   Model.store(:store).contains(data).all #=> [Model(name: 'first', ...)]
         | 
| 24 24 | 
             
                  def contains(opts)
         | 
| 25 | 
            -
                    update_scope  | 
| 25 | 
            +
                    update_scope contains_clause(opts)
         | 
| 26 26 | 
             
                  end
         | 
| 27 27 |  | 
| 28 28 | 
             
                  # Whether the store is contained within provided store
         | 
| @@ -52,6 +52,37 @@ module ActiveRecord | |
| 52 52 | 
             
                    self
         | 
| 53 53 | 
             
                  end
         | 
| 54 54 |  | 
| 55 | 
            +
                  # Query by store values.
         | 
| 56 | 
            +
                  # Supports array values.
         | 
| 57 | 
            +
                  #
         | 
| 58 | 
            +
                  # NOTE: This method uses "@>" (contains) operator with logic (AND/OR)
         | 
| 59 | 
            +
                  # and not uses "->" (value-by-key). The use of "contains" operator allows us to
         | 
| 60 | 
            +
                  # use GIN index effectively.
         | 
| 61 | 
            +
                  #
         | 
| 62 | 
            +
                  # Example
         | 
| 63 | 
            +
                  #   Model.create!(name: 'first', store: {b: 1, c: 2})
         | 
| 64 | 
            +
                  #   Model.create!(name: 'second', store: {b: 2, c: 3})
         | 
| 65 | 
            +
                  #
         | 
| 66 | 
            +
                  #   Model.store(:store, c: 2).all #=> [Model(name: 'first', ...)]
         | 
| 67 | 
            +
                  #   #=> (SQL) select * from ... where store @> '"c"=>"2"'::hstore
         | 
| 68 | 
            +
                  #
         | 
| 69 | 
            +
                  #   Model.store(:store, b: [1, 2]).size #=> 2
         | 
| 70 | 
            +
                  #   #=> (SQL) select * from ... where (store @> '"c"=>"1"'::hstore) or
         | 
| 71 | 
            +
                  #                                     (store @> '"c"=>"2"'::hstore)
         | 
| 72 | 
            +
                  def where(opts)
         | 
| 73 | 
            +
                    update_scope(
         | 
| 74 | 
            +
                      opts.map do |k, v|
         | 
| 75 | 
            +
                        case v
         | 
| 76 | 
            +
                        when Array
         | 
| 77 | 
            +
                          "(#{build_or_contains(k, v)})"
         | 
| 78 | 
            +
                        else
         | 
| 79 | 
            +
                          contains_clause(k => v)
         | 
| 80 | 
            +
                        end
         | 
| 81 | 
            +
                      end.join(' and ')
         | 
| 82 | 
            +
                    )
         | 
| 83 | 
            +
                    @scope
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
             | 
| 55 86 | 
             
                  if RAILS_5
         | 
| 56 87 | 
             
                    protected
         | 
| 57 88 |  | 
| @@ -66,20 +97,6 @@ module ActiveRecord | |
| 66 97 | 
             
                        @scope.table.type_cast_for_database(@store_name, value)
         | 
| 67 98 | 
             
                      )
         | 
| 68 99 | 
             
                    end
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                    def where_with_prefix(prefix, opts)
         | 
| 71 | 
            -
                      where_clause = @scope.send(:where_clause_factory).build(opts, {})
         | 
| 72 | 
            -
                      predicates = where_clause.ast.children.map do |rel|
         | 
| 73 | 
            -
                        rel.left = to_sql_literal(prefix, rel.left)
         | 
| 74 | 
            -
                        rel
         | 
| 75 | 
            -
                      end
         | 
| 76 | 
            -
                      where_clause = ActiveRecord::Relation::WhereClause.new(
         | 
| 77 | 
            -
                        predicates,
         | 
| 78 | 
            -
                        where_clause.binds
         | 
| 79 | 
            -
                      )
         | 
| 80 | 
            -
                      @scope.where_clause += @inverted ? where_clause.invert : where_clause
         | 
| 81 | 
            -
                      @scope
         | 
| 82 | 
            -
                    end
         | 
| 83 100 | 
             
                  else
         | 
| 84 101 | 
             
                    protected
         | 
| 85 102 |  | 
| @@ -98,15 +115,6 @@ module ActiveRecord | |
| 98 115 | 
             
                      )
         | 
| 99 116 | 
             
                    end
         | 
| 100 117 |  | 
| 101 | 
            -
                    def where_with_prefix(prefix, opts)
         | 
| 102 | 
            -
                      where_value = @scope.send(:build_where, opts).map do |rel|
         | 
| 103 | 
            -
                        rel.left = to_sql_literal(prefix, rel.left)
         | 
| 104 | 
            -
                        @inverted ? invert_arel(rel) : rel
         | 
| 105 | 
            -
                      end
         | 
| 106 | 
            -
                      @scope.where_values += where_value
         | 
| 107 | 
            -
                      @scope
         | 
| 108 | 
            -
                    end
         | 
| 109 | 
            -
             | 
| 110 118 | 
             
                    def invert_arel(rel)
         | 
| 111 119 | 
             
                      case rel
         | 
| 112 120 | 
             
                      when Arel::Nodes::In
         | 
| @@ -120,6 +128,16 @@ module ActiveRecord | |
| 120 128 | 
             
                      end
         | 
| 121 129 | 
             
                    end
         | 
| 122 130 | 
             
                  end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                  private
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                  def contains_clause(opts)
         | 
| 135 | 
            +
                    "#{@store_name} @> #{type_cast(opts)}"
         | 
| 136 | 
            +
                  end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                  def build_or_contains(k, vals)
         | 
| 139 | 
            +
                    vals.map { |v| contains_clause(k => v) }.join(' or ')
         | 
| 140 | 
            +
                  end
         | 
| 123 141 | 
             
                end
         | 
| 124 142 |  | 
| 125 143 | 
             
                # Base class for key-value types of stores (hstore, jsonb)
         | 
| @@ -171,6 +189,31 @@ module ActiveRecord | |
| 171 189 | 
             
                      "#{prefix}'#{node.name}'"
         | 
| 172 190 | 
             
                    )
         | 
| 173 191 | 
             
                  end
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                  if RAILS_5
         | 
| 194 | 
            +
                    def where_with_prefix(prefix, opts)
         | 
| 195 | 
            +
                      where_clause = @scope.send(:where_clause_factory).build(opts, {})
         | 
| 196 | 
            +
                      predicates = where_clause.ast.children.map do |rel|
         | 
| 197 | 
            +
                        rel.left = to_sql_literal(prefix, rel.left)
         | 
| 198 | 
            +
                        rel
         | 
| 199 | 
            +
                      end
         | 
| 200 | 
            +
                      where_clause = ActiveRecord::Relation::WhereClause.new(
         | 
| 201 | 
            +
                        predicates,
         | 
| 202 | 
            +
                        where_clause.binds
         | 
| 203 | 
            +
                      )
         | 
| 204 | 
            +
                      @scope.where_clause += @inverted ? where_clause.invert : where_clause
         | 
| 205 | 
            +
                      @scope
         | 
| 206 | 
            +
                    end
         | 
| 207 | 
            +
                  else
         | 
| 208 | 
            +
                    def where_with_prefix(prefix, opts)
         | 
| 209 | 
            +
                      where_value = @scope.send(:build_where, opts).map do |rel|
         | 
| 210 | 
            +
                        rel.left = to_sql_literal(prefix, rel.left)
         | 
| 211 | 
            +
                        @inverted ? invert_arel(rel) : rel
         | 
| 212 | 
            +
                      end
         | 
| 213 | 
            +
                      @scope.where_values += where_value
         | 
| 214 | 
            +
                      @scope
         | 
| 215 | 
            +
                    end
         | 
| 216 | 
            +
                  end
         | 
| 174 217 | 
             
                end
         | 
| 175 218 | 
             
              end
         | 
| 176 219 | 
             
            end
         | 
| @@ -2,35 +2,6 @@ module ActiveRecord | |
| 2 2 | 
             
              module QueryMethods
         | 
| 3 3 | 
             
                # Store chain for hstore columns.
         | 
| 4 4 | 
             
                class HstoreChain < KeyStoreChain
         | 
| 5 | 
            -
                  # Query by store values.
         | 
| 6 | 
            -
                  #
         | 
| 7 | 
            -
                  # Supports array values.
         | 
| 8 | 
            -
                  #
         | 
| 9 | 
            -
                  # Example
         | 
| 10 | 
            -
                  #   Model.create!(name: 'first', store: {b: 1, c: 2})
         | 
| 11 | 
            -
                  #   Model.create!(name: 'second', store: {b: 2, c: 3})
         | 
| 12 | 
            -
                  #
         | 
| 13 | 
            -
                  #   Model.store(:store, c: 2).all #=> [Model(name: 'first', ...)]
         | 
| 14 | 
            -
                  #   Model.store(:store, b: [1, 2]).size #=> 2
         | 
| 15 | 
            -
                  def where(opts)
         | 
| 16 | 
            -
                    opts = stringify(opts)
         | 
| 17 | 
            -
                    where_with_prefix "#{@store_name}->", opts
         | 
| 18 | 
            -
                  end
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                  private
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                  def stringify(val)
         | 
| 23 | 
            -
                    case val
         | 
| 24 | 
            -
                    when String
         | 
| 25 | 
            -
                      val
         | 
| 26 | 
            -
                    when Array
         | 
| 27 | 
            -
                      val.map { |v| stringify(v) }
         | 
| 28 | 
            -
                    when Hash
         | 
| 29 | 
            -
                      Hash[val.map { |k, v| [stringify(k), stringify(v)] }]
         | 
| 30 | 
            -
                    else
         | 
| 31 | 
            -
                      val.to_s
         | 
| 32 | 
            -
                    end
         | 
| 33 | 
            -
                  end
         | 
| 34 5 | 
             
                end
         | 
| 35 6 | 
             
              end
         | 
| 36 7 | 
             
            end
         | 
| @@ -2,23 +2,7 @@ module ActiveRecord | |
| 2 2 | 
             
              module QueryMethods
         | 
| 3 3 | 
             
                # Store chain for jsonb columns.
         | 
| 4 4 | 
             
                class JsonbChain < KeyStoreChain
         | 
| 5 | 
            -
                  # Query by  | 
| 6 | 
            -
                  # Supports array values (convert to IN statement).
         | 
| 7 | 
            -
                  #
         | 
| 8 | 
            -
                  # Example
         | 
| 9 | 
            -
                  #   Model.create!(name: 'first', store: {b: 1, c: 2})
         | 
| 10 | 
            -
                  #   Model.create!(name: 'second', store: {b: 2, c: 3})
         | 
| 11 | 
            -
                  #
         | 
| 12 | 
            -
                  #   Model.store(:store, c: 2).all #=> [Model(name: 'first', ...)]
         | 
| 13 | 
            -
                  #   Model.store(:store, b: [1, 2]).size #=> 2
         | 
| 14 | 
            -
                  def where(opts)
         | 
| 15 | 
            -
                    opts = flatten_json(opts)
         | 
| 16 | 
            -
                    where_with_prefix "#{@store_name}->", opts
         | 
| 17 | 
            -
                  end
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                  # Query by quality in path.
         | 
| 20 | 
            -
                  #
         | 
| 21 | 
            -
                  # Path can be set as object or as args.
         | 
| 5 | 
            +
                  # Query by value in path.
         | 
| 22 6 | 
             
                  #
         | 
| 23 7 | 
             
                  # Example:
         | 
| 24 8 | 
             
                  #   Model.create!(name: 'first', store: {b: 1, c: { d: 3 } })
         | 
| @@ -49,18 +33,6 @@ module ActiveRecord | |
| 49 33 |  | 
| 50 34 | 
             
                  private
         | 
| 51 35 |  | 
| 52 | 
            -
                  def flatten_json(val)
         | 
| 53 | 
            -
                    Hash[
         | 
| 54 | 
            -
                      val.map do |k, v|
         | 
| 55 | 
            -
                        if v.is_a?(Array)
         | 
| 56 | 
            -
                          [k, v.map { |i| ::ActiveSupport::JSON.encode(i) }]
         | 
| 57 | 
            -
                        else
         | 
| 58 | 
            -
                          [k, ::ActiveSupport::JSON.encode(v)]
         | 
| 59 | 
            -
                        end
         | 
| 60 | 
            -
                      end
         | 
| 61 | 
            -
                    ]
         | 
| 62 | 
            -
                  end
         | 
| 63 | 
            -
             | 
| 64 36 | 
             
                  def flatten_hash(hash)
         | 
| 65 37 | 
             
                    case hash
         | 
| 66 38 | 
             
                    when Hash
         | 
    
        data/lib/pgrel/version.rb
    CHANGED
    
    
    
        data/spec/pgrel/hstore_spec.rb
    CHANGED
    
    | @@ -116,7 +116,8 @@ describe Hstore do | |
| 116 116 |  | 
| 117 117 | 
             
              context '#not' do
         | 
| 118 118 | 
             
                it '#where' do
         | 
| 119 | 
            -
                  expect(Hstore.where.store(:tags).not(a:  | 
| 119 | 
            +
                  expect(Hstore.where.store(:tags).not(a: 2).size).to eq 4
         | 
| 120 | 
            +
                  expect(Hstore.where.store(:tags).not(a: 1, g: 'c').size).to eq 6
         | 
| 120 121 | 
             
                end
         | 
| 121 122 |  | 
| 122 123 | 
             
                it '#any' do
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: pgrel
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.1. | 
| 4 | 
            +
              version: 0.1.2
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - palkan
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2015- | 
| 11 | 
            +
            date: 2015-10-14 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: activerecord
         | 
| @@ -148,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 148 148 | 
             
                  version: '0'
         | 
| 149 149 | 
             
            requirements: []
         | 
| 150 150 | 
             
            rubyforge_project: 
         | 
| 151 | 
            -
            rubygems_version: 2. | 
| 151 | 
            +
            rubygems_version: 2.4.5
         | 
| 152 152 | 
             
            signing_key: 
         | 
| 153 153 | 
             
            specification_version: 4
         | 
| 154 154 | 
             
            summary: ActiveRecord extension for querying hstore and jsonb.
         |