AR supporting new JSON data type on PostgreSQL >= 9.2 #7527

Merged
merged 1 commit into from Sep 6, 2012

Projects

None yet

5 participants

@guedes

Hello all!

The next PostgreSQL version (9.2) will supports a native JSON type. Once the 9.2 version will be release soon I think that would be nice if AR supports it too.

Before started this, I searched for someone that could be working on this already, and tweeted @tenderlove asking if he remembers about someone doing this job, since seems that nobody is working on this I'm sending this pull request and I'd like to know your opinions about this feature and about my implementation. I marked two "FIXMEs" that could be a DRY candidate, IMO. Maybe should AR:Store be changed too?

Thanks.

@robin850 robin850 commented on the diff Sep 5, 2012
activerecord/test/cases/adapters/postgresql/json_test.rb
+ def setup
+ @connection = ActiveRecord::Base.connection
+ begin
+ @connection.transaction do
+ @connection.create_table('json_data_type') do |t|
+ t.json 'payload', :default => {}
+ end
+ end
+ rescue ActiveRecord::StatementInvalid
+ return skip "do not test on PG without json"
+ end
+ @column = JsonDataType.columns.find { |c| c.name == 'payload' }
+ end
+
+ def teardown
+ @connection.execute 'drop table if exists json_data_type'
@robin850
robin850 Sep 5, 2012

Do you mean this instead ?

@connection.execute 'drop table' if exists json_data_type
@guedes
guedes Sep 5, 2012

Hi!

No, I'm not. json_data_type is the name I'm using for the test table. See line 16 above.

Thanks for your review.

@robin850
robin850 Sep 5, 2012

Sorry, I thought. ^^ BTW, thanks for this pull request, awesome.

@robin850 robin850 commented on the diff Sep 5, 2012
activerecord/test/schema/postgresql_specific_schema.rb
@@ -82,6 +82,15 @@
_SQL
end
+ if 't' == select_value("select 'json'=ANY(select typname from pg_type)")
@robin850
robin850 Sep 5, 2012

Do you mean typename ? ^^

@guedes
guedes Sep 5, 2012

No, that statement is correct it must be typname because this is the column name from pg_type that gives me the name of type.

Thanks for your review!

@robin850
robin850 Sep 5, 2012

Okay, sorry once again. ;)

@robin850
Ruby on Rails member

I'm 👍 for this feature ! :-)

@carlosantoniodasilva carlosantoniodasilva and 1 other commented on an outdated diff Sep 5, 2012
...tive_record/connection_adapters/postgresql_adapter.rb
+ if Hash === object
+ JSON.generate(object)
+ else
+ object
+ end
+ end
+
+ def string_to_json(string)
+ if string.nil?
+ nil
+ elsif String === string
+ JSON.parse(string)
+ else
+ string
+ end
+ end
@carlosantoniodasilva
carlosantoniodasilva Sep 5, 2012

Shouldn't it use ActiveSupport::JSON?

@guedes
guedes Sep 5, 2012

Yes, I'm changing.

@carlosantoniodasilva carlosantoniodasilva and 1 other commented on an outdated diff Sep 5, 2012
...tive_record/connection_adapters/postgresql_adapter.rb
@@ -80,6 +80,24 @@ def string_to_hstore(string)
end
end
+ def json_to_string(object)
+ if Hash === object
+ JSON.generate(object)
+ else
+ object
+ end
+ end
+
+ def string_to_json(string)
+ if string.nil?
+ nil
@carlosantoniodasilva
carlosantoniodasilva Sep 5, 2012

I don't think you need to check for nil? here, since it's not a String, it'll return whatever string is, even if it's nil.

@carlosantoniodasilva carlosantoniodasilva commented on an outdated diff Sep 5, 2012
...tive_record/connection_adapters/postgresql_adapter.rb
@@ -600,8 +631,14 @@ def type_cast(value, column)
return super unless 'bytea' == column.sql_type
{ :value => value, :format => 1 }
when Hash
- return super unless 'hstore' == column.sql_type
- PostgreSQLColumn.hstore_to_string(value)
+ # FIXME: refactor this?
+ if 'hstore' == column.sql_type
+ PostgreSQLColumn.hstore_to_string(value)
+ elsif 'json' == column.sql_type
+ PostgreSQLColumn.json_to_string(value)
+ else
+ return super
+ end
@carlosantoniodasilva
carlosantoniodasilva Sep 5, 2012

I think a case statement, pretty much as the other in line 586 that you changed, would come in handy here.

@carlosantoniodasilva
Ruby on Rails member

Looks good, I've made a few comments. Thanks!

/cc @rafaelfranca @tenderlove

@carlosantoniodasilva
Ruby on Rails member

And apparently after 9e0a14f you'll have to rebase and move some code around :)

@rafaelfranca
Ruby on Rails member

Oopss! I didn't see this pull request. Sorry

@guedes

@carlosantoniodasilva Thank you for your suggestions, I rebased from master and did the changes squashing my commits. I ran the tests against postgres 9.1 and 9.2RC1 and everything passed.

/cc @rafaelfranca

@carlosantoniodasilva carlosantoniodasilva and 1 other commented on an outdated diff Sep 5, 2012
activerecord/test/cases/adapters/postgresql/json_test.rb
+require 'active_record/base'
+require 'active_record/connection_adapters/postgresql_adapter'
+
+class PostgresqlJSONTest < ActiveRecord::TestCase
+ class JsonDataType < ActiveRecord::Base
+ self.table_name = 'json_data_type'
+ end
+
+ def setup
+ @connection = ActiveRecord::Base.connection
+ begin
+ @connection.transaction do
+ @connection.create_table('json_data_type') do |t|
+ t.json 'payload', :default => {}
+ end
+ end
@carlosantoniodasilva
carlosantoniodasilva Sep 5, 2012

Do you need the transaction block to create only one table?

@guedes
guedes Sep 5, 2012

No, I don't. I'll remove it.

@carlosantoniodasilva carlosantoniodasilva and 1 other commented on an outdated diff Sep 5, 2012
...tive_record/connection_adapters/postgresql/quoting.rb
@@ -66,8 +67,12 @@ def type_cast(value, column)
return super unless 'bytea' == column.sql_type
{ :value => value, :format => 1 }
when Hash
- return super unless 'hstore' == column.sql_type
- PostgreSQLColumn.hstore_to_string(value)
+ case column.sql_type
+ when 'hstore' then PostgreSQLColumn.hstore_to_string(value)
+ when 'json' then PostgreSQLColumn.json_to_string(value)
+ else
+ super
@carlosantoniodasilva
carlosantoniodasilva Sep 5, 2012

I know this is nitpicking, but would you mind using else super like the other one above? :)

@carlosantoniodasilva
Ruby on Rails member

@guedes everything looks great! I just added another question, and I have to ask you to add a changelog entry to Active Record with the new json type for PostgreSQL.

Just ping us after that, and we'll merge. Thanks!

@guedes

Thanks for suggestions!

@guedes

@carlosantoniodasilva and @rafaelfranca : I fixed the code following your suggestions. Thank you for you time on this!

@rafaelfranca
Ruby on Rails member

Great! Should you squash the commits?

@guedes

@rafaelfranca I squashed the commits and changed the commit message too. Tests still passing.

Thanks!

@steveklabnik
Ruby on Rails member

This is somehow out of date. CHANGELOGs! /me shakes his fist.

@rafaelfranca
Ruby on Rails member

Yes. Please rebase it.

@guedes guedes ActiveRecord support to PostgreSQL 9.2 JSON type
This implements the support to encode/decode JSON
data to/from database and creating columns of type
JSON using a native type [1] supported by PostgreSQL
from version 9.2.

[1] http://www.postgresql.org/docs/9.2/static/datatype-json.html
3b516b5
@guedes

@rafaelfranca Sorry, I hope this is OK now. Thanks @steveklabnik to point me that.

@rafaelfranca rafaelfranca merged commit a690935 into rails:master Sep 6, 2012
@guedes

Thanks for accepting this!

@vjpr vjpr referenced this pull request in tgriesser/knex Jun 17, 2013
Merged

JSON datatype support for Postgres #20

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment