README.md in kredis-1.5.0 vs README.md in kredis-1.6.0

- old
+ new

@@ -19,15 +19,15 @@ integer = Kredis.integer "myinteger" integer.value = 5 # => SET myinteger "5" 5 == integer.value # => GET myinteger decimal = Kredis.decimal "mydecimal" # accuracy! -decimal.value = "%.47f" % (1.0/10) # => SET mydecimal "0.10000000000000000555111512312578270211815834045" +decimal.value = "%.47f" % (1.0 / 10) # => SET mydecimal "0.10000000000000000555111512312578270211815834045" BigDecimal("0.10000000000000000555111512312578270211815834045e0") == decimal.value # => GET mydecimal float = Kredis.float "myfloat" # speed! -float.value = 1.0/10 # => SET myfloat "0.1" +float.value = 1.0 / 10 # => SET myfloat "0.1" 0.1 == float.value # => GET myfloat boolean = Kredis.boolean "myboolean" boolean.value = true # => SET myboolean "t" true == boolean.value # => GET myboolean @@ -47,14 +47,14 @@ ```ruby list = Kredis.list "mylist" list << "hello world!" # => RPUSH mylist "hello world!" [ "hello world!" ] == list.elements # => LRANGE mylist 0, -1 -integer_list = Kredis.list "myintegerlist", typed: :integer -integer_list.append([ 1, 2, 3 ]) # => RPUSH myintegerlist "1" "2" "3" -integer_list << 4 # => RPUSH myintegerlist "4" -[ 1, 2, 3, 4 ] == integer_list.elements # => LRANGE myintegerlist 0 -1 +integer_list = Kredis.list "myintegerlist", typed: :integer, default: [ 1, 2, 3 ] # => EXISTS? myintegerlist, RPUSH myintegerlist "1" "2" "3" +integer_list.append([ 4, 5, 6 ]) # => RPUSH myintegerlist "4" "5" "6" +integer_list << 7 # => RPUSH myintegerlist "7" +[ 1, 2, 3, 4, 5, 6, 7 ] == integer_list.elements # => LRANGE myintegerlist 0 -1 unique_list = Kredis.unique_list "myuniquelist" unique_list.append(%w[ 2 3 4 ]) # => LREM myuniquelist 0, "2" + LREM myuniquelist 0, "3" + LREM myuniquelist 0, "4" + RPUSH myuniquelist "2", "3", "4" unique_list.prepend(%w[ 1 2 3 4 ]) # => LREM myuniquelist 0, "1" + LREM myuniquelist 0, "2" + LREM myuniquelist 0, "3" + LREM myuniquelist 0, "4" + LPUSH myuniquelist "1", "2", "3", "4" unique_list.append([]) @@ -161,20 +161,12 @@ true == flag.marked? #=> EXISTS myflag sleep 0.6.seconds false == flag.marked? #=> EXISTS myflag ``` -And using structures on a different than the default `shared` redis instance, relying on `config/redis/secondary.yml`: +### Models -```ruby -one_string = Kredis.string "mystring" -two_string = Kredis.string "mystring", config: :secondary - -one_string.value = "just on shared" -two_string.value != one_string.value -``` - You can use all these structures in models: ```ruby class Person < ApplicationRecord kredis_list :names @@ -195,10 +187,33 @@ true == person.morning.bright? # => GET people:5:morning person.morning.value = "blue" # => SET people:5:morning true == person.morning.blue? # => GET people:5:morning ``` +### Default values + +You can set a default value for all types. For example: + +```ruby +list = Kredis.list "favorite_colors", default: [ "red", "green", "blue" ] + +# or, in a model +class Person < ApplicationRecord + kredis_string :name, default: "Unknown" + kredis_list :favorite_colors, default: [ "red", "green", "blue" ] +end +``` + +There's a performance overhead to consider though. When you first read or write an attribute in a model, Kredis will +check if the underlying Redis key exists, while watching for concurrent changes, and if it does not, +write the specified default value. + +This means that using default values in a typical Rails app additional Redis calls (WATCH, EXISTS, UNWATCH) will be +executed for each Kredis attribute with a default value read or written during a request. + +### Callbacks + You can also define `after_change` callbacks that trigger on mutations: ```ruby class Person < ApplicationRecord kredis_list :names, after_change: ->(p) { } @@ -207,10 +222,22 @@ def skillset_changed end end ``` +### Multiple Redis servers + +And using structures on a different than the default `shared` redis instance, relying on `config/redis/secondary.yml`: + +```ruby +one_string = Kredis.string "mystring" +two_string = Kredis.string "mystring", config: :secondary + +one_string.value = "just on shared" +two_string.value != one_string.value +``` + ## Installation 1. Run `./bin/bundle add kredis` 2. Run `./bin/rails kredis:install` to add a default configuration at [`config/redis/shared.yml`](lib/install/shared.yml) @@ -226,18 +253,18 @@ If you need to connect to Redis with SSL, the recommended approach is to set your Redis instance manually by adding an entry to the `Kredis::Connections.connections` hash. Below an example showing how to connect to Redis using Client Authentication: ```ruby Kredis::Connections.connections[:shared] = Redis.new( - url: ENV['REDIS_URL'], + url: ENV["REDIS_URL"], ssl_params: { cert_store: OpenSSL::X509::Store.new.tap { |store| - store.add_file(Rails.root.join('config', 'ca_cert.pem').to_s) + store.add_file(Rails.root.join("config", "ca_cert.pem").to_s) }, cert: OpenSSL::X509::Certificate.new(File.read( - Rails.root.join('config', 'client.crt') + Rails.root.join("config", "client.crt") )), key: OpenSSL::PKey::RSA.new( Rails.application.credentials.redis[:client_key] ), @@ -256,9 +283,32 @@ ```ruby config.kredis.connector = ->(config) { SomeRedisProxy.new(config) } ``` By default Kredis will use `Redis.new(config)`. + +## Development + +A development console is available by running `bin/console`. + +From there, you can experiment with Kredis. e.g. + +```erb +>> str = Kredis.string "mystring" + Kredis (0.1ms) Connected to shared +=> +#<Kredis::Types::Scalar:0x0000000134c7d938 +... +>> str.value = "hello, world" + Kredis Proxy (2.4ms) SET mystring ["hello, world"] +=> "hello, world" +>> str.value +``` + +Run tests with `bin/test`. + +[`debug`](https://github.com/ruby/debug) can be used in the development console and in the test suite by inserting a +breakpoint, e.g. `debugger`. ## License Kredis is released under the [MIT License](https://opensource.org/licenses/MIT).