Merge lp:~ack/storm/postgres-json-operators into lp:storm

Proposed by Alberto Donato
Status: Merged
Merged at revision: 481
Proposed branch: lp:~ack/storm/postgres-json-operators
Merge into: lp:storm
Diff against target: 88 lines (+42/-5)
2 files modified
storm/databases/postgres.py (+17/-3)
tests/databases/postgres.py (+25/-2)
To merge this branch: bzr merge lp:~ack/storm/postgres-json-operators
Reviewer Review Type Date Requested Status
Данило Шеган (community) Approve
Benji York (community) Approve
Review via email: mp+290440@code.launchpad.net

Description of the change

This adds support for "->" and "->>" Postgres JSON operators.

To post a comment you must log in.
Revision history for this message
Benji York (benji) wrote :

This branch looks good.

review: Approve
Revision history for this message
Данило Шеган (danilo) wrote :

Hit a test failure on xenial: https://pastebin.canonical.com/152983/

Sparkie shared suggestions on IRC.

483. By Alberto Donato

Cast to text.

Revision history for this message
Данило Шеган (danilo) wrote :

Works now, thanks.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'storm/databases/postgres.py'
--- storm/databases/postgres.py 2015-06-15 12:02:12 +0000
+++ storm/databases/postgres.py 2016-03-30 15:22:19 +0000
@@ -40,9 +40,9 @@
4040
41from storm.expr import (41from storm.expr import (
42 Undef, Expr, SetExpr, Select, Insert, Alias, And, Eq, FuncExpr, SQLRaw,42 Undef, Expr, SetExpr, Select, Insert, Alias, And, Eq, FuncExpr, SQLRaw,
43 Sequence, Like, SQLToken, COLUMN, COLUMN_NAME, COLUMN_PREFIX, TABLE,43 Sequence, Like, SQLToken, BinaryOper, COLUMN, COLUMN_NAME, COLUMN_PREFIX,
44 compile, compile_select, compile_insert, compile_set_expr, compile_like,44 TABLE, compile, compile_select, compile_insert, compile_set_expr,
45 compile_sql_token)45 compile_like, compile_sql_token)
46from storm.variables import Variable, ListVariable46from storm.variables import Variable, ListVariable
47from storm.database import Database, Connection, Result47from storm.database import Database, Connection, Result
48from storm.exceptions import (48from storm.exceptions import (
@@ -456,3 +456,17 @@
456 "statement timeout" in str(error)):456 "statement timeout" in str(error)):
457 raise TimeoutError(457 raise TimeoutError(
458 statement, params, "SQL server cancelled statement")458 statement, params, "SQL server cancelled statement")
459
460
461# Postgres-specific operators
462
463class JSONElement(BinaryOper):
464 """Return an element of a JSON value (by index or field name)."""
465
466 oper = "->"
467
468
469class JSONTextElement(BinaryOper):
470 """Return an element of a JSON value (by index or field name) as text."""
471
472 oper = "->>"
459473
=== modified file 'tests/databases/postgres.py'
--- tests/databases/postgres.py 2015-06-05 07:27:54 +0000
+++ tests/databases/postgres.py 2016-03-30 15:22:19 +0000
@@ -20,10 +20,11 @@
20#20#
21from datetime import date, time, timedelta21from datetime import date, time, timedelta
22import os22import os
23import json
2324
24from storm.databases.postgres import (25from storm.databases.postgres import (
25 Postgres, compile, currval, Returning, Case, PostgresTimeoutTracer,26 Postgres, compile, currval, Returning, Case, PostgresTimeoutTracer,
26 make_dsn)27 make_dsn, JSONElement, JSONTextElement)
27from storm.database import create_database28from storm.database import create_database
28from storm.exceptions import InterfaceError, ProgrammingError29from storm.exceptions import InterfaceError, ProgrammingError
29from storm.variables import DateTimeVariable, RawStrVariable30from storm.variables import DateTimeVariable, RawStrVariable
@@ -31,7 +32,7 @@
31from storm.properties import Int32from storm.properties import Int
32from storm.exceptions import DisconnectionError, OperationalError33from storm.exceptions import DisconnectionError, OperationalError
33from storm.expr import (Union, Select, Insert, Update, Alias, SQLRaw, State,34from storm.expr import (Union, Select, Insert, Update, Alias, SQLRaw, State,
34 Sequence, Like, Column, COLUMN)35 Sequence, Like, Column, COLUMN, Cast, Func)
35from storm.tracer import install_tracer, TimeoutError36from storm.tracer import install_tracer, TimeoutError
36from storm.uri import URI37from storm.uri import URI
3738
@@ -638,6 +639,28 @@
638 exc = OperationalError("could not receive data from server")639 exc = OperationalError("could not receive data from server")
639 self.assertTrue(self.connection.is_disconnection_error(exc))640 self.assertTrue(self.connection.is_disconnection_error(exc))
640641
642 def test_json_element(self):
643 "JSONElement returns an element from a json field."
644 connection = self.database.connect()
645 json_value = Cast(u'{"a": 1}', "json")
646 expr = JSONElement(json_value, u"a")
647 # Need to cast as text since newer psycopg versions decode JSON
648 # automatically.
649 result = connection.execute(Select(Cast(expr, "text")))
650 self.assertEqual("1", result.get_one()[0])
651 result = connection.execute(Select(Func("pg_typeof", expr)))
652 self.assertEqual("json", result.get_one()[0])
653
654 def test_json_text_element(self):
655 "JSONTextElement returns an element from a json field as text."
656 connection = self.database.connect()
657 json_value = Cast(u'{"a": 1}', "json")
658 expr = JSONTextElement(json_value, u"a")
659 result = connection.execute(Select(expr))
660 self.assertEqual("1", result.get_one()[0])
661 result = connection.execute(Select(Func("pg_typeof", expr)))
662 self.assertEqual("text", result.get_one()[0])
663
641664
642_max_prepared_transactions = None665_max_prepared_transactions = None
643666

Subscribers

People subscribed via source and target branches

to status/vote changes: