GithubHelp home page GithubHelp logo

cqr / activerecord-postgres-hstore Goto Github PK

View Code? Open in Web Editor NEW

This project forked from diogob/activerecord-postgres-hstore

0.0 1.0 0.0 654 KB

Goodbye serialize, hello hstore. Speed up hashes in the database.

Home Page: http://engageis.github.com/activerecord-postgres-hstore

License: MIT License

JavaScript 0.01% Ruby 100.00%

activerecord-postgres-hstore's Introduction

Build Status

Goodbye serialize, hello hstore.

You need dynamic columns in your tables. What do you do?

  • Create lots of tables to handle it. Nice, now you’ll need more models and lots of additional sqls. Insertion and selection will be slow as hell.
  • Use a noSQL database just for this issue. Good luck.
  • Create a serialized column. Nice, insertion will be fine, and reading data from a record too. But, what if you have a condition in your select that includes serialized data? Yeah, regular expressions.

Requirements

Postgresql 8.4+ with contrib and Rails 3+. (It might work on 2.3.x with minor patches…) On Ubuntu, this is easy: sudo apt-get install postgresql-contrib-9.1

On Mac you have a couple of options:

Notes for Rails 3.1 and above

The master branch already support a custom serialization coder. If you want to use it just put in your Gemfile:

gem 'activerecord-postgres-hstore', github: 'engageis/activerecord-postgres-hstore'

If you install them gem from the master branch you also have to insert a line in each model that uses hstore. Assuming a model called Person, with a data field on it, the code should look like:

class Person < ActiveRecord::Base
  serialize :data, ActiveRecord::Coders::Hstore
end

If you want a default value (say, an empty hash) you should pass it as an argument when you initialize the serializer, like so:

class Person < ActiveRecord::Base
  serialize :data, ActiveRecord::Coders::Hstore.new({})
end

This way, you will automatically start with an empty hash that you can write attributes to.

irb(main):001:0> person = Person.new
=> #<Person id: nil, name: nil, data: {}, created_at: nil, updated_at: nil>
irb(main):002:0> person.data['favorite_color'] = 'blue'
=> "blue"

If you skip this step, you will have to manually initialize the value to an empty hash before writing to the attribute, or else you will get an error:

NoMethodError: undefined method `[]=' for nil:NilClass

Install

Hstore is a PostgreSQL contrib type, check it out first.

Then, just add this to your Gemfile:

gem 'activerecord-postgres-hstore'

And run your bundler:

bundle install

Make sure that you have the desired database, if not create it as the desired user:

createdb hstorage_dev

Add the parameters to your database.yml (these are system dependant), e.g.:

development:
  adapter: postgresql
  host: 127.0.0.1
  database: hstorage_dev
  encoding: unicode
  username: postgres
  password:
  pool: 5

Now you need to create a migration that adds hstore support for your PostgreSQL database:

rails g hstore:setup

Run it:

rake db:migrate

Finally you can create your own tables using hstore type. It’s easy:

rails g model Person name:string data:hstore
rake db:migrate

You’re done. Well, not yet. Don’t forget to add indexes. Like this:

CREATE INDEX people_gist_data ON people USING GIST(data); or CREATE INDEX people_gin_data ON people USING GIN(data);

To understand the difference between the two types of indexes take a look at PostgreSQL docs.

Usage

Once you have it installed, you just need to learn a little bit of new sqls for selecting stuff (creating and updating is transparent). Find records that contains a key named 'foo’:

Person.where("data ? 'foo'")

Find records where 'foo’ is equal to 'bar’:

Person.where("data -> 'foo' = 'bar'")

This same sql is at least twice as fast (using indexes) if you do it that way:

Person.where("data @> 'foo=>bar'")

Find records where 'foo’ is not equal to 'bar’:

Person.where("data -> 'foo' <> 'bar'")

Find records where 'foo’ is like 'bar’:

Person.where("data -> 'foo' LIKE '%bar%'")

If you need to delete a key in a record, you can do it that way:

person.destroy_key(:data, :foo)

This way you’ll also save the record:

person.destroy_key!(:data, :foo)

The destroy_key method returns 'self’, so you can chain it:

person.destroy_key(:data, :foo).destroy_key(:data, :bar).save

But there is a shortcuts for that:

person.destroy_keys(:data, :foo, :bar)

And finally, if you need to delete keys in many rows, you can:

Person.delete_key(:data, :foo)

and with many keys:

Person.delete_keys(:data, :foo, :bar)

Caveats

hstore keys and values have to be strings. This means true will become "true" and 42 will become "42" after you save the record. Only nil values are preserved.

It is also confusing when querying:

Person.where("data -> 'foo' = :value", value: true).to_sql
#=> SELECT "people".* FROM "people" WHERE ("data -> 'foo' = 't'") # notice 't'

To avoid the above, make sure all named parameters are strings:

Person.where("data -> 'foo' = :value", value: some_var.to_s)

Have fun.

Test Database

To have hstore enabled when you load your database schema (as happens in rake db:test:prepare), you have two options.

The first option is creating a template database with hstore installed and set the template option in database.yml to that database.

The second option is to uncomment or add the following line in config/application.rb

config.active_record.schema_format = :sql

This will change your schema dumps from Ruby to SQL. If you're unsure about the implications of this change, we suggest reading this Rails Guide.

Help

You can use issues in github for that. Or else you can reach us at twitter: @dbiazus or @joaomilho

Note on Patches/Pull Requests

  • Fork the project.
  • Make your feature addition or bug fix.
  • Add tests for it. This is important so I don’t break it in a future version unintentionally.
  • Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
  • Send me a pull request. Bonus points for topic branches.

Copyright

Copyright © 2010 Juan Maiz. See LICENSE for details.

activerecord-postgres-hstore's People

Contributors

betelgeuse avatar cqr avatar diogob avatar dotemacs avatar ecin avatar eshear avatar joaomilho avatar kevmoo avatar kgilpin avatar matrushka avatar msheakoski avatar releu avatar ren avatar tadast avatar tomtaylor avatar virtualstaticvoid avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.