relix 2.1.0 → 2.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 +8 -8
- data/HISTORY.md +4 -0
- data/README.md +25 -0
- data/lib/relix/index_set.rb +72 -6
- data/lib/relix/indexes/multi.rb +9 -0
- data/lib/relix/indexes/ordered.rb +4 -0
- data/lib/relix/indexes/unique.rb +5 -0
- data/lib/relix/version.rb +1 -1
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,15 +1,15 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            !binary "U0hBMQ==":
         | 
| 3 3 | 
             
              metadata.gz: !binary |-
         | 
| 4 | 
            -
                 | 
| 4 | 
            +
                OGM4Mzc2ZGI4YjZmNTBlYjczMjM4MjA0ZDE3YzM4ZGQ2ZmU1NTg0ZA==
         | 
| 5 5 | 
             
              data.tar.gz: !binary |-
         | 
| 6 | 
            -
                 | 
| 6 | 
            +
                MWRkMDg2ZTdlOWVmMmY2NWFkNDc1OGRiN2QwNThjZDc5NzQ2MzA2Zg==
         | 
| 7 7 | 
             
            !binary "U0hBNTEy":
         | 
| 8 8 | 
             
              metadata.gz: !binary |-
         | 
| 9 | 
            -
                 | 
| 10 | 
            -
                 | 
| 11 | 
            -
                 | 
| 9 | 
            +
                MTU3YjZmNjYxOTEzODAxN2EyM2M3Nzk5ZWVhYTg5M2IyMGFkZDE0ZGIzMmYz
         | 
| 10 | 
            +
                NjQyYmQ2MTc3NGU4Zjc1ZmU5ZTE0Yjc5NTNkOGFmN2I0NmYzZGZiZDkxYjYy
         | 
| 11 | 
            +
                ZjBjYTY4MDlhYmQ5OTVlM2FiZWQzZWJhMTkyYTBmZTE3NjJiNzM=
         | 
| 12 12 | 
             
              data.tar.gz: !binary |-
         | 
| 13 | 
            -
                 | 
| 14 | 
            -
                 | 
| 15 | 
            -
                 | 
| 13 | 
            +
                NTdkZjBlMTE2YThjNTkyOTRkMWI4YWQ0ZGI4NTM2ZGY5ZDFlOTVhYTc3OWYw
         | 
| 14 | 
            +
                MmQ0MmNlMjExZTYyOGU4YjY0ZmJjNGQyNWI1YjMwYmI5N2RlNTI1MDcxN2Fl
         | 
| 15 | 
            +
                NTEzY2I4NjljZmU1ZTA3ZDhkYzQ2YjZlODcyNTgzYWZlNjFjNjE=
         | 
    
        data/HISTORY.md
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -296,3 +296,28 @@ Keys take up space, and especially since Redis holds the keyset in memory it can | |
| 296 296 | 
             
            ### Legacy
         | 
| 297 297 |  | 
| 298 298 | 
             
            This (eventually to be deprecated and removed) strategy exactly mirrors the keying supported by Relix when first released.
         | 
| 299 | 
            +
             | 
| 300 | 
            +
             | 
| 301 | 
            +
            ## Maintenance
         | 
| 302 | 
            +
             | 
| 303 | 
            +
            ### Index removal
         | 
| 304 | 
            +
             | 
| 305 | 
            +
            Sometimes an index is no longer needed, or is being moved or renamed, and you'll want to clean up the old index data including both the index itself as well as the current values that are tracked for that index.
         | 
| 306 | 
            +
             | 
| 307 | 
            +
            To remove an index, first change its declaration like so:
         | 
| 308 | 
            +
             | 
| 309 | 
            +
                class Transaction
         | 
| 310 | 
            +
                  relix do
         | 
| 311 | 
            +
                    obsolete{:multi, :account_key, order: :created_at}
         | 
| 312 | 
            +
                  end
         | 
| 313 | 
            +
                end
         | 
| 314 | 
            +
             | 
| 315 | 
            +
            This just wraps the original index declaration in an `obsolete` block. Doing this makes it so that the index is no longer updated (though it will still deindex), and also marks the index for removal within Relix.
         | 
| 316 | 
            +
             | 
| 317 | 
            +
            Second, run `destroy_index` on the index:
         | 
| 318 | 
            +
             | 
| 319 | 
            +
                Transaction.relix.destroy_index(:account_key)
         | 
| 320 | 
            +
             | 
| 321 | 
            +
            This will remove all related data from Redis. Note that `destroy_index` is idempotent, so while it's not recommended you run it multiple times (it iterates through the whole primary key space), it won't hurt anything if you do.
         | 
| 322 | 
            +
             | 
| 323 | 
            +
            And finally: just delete the whole `obsolete` line from your relix declaration. The index is now dead - long live the index!
         | 
    
        data/lib/relix/index_set.rb
    CHANGED
    
    | @@ -6,6 +6,7 @@ module Relix | |
| 6 6 | 
             
                  @klass = klass
         | 
| 7 7 | 
             
                  @redis_source = redis_source
         | 
| 8 8 | 
             
                  @indexes = Hash.new
         | 
| 9 | 
            +
                  @obsolete_indexes = Hash.new
         | 
| 9 10 | 
             
                  @keyer = Keyer.default_for(@klass) unless parent
         | 
| 10 11 | 
             
                end
         | 
| 11 12 |  | 
| @@ -46,8 +47,63 @@ module Relix | |
| 46 47 | 
             
                end
         | 
| 47 48 |  | 
| 48 49 | 
             
                def add_index(index_type, name, options={})
         | 
| 49 | 
            -
                   | 
| 50 | 
            -
             | 
| 50 | 
            +
                  raise Relix::InvalidIndexError.new("Index #{name} is already declared as obsolete.") if @obsolete_indexes[name.to_s]
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  @indexes[name.to_s] = create_index(self, index_type, name, options)
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                class Obsolater
         | 
| 56 | 
            +
                  def initialize(index_set)
         | 
| 57 | 
            +
                    @index_set = index_set
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  def method_missing(m, *args)
         | 
| 61 | 
            +
                    if Relix.index_types.keys.include?(m.to_sym)
         | 
| 62 | 
            +
                      @index_set.add_obsolete_index(m, *args)
         | 
| 63 | 
            +
                    else
         | 
| 64 | 
            +
                      raise ArgumentError.new("Unknown index type #{m}.")
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def obsolete(&block)
         | 
| 70 | 
            +
                  raise ArgumentError.new("No block passed.") unless block_given?
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  Obsolater.new(self).instance_eval(&block)
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                def add_obsolete_index(index_type, name, options={})
         | 
| 76 | 
            +
                  raise Relix::InvalidIndexError.new("Primary key indexes cannot be obsoleted.") if(index_type == :primary_key)
         | 
| 77 | 
            +
                  raise Relix::InvalidIndexError.new("Index #{name} is already declared as non-obsolete.") if @indexes[name.to_s]
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  @obsolete_indexes[name.to_s] = create_index(self, index_type, name, options)
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                def destroy_index(name)
         | 
| 83 | 
            +
                  name = name.to_s
         | 
| 84 | 
            +
                  index = @obsolete_indexes[name]
         | 
| 85 | 
            +
                  raise MissingIndexError.new("No obsolete index found for #{name}.") unless index
         | 
| 86 | 
            +
                  raise InvalidIndexError.new("Indexes built on immutable attributes cannot be destroyed.") if index.attribute_immutable?
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  lookup.each do |pk|
         | 
| 89 | 
            +
                    handle_concurrent_modifications(pk) do
         | 
| 90 | 
            +
                      current_values_name = current_values_name(pk)
         | 
| 91 | 
            +
                      redis.watch current_values_name
         | 
| 92 | 
            +
                      current_values = redis.hgetall(current_values_name)
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                      old_value = current_values[name]
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                      ((watch = index.watch(old_value)) && !watch.empty? && redis.watch(*watch))
         | 
| 97 | 
            +
                      ops = []
         | 
| 98 | 
            +
                      ops << proc{ index.destroy(redis, pk, old_value) } if index.respond_to?(:destroy)
         | 
| 99 | 
            +
                      ops << proc{ redis.hdel current_values_name, name }
         | 
| 100 | 
            +
                      ops
         | 
| 101 | 
            +
                    end
         | 
| 102 | 
            +
                  end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                  if index.respond_to?(:destroy_all)
         | 
| 105 | 
            +
                    index.destroy_all(redis)
         | 
| 106 | 
            +
                  end
         | 
| 51 107 | 
             
                end
         | 
| 52 108 |  | 
| 53 109 | 
             
                def indexes
         | 
| @@ -114,7 +170,7 @@ module Relix | |
| 114 170 | 
             
                    redis.watch current_values_name
         | 
| 115 171 | 
             
                    current_values = redis.hgetall(current_values_name)
         | 
| 116 172 |  | 
| 117 | 
            -
                    full_index_list.map do |name, index|
         | 
| 173 | 
            +
                    full_index_list(:including_obsolete).map do |name, index|
         | 
| 118 174 | 
             
                      old_value = if index.attribute_immutable?
         | 
| 119 175 | 
             
                        index.read_normalized(object)
         | 
| 120 176 | 
             
                      else
         | 
| @@ -133,7 +189,7 @@ module Relix | |
| 133 189 | 
             
                    redis.watch current_values_name
         | 
| 134 190 | 
             
                    current_values = redis.hgetall(current_values_name)
         | 
| 135 191 |  | 
| 136 | 
            -
                    full_index_list.map do |name, index|
         | 
| 192 | 
            +
                    full_index_list(:including_obsolete).map do |name, index|
         | 
| 137 193 | 
             
                      old_value = current_values[name]
         | 
| 138 194 |  | 
| 139 195 | 
             
                      ((watch = index.watch(old_value)) && !watch.empty? && redis.watch(*watch))
         | 
| @@ -164,12 +220,21 @@ module Relix | |
| 164 220 |  | 
| 165 221 | 
             
                protected
         | 
| 166 222 |  | 
| 167 | 
            -
                def full_index_list
         | 
| 168 | 
            -
                  (parent ? parent.full_index_list.merge(@indexes) : @indexes)
         | 
| 223 | 
            +
                def full_index_list(including_obsolete=false)
         | 
| 224 | 
            +
                  list = (parent ? parent.full_index_list.merge(@indexes) : @indexes)
         | 
| 225 | 
            +
                  if including_obsolete
         | 
| 226 | 
            +
                    list = @obsolete_indexes.merge(list)
         | 
| 227 | 
            +
                  end
         | 
| 228 | 
            +
                  list
         | 
| 169 229 | 
             
                end
         | 
| 170 230 |  | 
| 171 231 | 
             
                private
         | 
| 172 232 |  | 
| 233 | 
            +
                def create_index(index_set, index_type, name, options)
         | 
| 234 | 
            +
                  accessor = (options.delete(:on) || name)
         | 
| 235 | 
            +
                  Relix.index_types[index_type].new(index_set, name, accessor, options)
         | 
| 236 | 
            +
                end
         | 
| 237 | 
            +
             | 
| 173 238 | 
             
                def handle_concurrent_modifications(primary_key)
         | 
| 174 239 | 
             
                  retries = 5
         | 
| 175 240 | 
             
                  loop do
         | 
| @@ -203,4 +268,5 @@ module Relix | |
| 203 268 | 
             
              class MissingPrimaryKeyError < Relix::Error; end
         | 
| 204 269 | 
             
              class RedisIndexingError < Relix::Error; end
         | 
| 205 270 | 
             
              class ExceededRetriesForConcurrentWritesError < Relix::Error; end
         | 
| 271 | 
            +
              class InvalidIndexError < Relix::Error; end
         | 
| 206 272 | 
             
            end
         | 
    
        data/lib/relix/indexes/multi.rb
    CHANGED
    
    | @@ -20,6 +20,11 @@ module Relix | |
| 20 20 | 
             
                  deindex_value(r, old_value) if index_values?
         | 
| 21 21 | 
             
                end
         | 
| 22 22 |  | 
| 23 | 
            +
                def destroy(r, pk, old_value)
         | 
| 24 | 
            +
                  r.del(key_for(old_value))
         | 
| 25 | 
            +
                  r.destroy_values(r) if index_values?
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 23 28 | 
             
                def eq(r, value, options={})
         | 
| 24 29 | 
             
                  r.zrange(key_for(value), *range_from_options(r, options, value))
         | 
| 25 30 | 
             
                end
         | 
| @@ -59,6 +64,10 @@ module Relix | |
| 59 64 | 
             
                    return "OK"
         | 
| 60 65 | 
             
                  ), [values_key, key_for(old_value)], [old_value]
         | 
| 61 66 | 
             
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                def destroy_value(r)
         | 
| 69 | 
            +
                  r.del(values_key)
         | 
| 70 | 
            +
                end
         | 
| 62 71 | 
             
              end
         | 
| 63 72 | 
             
              register_index MultiIndex
         | 
| 64 73 | 
             
            end
         | 
    
        data/lib/relix/indexes/unique.rb
    CHANGED
    
    
    
        data/lib/relix/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: relix
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 2. | 
| 4 | 
            +
              version: 2.2.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Nathaniel Talbott
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2013- | 
| 11 | 
            +
            date: 2013-05-08 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              prerelease: false
         |