Skip to content

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

Merged
merged 1 commit into from Sep 6, 2012

5 participants

@guedes
guedes commented Sep 5, 2012

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
Ruby on Rails member
robin850 added a note Sep 5, 2012

Do you mean this instead ?

@connection.execute 'drop table' if exists json_data_type
@guedes
guedes added a note 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
Ruby on Rails member
robin850 added a note Sep 5, 2012

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@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
Ruby on Rails member
robin850 added a note Sep 5, 2012

Do you mean typename ? ^^

@guedes
guedes added a note 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
Ruby on Rails member
robin850 added a note Sep 5, 2012

Okay, sorry once again. ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@robin850
Ruby on Rails member
robin850 commented Sep 5, 2012

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
Ruby on Rails member

Shouldn't it use ActiveSupport::JSON?

@guedes
guedes added a note Sep 5, 2012

Yes, I'm changing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@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
Ruby on Rails member

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.

@guedes
guedes added a note Sep 5, 2012

Agreed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@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
Ruby on Rails member

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@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
guedes commented Sep 5, 2012

@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
Ruby on Rails member

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

@guedes
guedes added a note Sep 5, 2012

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@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
Ruby on Rails member

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

@guedes
guedes added a note Sep 5, 2012

Sure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@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
guedes commented Sep 5, 2012

Thanks for suggestions!

@guedes
guedes commented Sep 5, 2012

@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
guedes commented Sep 5, 2012

@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
guedes commented Sep 6, 2012

@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
guedes commented Sep 6, 2012

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
Something went wrong with that request. Please try again.