[PATCH v3 2/7] lib: introduce a new json_path_multikey_offset helper

Kirill Shcherbatov kshcherbatov at tarantool.org
Tue Apr 2 18:49:33 MSK 2019


Introduced a new procedure json_path_multikey_offset. This helper
scans the JSON path string and returns the offset of the first character
[*] (the array index placeholder).

We need this function in the scope of the multikey index patchset to
extract the number of keys to be inserted into the index
using JSON subpath that has json_path_multikey_offset() length.

Needed for #1257
---
 src/lib/json/json.c   | 18 ++++++++++++++++++
 src/lib/json/json.h   | 10 ++++++++++
 test/unit/json.c      | 32 +++++++++++++++++++++++++++++++-
 test/unit/json.result | 12 +++++++++++-
 4 files changed, 70 insertions(+), 2 deletions(-)

diff --git a/src/lib/json/json.c b/src/lib/json/json.c
index 854158f63..2d3c35f4b 100644
--- a/src/lib/json/json.c
+++ b/src/lib/json/json.c
@@ -321,6 +321,24 @@ json_path_validate(const char *path, int path_len, int index_base)
 	return rc;
 }
 
+int
+json_path_multikey_offset(const char *path, int path_len, int index_base)
+{
+	struct json_lexer lexer;
+	json_lexer_create(&lexer, path, path_len, index_base);
+	struct json_token token;
+	int rc, last_lexer_offset = 0;
+	while ((rc = json_lexer_next_token(&lexer, &token)) == 0) {
+		if (token.type == JSON_TOKEN_ANY)
+			return last_lexer_offset;
+		else if (token.type == JSON_TOKEN_END)
+			break;
+		last_lexer_offset = lexer.offset;
+	}
+	assert(rc == 0);
+	return -1;
+}
+
 /**
  * An snprint-style helper to print an individual token key.
  */
diff --git a/src/lib/json/json.h b/src/lib/json/json.h
index c1de3e579..2cc5f7b84 100644
--- a/src/lib/json/json.h
+++ b/src/lib/json/json.h
@@ -259,6 +259,16 @@ json_path_cmp(const char *a, int a_len, const char *b, int b_len,
 int
 json_path_validate(const char *path, int path_len, int index_base);
 
+/**
+ * Scan the JSON path string and return the offset of the first
+ * character [*] (the array index placeholder).
+ * - if [*] is not found, -1 is returned.
+ * - specified JSON path must be valid
+ *   (may be tested with json_path_validate).
+ */
+int
+json_path_multikey_offset(const char *path, int path_len, int index_base);
+
 /**
  * Test if a given JSON token is a JSON tree leaf, i.e.
  * has no child nodes.
diff --git a/test/unit/json.c b/test/unit/json.c
index fd320c9eb..194e1664b 100644
--- a/test/unit/json.c
+++ b/test/unit/json.c
@@ -555,17 +555,47 @@ test_path_snprint()
 	footer();
 }
 
+void
+test_path_multikey()
+{
+	static struct {
+		const char *str;
+		int rc;
+	} test_cases[] = {
+		{"", -1},
+		{"[1]Data[1]extra[1]", -1},
+		{"[*]Data[1]extra[1]", 0},
+		{"[*]Data[*]extra[1]", 0},
+		{"[1]Data[*]extra[1]", 7},
+		{"[1]Data[1]extra[*]", 15},
+	};
+
+	header();
+	plan(lengthof(test_cases));
+	for (unsigned i = 0; i < lengthof(test_cases); i++) {
+		int rc = json_path_multikey_offset(test_cases[i].str,
+						   strlen(test_cases[i].str),
+						   INDEX_BASE);
+		is(rc, test_cases[i].rc, "Test json_path_multikey_offset with "
+		   "%s: have %d expected %d", test_cases[i].str, rc,
+		   test_cases[i].rc);
+	}
+	check_plan();
+	footer();
+}
+
 int
 main()
 {
 	header();
-	plan(5);
+	plan(6);
 
 	test_basic();
 	test_errors();
 	test_tree();
 	test_path_cmp();
 	test_path_snprint();
+	test_path_multikey();
 
 	int rc = check_plan();
 	footer();
diff --git a/test/unit/json.result b/test/unit/json.result
index 3a15e84bb..8f5fda6b1 100644
--- a/test/unit/json.result
+++ b/test/unit/json.result
@@ -1,5 +1,5 @@
 	*** main ***
-1..5
+1..6
 	*** test_basic ***
     1..71
     ok 1 - parse <[1]>
@@ -194,4 +194,14 @@ ok 4 - subtests
     ok 9 - 0-byte buffer - retval
 ok 5 - subtests
 	*** test_path_snprint: done ***
+	*** test_path_multikey ***
+    1..6
+    ok 1 - Test json_path_multikey_offset with : have -1 expected -1
+    ok 2 - Test json_path_multikey_offset with [1]Data[1]extra[1]: have -1 expected -1
+    ok 3 - Test json_path_multikey_offset with [*]Data[1]extra[1]: have 0 expected 0
+    ok 4 - Test json_path_multikey_offset with [*]Data[*]extra[1]: have 0 expected 0
+    ok 5 - Test json_path_multikey_offset with [1]Data[*]extra[1]: have 7 expected 7
+    ok 6 - Test json_path_multikey_offset with [1]Data[1]extra[*]: have 15 expected 15
+ok 6 - subtests
+	*** test_path_multikey: done ***
 	*** main: done ***
-- 
2.21.0




More information about the Tarantool-patches mailing list