From 579342339b05da69db0337ec41c2ad9e3e54d1ec Mon Sep 17 00:00:00 2001 From: Vitor Baptista Date: Fri, 20 Jun 2014 15:55:15 -0300 Subject: [PATCH] [#1776] Fix bug when upserting [] on JSON column in the datastore We were testing that the new value wasn't `None` using `if value`. As `[]` is a falsy value, we never went through that `if` and ended up trying to run an invalid SQL query. This commit fixes that by explictly testing `if value is not None`. This was first discovered in http://stackoverflow.com/questions/24207065/inserting-empty-arrays-in-json-type-fields-in-datastore --- ckanext/datastore/db.py | 2 +- ckanext/datastore/tests/test_upsert.py | 29 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/ckanext/datastore/db.py b/ckanext/datastore/db.py index f9c729b583e..ecf6b7993fe 100644 --- a/ckanext/datastore/db.py +++ b/ckanext/datastore/db.py @@ -620,7 +620,7 @@ def upsert_data(context, data_dict): for field in fields: value = record.get(field['id']) - if value and field['type'].lower() == 'nested': + if value is not None and field['type'].lower() == 'nested': ## a tuple with an empty second value record[field['id']] = (json.dumps(value), '') diff --git a/ckanext/datastore/tests/test_upsert.py b/ckanext/datastore/tests/test_upsert.py index 6db537415d5..0f0ac69f9f8 100644 --- a/ckanext/datastore/tests/test_upsert.py +++ b/ckanext/datastore/tests/test_upsert.py @@ -13,6 +13,8 @@ import ckanext.datastore.db as db from ckanext.datastore.tests.helpers import rebuild_all_dbs +assert_equal = nose.tools.assert_equal + class TestDatastoreUpsert(tests.WsgiAppCase): sysadmin_user = None @@ -236,6 +238,33 @@ def test_upsert_non_existing_field(self): assert res_dict['success'] is False + def test_upsert_works_with_empty_list_in_json_field(self): + hhguide = u"hitchhiker's guide to the galaxy" + + data = { + 'resource_id': self.data['resource_id'], + 'method': 'upsert', + 'records': [{ + 'nested': [], + u'b\xfck': hhguide}] + } + + postparams = '%s=1' % json.dumps(data) + auth = {'Authorization': str(self.sysadmin_user.apikey)} + res = self.app.post('/api/action/datastore_upsert', params=postparams, + extra_environ=auth) + res_dict = json.loads(res.body) + assert res_dict['success'] is True, res_dict + + c = self.Session.connection() + results = c.execute('select * from "{0}"'.format(data['resource_id'])) + record = [r for r in results.fetchall() if r[2] == hhguide] + self.Session.remove() + assert len(record) == 1, record + assert_equal(json.loads(record[0][4].json), + data['records'][0]['nested']) + + class TestDatastoreInsert(tests.WsgiAppCase): sysadmin_user = None