Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introducing Hyperion

Myles Megyesi
September 19, 2012

Introducing Hyperion

Myles Megyesi

September 19, 2012
Tweet

More Decks by Myles Megyesi

Other Decks in Technology

Transcript

  1. What is Hyperion? • A persistence library for Ruby and

    Clojure that supports many different databases • An idea - choosing your database is a decision that can be deferred
  2. Hosemonster • Months later - persistence decided • In the

    app - implement another datastore • Build a service with Gaeshi
  3. Hosemonster • We had 3 datastore implementations ◦ our API

    was similar, but worse, than the GAE datastore API ◦ merge the APIs ◦ extract into reusable library - Hyperion
  4. Hosemonster • Conversion to web-app complete ◦ Deploy to staging

    (GAE) - boom! ◦ PDF generation doesn't work • Move off of GAE ◦ Moved to Heroku ◦ Write migrations, fix bugs in Hyperion ◦ Switched databases in one weekend
  5. Hosemonster • Fast-forward 9 months ◦ production deployment ◦ deploy

    manually to AWS • Switch to MongoDB ◦ Application code did not have to change ▪ only reconfigure Hyperion
  6. Hosemonster • Started with a simple idea ◦ defer the

    persistence decision ◦ once the decision is made - keep the abstraction and make it better
  7. Hyperion Clojure • In-memory - testing datastore • Google App

    Engine Datastore • Mongo DB • MySQL • PostgreSQL • Riak • SQLite • Redis
  8. Design Principles 1. key/value store All Hyperion implementations, even for

    relational databases, conform to the simple key/value store API. 2. values are maps Every 'value' the goes in or out of a Hyperion datastore is map. 3. :key and :kind Every 'value' must have a :kind entry; a short string like "user" or "product". Persisted 'value's will have a :key entry; strings generated by the datastore. 4. search with data All queries are described by data.
  9. Examples: Instantiate Datastore (use 'hyperion.api) (new-datastore :implementation :memory) (new-datastore :implementation

    :mysql :connection-url "jdbc:mysql://localhost:3306/myapp?user=root" :database "myapp") (new-datastore :implementation :mongo :host "localhost" :port 27017 :database "myapp" :username "test" :password "test")
  10. Examples: Installing a datastore ; with brute force (set-ds! (new-datastore

    ...)) ; with elegance (binding [*ds* (new-datastore ...)] ; persistence stuff here)
  11. Examples: Saving stuff (save {:kind :foo}) ;=> {:kind "foo" :key

    "generated key"} (save {:kind :foo} {:value :bar}) ;=> {:kind "foo" :value :bar :key "generated key"} (save {:kind :foo} :value :bar) ;=> {:kind "foo" :value :bar :key "generated key"} (save {:kind :foo} {:value :bar} :another :fizz) ;=> {:kind "foo" :value :bar :another :fizz :key "generated key"} (save (citizen) :name "Joe" :age 21 :country "France") ;=> #<{:kind "citizen" :name "Joe" :age 21 :country "France" ...}>
  12. Examples: Updating saved data (let [record (save {:kind :foo :name

    "Sue"}) new-record (assoc record :name "John")] (save new-record)) ;=> {:kind "foo" :name "John" :key "generated key"}
  13. Examples: Finding Stuff ; if you have a key... (let

    [record (save {:kind :foo})] (find-by-key (:key record)) ; otherwise (find-by-kind :dog) (find-by-kind :dog :filters [:= :name "Fido"]) (find-by-kind :dog :filters [[:> :age 2][:< :age 5]]) (find-by-kind :dog :sorts [:name :asc]) (find-by-kind :dog :sorts [[:age :desc][:name :asc]]) (find-by-kind :dog :limit 10) (find-by-kind :dog :sorts [:name :asc] :limit 10) (find-by-kind :dog :sorts [:name :asc] :limit 10 :offset 10)
  14. Examples: Deleting Stuff ; if you have a key... (delete-by-key

    my-key) ; otherwise (delete-by-kind :dog) (delete-by-kind :dog :filters [:= :name "Fido"]) (delete-by-kind :dog :filters [[:> :age 2][:< :age 5]])
  15. Examples: defentity (defentity Citizen [name] [age :packer ->int] [gender :unpacker

    ->string] [occupation :type my.ns.Occupation] [spouse-key :type :key] [country :default "USA"] [created-at] [updated-at]) (save (citizen :name "John" :age "21" :gender :male :occupation coder :spouse-key "abc123"))
  16. Implement the Protocol Datastore (defprotocol Datastore (ds-save [this records]) (ds-delete-by-key

    [this key]) (ds-delete-by-kind [this kind filters]) (ds-count-by-kind [this kind filters]) (ds-find-by-key [this key]) (ds-find-by-kind [this kind filters sorts limit offset]) (ds-all-kinds [this]) (ds-pack-key [this value]) (ds-unpack-key [this value]))
  17. Examples: Installing a datastore # datastore not installed Hyperion.with_datastore(:postgres, options)

    do # datastore is installed # some persistence code here end # datastore not installed Hyperion.datastore = Hyperion.new_datastore(:postgres, options)
  18. Examples: Saving stuff Hyperion.save({:kind => :foo}) #=> {:kind=>"foo", :key=>"<generated key>"}

    Hyperion.save({:kind => :foo}, :value => :bar) #=> {:kind=>"foo", :value=>:bar, :key=>" <generated key>"}
  19. Examples: Updating saved data record = Hyperion.save({kind: :foo, name: 'Sam'})

    Hyperion.save(record, :name => 'John') #=> {:kind=>"foo", :name=>'John', :key=>" <generated key>"}
  20. Examples: Finding Stuff # if you have a key... Hyperion.find_by_key(my_key)

    # otherwise Hyperion.find_by_kind(:dog) Hyperion.find_by_kind(:dog, :filters => [[:name, '=', "Fido"]]) Hyperion.find_by_kind(:dog, :filters => [[:age, '>', 2], [:age, '<', 5]]) Hyperion.find_by_kind(:dog, :sorts => [[:age, :desc], [:name, :asc]]) Hyperion.find_by_kind(:dog, :limit => 10, :offset => 15) Hyperion.find_by_kind(:dog, :offset => 15) Hyperion.find_by_kind(:dog, :sorts => [[:name, :asc]])
  21. Examples: Deleting Stuff # if you have a key... Hyperion.delete_by_key(my_key)

    # otherwise Hyperion.delete_by_kind(:dog) Hyperion.delete_by_kind(:dog, :filters => [[:name, "=", "Fido"]]) Hyperion.delete_by_kind(:dog, :filters => [[:age, ">", 2], [:age, "<", 5]])
  22. Excluded Features • Associations • Custom finders • Lazy bindings

    • Validations • Adding behavior to data (Objects)
  23. Conclusion • Big idea - Defer the database decision •

    Hyperion is a library built for this purpose