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
1=== modified file 'storm/databases/postgres.py'
2--- storm/databases/postgres.py 2015-06-15 12:02:12 +0000
3+++ storm/databases/postgres.py 2016-03-30 15:22:19 +0000
4@@ -40,9 +40,9 @@
5
6 from storm.expr import (
7 Undef, Expr, SetExpr, Select, Insert, Alias, And, Eq, FuncExpr, SQLRaw,
8- Sequence, Like, SQLToken, COLUMN, COLUMN_NAME, COLUMN_PREFIX, TABLE,
9- compile, compile_select, compile_insert, compile_set_expr, compile_like,
10- compile_sql_token)
11+ Sequence, Like, SQLToken, BinaryOper, COLUMN, COLUMN_NAME, COLUMN_PREFIX,
12+ TABLE, compile, compile_select, compile_insert, compile_set_expr,
13+ compile_like, compile_sql_token)
14 from storm.variables import Variable, ListVariable
15 from storm.database import Database, Connection, Result
16 from storm.exceptions import (
17@@ -456,3 +456,17 @@
18 "statement timeout" in str(error)):
19 raise TimeoutError(
20 statement, params, "SQL server cancelled statement")
21+
22+
23+# Postgres-specific operators
24+
25+class JSONElement(BinaryOper):
26+ """Return an element of a JSON value (by index or field name)."""
27+
28+ oper = "->"
29+
30+
31+class JSONTextElement(BinaryOper):
32+ """Return an element of a JSON value (by index or field name) as text."""
33+
34+ oper = "->>"
35
36=== modified file 'tests/databases/postgres.py'
37--- tests/databases/postgres.py 2015-06-05 07:27:54 +0000
38+++ tests/databases/postgres.py 2016-03-30 15:22:19 +0000
39@@ -20,10 +20,11 @@
40 #
41 from datetime import date, time, timedelta
42 import os
43+import json
44
45 from storm.databases.postgres import (
46 Postgres, compile, currval, Returning, Case, PostgresTimeoutTracer,
47- make_dsn)
48+ make_dsn, JSONElement, JSONTextElement)
49 from storm.database import create_database
50 from storm.exceptions import InterfaceError, ProgrammingError
51 from storm.variables import DateTimeVariable, RawStrVariable
52@@ -31,7 +32,7 @@
53 from storm.properties import Int
54 from storm.exceptions import DisconnectionError, OperationalError
55 from storm.expr import (Union, Select, Insert, Update, Alias, SQLRaw, State,
56- Sequence, Like, Column, COLUMN)
57+ Sequence, Like, Column, COLUMN, Cast, Func)
58 from storm.tracer import install_tracer, TimeoutError
59 from storm.uri import URI
60
61@@ -638,6 +639,28 @@
62 exc = OperationalError("could not receive data from server")
63 self.assertTrue(self.connection.is_disconnection_error(exc))
64
65+ def test_json_element(self):
66+ "JSONElement returns an element from a json field."
67+ connection = self.database.connect()
68+ json_value = Cast(u'{"a": 1}', "json")
69+ expr = JSONElement(json_value, u"a")
70+ # Need to cast as text since newer psycopg versions decode JSON
71+ # automatically.
72+ result = connection.execute(Select(Cast(expr, "text")))
73+ self.assertEqual("1", result.get_one()[0])
74+ result = connection.execute(Select(Func("pg_typeof", expr)))
75+ self.assertEqual("json", result.get_one()[0])
76+
77+ def test_json_text_element(self):
78+ "JSONTextElement returns an element from a json field as text."
79+ connection = self.database.connect()
80+ json_value = Cast(u'{"a": 1}', "json")
81+ expr = JSONTextElement(json_value, u"a")
82+ result = connection.execute(Select(expr))
83+ self.assertEqual("1", result.get_one()[0])
84+ result = connection.execute(Select(Func("pg_typeof", expr)))
85+ self.assertEqual("text", result.get_one()[0])
86+
87
88 _max_prepared_transactions = None
89

Subscribers

People subscribed via source and target branches

to status/vote changes: