Merge lp:~chipaca/u1db/split_out_bad_globbage into lp:u1db

Proposed by John Lenton
Status: Merged
Approved by: John Lenton
Approved revision: 310
Merged at revision: 309
Proposed branch: lp:~chipaca/u1db/split_out_bad_globbage
Merge into: lp:u1db
Prerequisite: lp:~chipaca/u1db/u1db-client_first_pass_of_get-from-index
Diff against target: 297 lines (+78/-47)
10 files modified
include/u1db/u1db.h (+1/-0)
src/u1db_query.c (+2/-2)
u1db/backends/inmemory.py (+2/-2)
u1db/backends/sqlite_backend.py (+2/-2)
u1db/commandline/client.py (+33/-18)
u1db/errors.py (+5/-4)
u1db/tests/c_backend_wrapper.pyx (+3/-0)
u1db/tests/commandline/test_client.py (+24/-13)
u1db/tests/test_backends.py (+5/-5)
u1db/tests/test_inmemory.py (+1/-1)
To merge this branch: bzr merge lp:~chipaca/u1db/split_out_bad_globbage
Reviewer Review Type Date Requested Status
John O'Brien (community) Approve
Eric Casteleijn (community) Approve
Review via email: mp+106991@code.launchpad.net

This proposal supersedes a proposal from 2012-05-23.

Commit message

Split the «user globbed wrong» error from the «user used the wrong number of arguments» error when querying indexes (u1db-client gains better error reporting).

Description of the change

Split the «user globbed wrong» error from the «user used the wrong number of arguments» error when querying indexes.

To post a comment you must log in.
Revision history for this message
Eric Casteleijn (thisfred) wrote :

I don't think the text of the error message is always correct:

["value1*", "value2"] is not two partial searches, it's a case where the partial search is in the wrong place. To put it in language that covers all cases is left as an exercise to the reader.

Revision history for this message
Eric Casteleijn (thisfred) wrote :

otherwise fine, tests pass, no memory leaks

review: Approve
Revision history for this message
John O'Brien (jdobrien) wrote :

works for me!

review: Approve
Revision history for this message
Eric Casteleijn (thisfred) wrote :

Awesome thanks for making it clearer!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'include/u1db/u1db.h'
2--- include/u1db/u1db.h 2012-05-23 14:58:00 +0000
3+++ include/u1db/u1db.h 2012-05-23 16:48:17 +0000
4@@ -67,6 +67,7 @@
5 #define U1DB_INVALID_FIELD_SPECIFIER -16
6 #define U1DB_DUPLICATE_INDEX_NAME -17
7 #define U1DB_INDEX_DOES_NOT_EXIST -18
8+#define U1DB_INVALID_GLOBBING -19
9 #define U1DB_INTERNAL_ERROR -999
10
11 // Used by put_doc_if_newer
12
13=== modified file 'src/u1db_query.c'
14--- src/u1db_query.c 2012-05-21 16:29:25 +0000
15+++ src/u1db_query.c 2012-05-23 16:48:17 +0000
16@@ -725,7 +725,7 @@
17 wildcard[i] = 2;
18 if (have_wildcard) {
19 //globs not allowed after another wildcard
20- status = U1DB_INVALID_VALUE_FOR_INDEX;
21+ status = U1DB_INVALID_GLOBBING;
22 goto finish;
23 }
24 have_wildcard = 1;
25@@ -734,7 +734,7 @@
26 wildcard[i] = 0;
27 if (have_wildcard) {
28 // Can't have a non-wildcard after a wildcard
29- status = U1DB_INVALID_VALUE_FOR_INDEX;
30+ status = U1DB_INVALID_GLOBBING;
31 goto finish;
32 }
33 add_to_buf(&cur, &buf_size, " AND d%d.value = ?", i);
34
35=== modified file 'u1db/backends/inmemory.py'
36--- u1db/backends/inmemory.py 2012-05-23 13:11:46 +0000
37+++ u1db/backends/inmemory.py 2012-05-23 16:48:17 +0000
38@@ -302,14 +302,14 @@
39 # We have an 'x*' style wildcard
40 if is_wildcard:
41 # We were already in wildcard mode, so this is invalid
42- raise errors.InvalidValueForIndex()
43+ raise errors.InvalidGlobbing
44 last = idx + 1
45 is_wildcard = True
46 else:
47 if is_wildcard:
48 # We were in wildcard mode, we can't follow that with
49 # non-wildcard
50- raise errors.InvalidValueForIndex()
51+ raise errors.InvalidGlobbing
52 last = idx + 1
53 if not is_wildcard:
54 return -1
55
56=== modified file 'u1db/backends/sqlite_backend.py'
57--- u1db/backends/sqlite_backend.py 2012-05-23 13:11:46 +0000
58+++ u1db/backends/sqlite_backend.py 2012-05-23 16:48:17 +0000
59@@ -592,13 +592,13 @@
60 if is_wildcard:
61 # We can't have a partial wildcard following
62 # another wildcard
63- raise errors.InvalidValueForIndex()
64+ raise errors.InvalidGlobbing
65 where.append(like_where[idx])
66 args.append(self._transform_glob(value))
67 is_wildcard = True
68 else:
69 if is_wildcard:
70- raise errors.InvalidValueForIndex()
71+ raise errors.InvalidGlobbing
72 where.append(exact_where[idx])
73 args.append(value)
74 statement = ("SELECT d.doc_id, d.doc_rev, d.content"
75
76=== modified file 'u1db/commandline/client.py'
77--- u1db/commandline/client.py 2012-05-23 14:20:12 +0000
78+++ u1db/commandline/client.py 2012-05-23 16:48:17 +0000
79@@ -351,26 +351,41 @@
80 self.stderr.write("Index does not exist.\n")
81 except errors.InvalidValueForIndex:
82 index_def = db._get_index_definition(index)
83- msg = ["Invalid query;"]
84 len_diff = len(index_def) - len(values)
85- if len_diff:
86- msg.append("index %r requires %d query expression%s"
87- % (index, len(index_def),
88- "s" if len(index_def) > 1 else ""))
89- if len(values):
90- msg[-1] += ", not %d" % len(values)
91- if len_diff > 0:
92- msg[-1] += ".\nPerhaps you meant:"
93- argv = self.argv if self.argv is not None else sys.argv
94- msg.extend(argv[:2])
95- msg.append(repr(database))
96- msg.extend(map(repr, values))
97- msg.extend(["'*'" for i in range(len_diff)])
98- else:
99+ if len_diff == 0:
100 # can't happen (HAH)
101- msg.append("not sure how to help you (read the docs?)")
102- self.stderr.write(" ".join(msg))
103- self.stderr.write(".\n")
104+ raise
105+ argv = self.argv if self.argv is not None else sys.argv
106+ self.stderr.write(
107+ "Invalid query: "
108+ "index %r requires %d query expression%s%s.\n"
109+ "For example, the following would be valid:\n"
110+ " %s %s %r %r %s\n"
111+ % (index,
112+ len(index_def),
113+ "s" if len(index_def) > 1 else "",
114+ ", not %d" % len(values) if len(values) else "",
115+ argv[0], argv[1], database, index,
116+ " ".join(map(repr,
117+ values[:len(index_def)]
118+ + ["*" for i in range(len_diff)])),
119+ ))
120+ except errors.InvalidGlobbing:
121+ argv = self.argv if self.argv is not None else sys.argv
122+ fixed = []
123+ for (i, v) in enumerate(values):
124+ fixed.append(v)
125+ if v.endswith('*'):
126+ break
127+ # values has at least one element, so i is defined
128+ fixed.extend('*'*(len(values)-i-1))
129+ self.stderr.write(
130+ "Invalid query: a star can only be followed by stars.\n"
131+ "For example, the following would be valid:\n"
132+ " %s %s %r %r %s\n"
133+ % (argv[0], argv[1], database, index,
134+ " ".join(map(repr, fixed))))
135+
136 else:
137 self.stdout.write("[")
138 for i, doc in enumerate(docs):
139
140=== modified file 'u1db/errors.py'
141--- u1db/errors.py 2012-05-21 15:01:18 +0000
142+++ u1db/errors.py 2012-05-23 16:48:17 +0000
143@@ -44,10 +44,11 @@
144
145
146 class InvalidValueForIndex(U1DBError):
147- """The values supplied does not match the index definition.
148-
149- Can also be raised if wildcard matches are not strictly at the tail of the
150- request.
151+ """The values supplied does not match the index definition."""
152+
153+
154+class InvalidGlobbing(U1DBError):
155+ """Raised if wildcard matches are not strictly at the tail of the request.
156 """
157
158
159
160=== modified file 'u1db/tests/c_backend_wrapper.pyx'
161--- u1db/tests/c_backend_wrapper.pyx 2012-05-23 14:58:00 +0000
162+++ u1db/tests/c_backend_wrapper.pyx 2012-05-23 16:48:17 +0000
163@@ -116,6 +116,7 @@
164 int U1DB_NOT_IMPLEMENTED
165 int U1DB_INVALID_JSON
166 int U1DB_INVALID_VALUE_FOR_INDEX
167+ int U1DB_INVALID_GLOBBING
168 int U1DB_BROKEN_SYNC_STREAM
169 int U1DB_DUPLICATE_INDEX_NAME
170 int U1DB_INDEX_DOES_NOT_EXIST
171@@ -559,6 +560,8 @@
172 % (context,))
173 if status == U1DB_INVALID_VALUE_FOR_INDEX:
174 raise errors.InvalidValueForIndex()
175+ if status == U1DB_INVALID_GLOBBING:
176+ raise errors.InvalidGlobbing()
177 if status == U1DB_INTERNAL_ERROR:
178 raise errors.U1DBError("internal error")
179 if status == U1DB_BROKEN_SYNC_STREAM:
180
181=== modified file 'u1db/tests/commandline/test_client.py'
182--- u1db/tests/commandline/test_client.py 2012-05-23 14:20:12 +0000
183+++ u1db/tests/commandline/test_client.py 2012-05-23 16:48:17 +0000
184@@ -524,20 +524,28 @@
185 def test_get_from_index_two_expr_instead_of_one(self):
186 self.db.create_index("index", ["key1"])
187 cmd = self.make_command(client.CmdGetFromIndex)
188+ cmd.argv = ["XX", "YY"]
189 retval = cmd.run(self.db_path, "index", ["value1", "value2"])
190 self.assertEqual(retval, 1)
191 self.assertEqual(cmd.stdout.getvalue(), '')
192- self.assertEqual(cmd.stderr.getvalue(), "Invalid query; index"
193- " 'index' requires 1 query expression, not 2.\n")
194+ self.assertEqual("Invalid query: index 'index' requires"
195+ " 1 query expression, not 2.\n"
196+ "For example, the following would be valid:\n"
197+ " XX YY %r 'index' 'value1'\n"
198+ % self.db_path, cmd.stderr.getvalue())
199
200 def test_get_from_index_three_expr_instead_of_two(self):
201 self.db.create_index("index", ["key1", "key2"])
202 cmd = self.make_command(client.CmdGetFromIndex)
203+ cmd.argv = ["XX", "YY"]
204 retval = cmd.run(self.db_path, "index", ["value1", "value2", "value3"])
205 self.assertEqual(retval, 1)
206 self.assertEqual(cmd.stdout.getvalue(), '')
207- self.assertEqual(cmd.stderr.getvalue(), "Invalid query; index"
208- " 'index' requires 2 query expressions, not 3.\n")
209+ self.assertEqual("Invalid query: index 'index' requires"
210+ " 2 query expressions, not 3.\n"
211+ "For example, the following would be valid:\n"
212+ " XX YY %r 'index' 'value1' 'value2'\n"
213+ % self.db_path, cmd.stderr.getvalue())
214
215 def test_get_from_index_one_expr_instead_of_two(self):
216 self.db.create_index("index", ["key1", "key2"])
217@@ -546,21 +554,24 @@
218 retval = cmd.run(self.db_path, "index", ["value1"])
219 self.assertEqual(retval, 1)
220 self.assertEqual(cmd.stdout.getvalue(), '')
221- self.assertEqual(cmd.stderr.getvalue(), "Invalid query; index"
222- " 'index' requires 2 query expressions, not 1.\n"
223- "Perhaps you meant: XX YY %r 'value1' '*'.\n"
224- % self.db_path)
225+ self.assertEqual("Invalid query: index 'index' requires"
226+ " 2 query expressions, not 1.\n"
227+ "For example, the following would be valid:\n"
228+ " XX YY %r 'index' 'value1' '*'\n"
229+ % self.db_path, cmd.stderr.getvalue())
230
231 def test_get_from_index_cant_bad_glob(self):
232 self.db.create_index("index", ["key1", "key2"])
233 cmd = self.make_command(client.CmdGetFromIndex)
234- retval = cmd.run(self.db_path, "index", ["*", "a"])
235+ cmd.argv = ["XX", "YY"]
236+ retval = cmd.run(self.db_path, "index", ["value1*", "value2"])
237 self.assertEqual(retval, 1)
238 self.assertEqual(cmd.stdout.getvalue(), '')
239- # temp error until we split exceptions in the backend
240- # (in a later commit)
241- self.assertEqual(cmd.stderr.getvalue(), "Invalid query;"
242- " not sure how to help you (read the docs?).\n")
243+ self.assertEqual("Invalid query:"
244+ " a star can only be followed by stars.\n"
245+ "For example, the following would be valid:\n"
246+ " XX YY %r 'index' 'value1*' '*'\n"
247+ % self.db_path, cmd.stderr.getvalue())
248
249
250 class RunMainHelper(object):
251
252=== modified file 'u1db/tests/test_backends.py'
253--- u1db/tests/test_backends.py 2012-05-22 18:58:04 +0000
254+++ u1db/tests/test_backends.py 2012-05-23 16:48:17 +0000
255@@ -769,12 +769,12 @@
256
257 def test_get_from_index_illegal_wildcard_order(self):
258 self.db.create_index('test-idx', ['k1', 'k2'])
259- self.assertRaises(errors.InvalidValueForIndex,
260+ self.assertRaises(errors.InvalidGlobbing,
261 self.db.get_from_index, 'test-idx', [('*', 'v2')])
262
263 def test_get_from_index_illegal_glob_after_wildcard(self):
264 self.db.create_index('test-idx', ['k1', 'k2'])
265- self.assertRaises(errors.InvalidValueForIndex,
266+ self.assertRaises(errors.InvalidGlobbing,
267 self.db.get_from_index, 'test-idx', [('*', 'v*')])
268
269 def test_get_all_from_index(self):
270@@ -891,13 +891,13 @@
271
272 def test_get_from_index_illegal_glob_before_value(self):
273 self.db.create_index('test-idx', ['k1', 'k2'])
274- self.assertRaises(errors.InvalidValueForIndex,
275+ self.assertRaises(errors.InvalidGlobbing,
276 self.db.get_from_index, 'test-idx', [('v*', 'v2')])
277
278 def test_get_from_index_illegal_glob_after_glob(self):
279 self.db.create_index('test-idx', ['k1', 'k2'])
280- self.assertRaises(errors.InvalidValueForIndex,
281- self.db.get_from_index, 'test-idx', [('*', 'v*')])
282+ self.assertRaises(errors.InvalidGlobbing,
283+ self.db.get_from_index, 'test-idx', [('v*', 'v*')])
284
285 def test_get_from_index_with_sql_wildcards(self):
286 self.db.create_index('test-idx', ['key'])
287
288=== modified file 'u1db/tests/test_inmemory.py'
289--- u1db/tests/test_inmemory.py 2012-04-27 14:22:47 +0000
290+++ u1db/tests/test_inmemory.py 2012-05-23 16:48:17 +0000
291@@ -124,5 +124,5 @@
292 idx._find_non_wildcards, ('a', 'b'))
293 self.assertRaises(errors.InvalidValueForIndex,
294 idx._find_non_wildcards, ('a', 'b', 'c', 'd'))
295- self.assertRaises(errors.InvalidValueForIndex,
296+ self.assertRaises(errors.InvalidGlobbing,
297 idx._find_non_wildcards, ('*', 'b', 'c'))

Subscribers

People subscribed via source and target branches