Merge lp:~thisfred/u1db/combine-mapping-3 into lp:u1db

Proposed by Eric Casteleijn
Status: Merged
Approved by: Eric Casteleijn
Approved revision: 369
Merged at revision: 363
Proposed branch: lp:~thisfred/u1db/combine-mapping-3
Merge into: lp:u1db
Prerequisite: lp:~thisfred/u1db/combine-mapping-2
Diff against target: 186 lines (+85/-3)
5 files modified
src/u1db_query.c (+20/-3)
u1db/query_parser.py (+21/-0)
u1db/tests/c_backend_wrapper.pyx (+6/-0)
u1db/tests/test_backends.py (+32/-0)
u1db/tests/test_query_parser.py (+6/-0)
To merge this branch: bzr merge lp:~thisfred/u1db/combine-mapping-3
Reviewer Review Type Date Requested Status
Samuele Pedroni Approve
Review via email: mp+116526@code.launchpad.net

This proposal supersedes a proposal from 2012-07-24.

Commit message

Added the combine() mapping.

Description of the change

Added the combine() mapping.

To post a comment you must log in.
lp:~thisfred/u1db/combine-mapping-3 updated
368. By Eric Casteleijn

removed debug prints

369. By Eric Casteleijn

removed debugging

Revision history for this message
Samuele Pedroni (pedronis) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/u1db_query.c'
2--- src/u1db_query.c 2012-07-25 20:48:18 +0000
3+++ src/u1db_query.c 2012-07-26 12:03:19 +0000
4@@ -213,6 +213,7 @@
5 static int op_split_words(
6 parse_tree *tree, json_object *obj, string_list *result);
7 static int op_bool(parse_tree *tree, json_object *obj, string_list *result);
8+static int op_combine(parse_tree *tree, json_object *obj, string_list *result);
9
10 static const int JUST_EXPRESSION[1] = {EXPRESSION};
11 static const int EXPRESSION_INTEGER[2] = {EXPRESSION, INTEGER};
12@@ -228,7 +229,8 @@
13 op_lower, "lower", json_type_string, 1, JUST_EXPRESSION,
14 op_number, "number", json_type_int, 2, EXPRESSION_INTEGER,
15 op_split_words, "split_words", json_type_string, 1, JUST_EXPRESSION,
16- op_bool, "bool", json_type_boolean, 1, JUST_EXPRESSION};
17+ op_bool, "bool", json_type_boolean, 1, JUST_EXPRESSION,
18+ op_combine, "combine", json_type_string, -1, JUST_EXPRESSION};
19
20 static int
21 extract_field_values(json_object *obj, const string_list *field_path,
22@@ -443,6 +445,21 @@
23 }
24
25 static int
26+op_combine(parse_tree *tree, json_object *obj, string_list *result)
27+{
28+ parse_tree *node = NULL;
29+ int status = U1DB_OK;
30+
31+ node = tree->first_child;
32+ for (node = tree->first_child; node != NULL; node = node->next_sibling) {
33+ status = get_values(node, obj, result);
34+ if (status != U1DB_OK)
35+ return status;
36+ }
37+ return status;
38+}
39+
40+static int
41 op_split_words(parse_tree *tree, json_object *obj, string_list *result)
42 {
43 string_list_item *item = NULL;
44@@ -1265,13 +1282,13 @@
45 while (expression[*start] == ' ')
46 (*start)++;
47 size = *idx - *start;
48- if (!size)
49- return U1DB_OK;
50 term = expression + *start;
51 (*idx)++;
52 while (expression[*idx] == ' ')
53 (*idx)++;
54 *start = *idx;
55+ if (!size)
56+ return U1DB_OK;
57 if (size) {
58 status = append_child(result);
59 if (status != U1DB_OK) {
60
61=== modified file 'u1db/query_parser.py'
62--- u1db/query_parser.py 2012-07-25 19:10:50 +0000
63+++ u1db/query_parser.py 2012-07-26 12:03:19 +0000
64@@ -207,6 +207,26 @@
65 return list(result)
66
67
68+class Combine(Transformation):
69+ """Combine multiple expressions into a single index."""
70+
71+ name = "combine"
72+ # variable number of args
73+ arity = -1
74+
75+ def __init__(self, *inner):
76+ super(Combine, self).__init__(inner)
77+
78+ def get(self, raw_doc):
79+ inner_values = []
80+ for inner in self.inner:
81+ inner_values.extend(inner.get(raw_doc))
82+ return self.transform(inner_values)
83+
84+ def transform(self, values):
85+ return values
86+
87+
88 class IsNull(Transformation):
89 """Indicate whether the input is None.
90
91@@ -348,3 +368,4 @@
92 Parser.register_transormation(Number)
93 Parser.register_transormation(Bool)
94 Parser.register_transormation(IsNull)
95+Parser.register_transormation(Combine)
96
97=== modified file 'u1db/tests/c_backend_wrapper.pyx'
98--- u1db/tests/c_backend_wrapper.pyx 2012-07-23 18:00:03 +0000
99+++ u1db/tests/c_backend_wrapper.pyx 2012-07-26 12:03:19 +0000
100@@ -138,6 +138,8 @@
101 int U1DB_INDEX_DOES_NOT_EXIST
102 int U1DB_INVALID_GENERATION
103 int U1DB_INVALID_TRANSACTION_ID
104+ int U1DB_INVALID_TRANSFORMATION_FUNCTION
105+ int U1DB_UNKNOWN_OPERATION
106 int U1DB_INTERNAL_ERROR
107 int U1DB_TARGET_UNAVAILABLE
108
109@@ -612,6 +614,10 @@
110 raise errors.DocumentTooBig
111 if status == U1DB_USER_QUOTA_EXCEEDED:
112 raise errors.UserQuotaExceeded
113+ if status == U1DB_INVALID_TRANSFORMATION_FUNCTION:
114+ raise errors.IndexDefinitionParseError
115+ if status == U1DB_UNKNOWN_OPERATION:
116+ raise errors.IndexDefinitionParseError
117 raise RuntimeError('%s (status: %s)' % (context, status))
118
119
120
121=== modified file 'u1db/tests/test_backends.py'
122--- u1db/tests/test_backends.py 2012-07-24 16:22:38 +0000
123+++ u1db/tests/test_backends.py 2012-07-26 12:03:19 +0000
124@@ -1456,6 +1456,13 @@
125 self.db.create_index('test-idx', 'sub.foo.bar.baz.qux.fnord')
126 self.assertEqual([], self.db.get_from_index('test-idx', '*'))
127
128+ def test_nested_unknown_operation(self):
129+ self.db.create_doc_from_json(nested_doc)
130+ # sub exists, but sub.foo does not:
131+ self.assertRaises(
132+ errors.IndexDefinitionParseError, self.db.create_index, 'test-idx',
133+ 'unknown_operation(field1)')
134+
135 def test_index_list1(self):
136 self.db.create_index("index", "name")
137 content = '{"name": ["foo", "bar"]}'
138@@ -1617,6 +1624,31 @@
139 rows = self.db.get_from_index("index", "*")
140 self.assertEqual([], rows)
141
142+ def test_get_from_index_with_combine(self):
143+ self.db.create_index("index", "combine(foo, bar)")
144+ content = '{"foo": "value1", "bar": "value2"}'
145+ doc = self.db.create_doc_from_json(content)
146+ rows = self.db.get_from_index("index", "value1")
147+ self.assertEqual([doc], rows)
148+ rows = self.db.get_from_index("index", "value2")
149+ self.assertEqual([doc], rows)
150+
151+ def test_get_complex_combine(self):
152+ self.db.create_index(
153+ "index", "combine(number(foo, 5), lower(bar), split_words(baz))")
154+ content = '{"foo": 12, "bar": "ALLCAPS", "baz": "qux nox"}'
155+ doc = self.db.create_doc_from_json(content)
156+ content = '{"foo": "not a number", "bar": "something"}'
157+ doc2 = self.db.create_doc_from_json(content)
158+ rows = self.db.get_from_index("index", "00012")
159+ self.assertEqual([doc], rows)
160+ rows = self.db.get_from_index("index", "allcaps")
161+ self.assertEqual([doc], rows)
162+ rows = self.db.get_from_index("index", "nox")
163+ self.assertEqual([doc], rows)
164+ rows = self.db.get_from_index("index", "something")
165+ self.assertEqual([doc2], rows)
166+
167 def test_get_index_keys_from_index(self):
168 self.db.create_index('test-idx', 'key')
169 content1 = '{"key": "value1"}'
170
171=== modified file 'u1db/tests/test_query_parser.py'
172--- u1db/tests/test_query_parser.py 2012-07-25 16:20:27 +0000
173+++ u1db/tests/test_query_parser.py 2012-07-26 12:03:19 +0000
174@@ -59,6 +59,12 @@
175 self.parser.parse('lower(split_words(field1))'),
176 query_parser.Lower)
177
178+ def test_nested_branching_mapping(self):
179+ self.assertIsInstance(
180+ self.parser.parse(
181+ 'combine(lower(field1), split_words(field2), '
182+ 'number(field3, 5))'), query_parser.Combine)
183+
184 def test_single_mapping_multiple_fields(self):
185 self.assertIsInstance(
186 self.parser.parse('number(field1, 5)'), query_parser.Number)

Subscribers

People subscribed via source and target branches