Tarantool development patches archive
 help / color / mirror / Atom feed
From: Vladislav Shpilevoy <v.shpilevoy@tarantool.org>
To: tarantool-patches@freelists.org,
	Vladimir Davydov <vdavydov.dev@gmail.com>
Cc: kshcherbatov@tarantool.org
Subject: Re: [tarantool-patches] Re: [PATCH v3 3/3] Lua: implement json path access to tuple fields
Date: Sat, 14 Apr 2018 00:51:30 +0300	[thread overview]
Message-ID: <48a37669-c959-1f31-1bee-ecd85787046f@tarantool.org> (raw)
In-Reply-To: <20180413113326.3lijwwzy6dwzrgev@esperanza>

Hello. Thanks for review.

New commit message:

     lua: implement json path access to tuple fields

     Until this moment in Lua a tuple data could be accessed in 3 ways:
     - get field by field number, decode into Lua,
     - get field by field name, decode into Lua
     - decode entire tuple into Lua.

     It was impossible to decode into Lua only a part of the field to
     avoid Lua garbage creating. For example, consider the tuple:
     `{1, 2, {key1 = value1,
              key2 = {key21 = {key211 = {key2111, key2112}}}}}`
     with field names `field1`, `field2`, `field3`.

     To get `key2112` it is necessary to decode into Lua the entire
     3-th field, including `key1`, `value1`, `key2`, `key21`,
     `key211`, `key2111` using the syntax
     `key2112 = tuple.field3.key2.key21.key211[2]`.

     Now the one can use the following syntax:
     `key2112 = tuple["field3.key2.key21.key211[2]"]`. The difference
     is in placing all the path into quotes and brackets `["..."]`.
     The Tarantool goes through this path and MessagePack tuple body,
     gets the needed tuple part and decodes into Lua only it.

     The path must be valid JSON path with one exception - in
     Tarantool a path can start with `.`. For example:
     `tuple[".field3..."]` - it is done to lay emphasis that the JSON
     path here is just a suffix for the tuple.

     At the same time tuple field names still work: `tuple["field1"]`,
     `tuple.field2`.

     If the field name looks like JSON path, for example:
     `my.field.name`, then it works too. The path at first is checked
     to be a real JSON path, and if nothing is found, then the entire
     path is considered as a field name. To combine such names and
     path elements the one can use `["..."]`. For example:
     `tuple["['my.field.name'].key1.key2.['another.key.in.map']"]`.

     Closes #1285

> 
> Why did you move handling of integer index from Lua to C? AFAIU having
> it in Lua should be faster. Besides, this new function is kinda
> difficult to follow IMO as it does two things now. I'd prefer it to do
> just one thing - looking up a tuple field by path.
> 

Fixed. I returned the tuple field by number implementation as it
was before JSON path patch.


diff --git a/src/box/lua/tuple.c b/src/box/lua/tuple.c
index c10e9b253..e01c12a56 100644
--- a/src/box/lua/tuple.c
+++ b/src/box/lua/tuple.c
@@ -426,8 +426,8 @@ lbox_tuple_transform(struct lua_State *L)
   * @param L Lua state.
   * @param tuple 1-th argument on a lua stack, tuple to get field
   *        from.
- * @param path 2-th argument on lua stack. Can be field name,
- *        JSON path to a field or a field number.
+ * @param path 2-th argument on lua stack. Can be field name or a
+ *        JSON path to a field.
   *
   * @retval not nil Found field value.
   * @retval     nil A field is NULL or does not exist.
@@ -438,37 +438,16 @@ lbox_tuple_field_by_path(struct lua_State *L)
  	struct tuple *tuple = luaT_istuple(L, 1);
  	/* Is checked in Lua wrapper. */
  	assert(tuple != NULL);
-	const char *field = NULL;
-	if (lua_isnumber(L, 2)) {
-		double dbl_index = lua_tonumber(L, 2);
-		if (dbl_index != floor(dbl_index))
-			goto usage_error;
-		int index = (int) floor(dbl_index) - TUPLE_INDEX_BASE;
-		if (index >= 0) {
-			field = tuple_field(tuple, index);
-			if (field == NULL) {
-				lua_pushnil(L);
-				return 1;
-			}
-		} else {
-			lua_pushnil(L);
-			return 1;
-		}
-	} else if (lua_isstring(L, 2)) {
-		size_t len;
-		const char *path = lua_tolstring(L, 2, &len);
-		if (len == 0)
-			goto usage_error;
-		if (tuple_field_by_path(tuple, path, (uint32_t) len,
-					lua_hashstring(L, 2), &field) != 0) {
-			return luaT_error(L);
-		} else if (field == NULL) {
-			lua_pushnil(L);
-			return 1;
-		}
-	} else {
-usage_error:
-		return luaL_error(L, "Usage: tuple[<path> or number >= 1]");
+	assert(lua_isstring(L, 2));
+	size_t len;
+	const char *field = NULL, *path = lua_tolstring(L, 2, &len);
+	if (len == 0)
+		return 0;
+	if (tuple_field_by_path(tuple, path, (uint32_t) len,
+				lua_hashstring(L, 2), &field) != 0) {
+		return luaT_error(L);
+	} else if (field == NULL) {
+		return 0;
  	}
  	assert(field != NULL);
  	luamp_decode(L, luaL_msgpack_default, &field);
diff --git a/src/box/lua/tuple.lua b/src/box/lua/tuple.lua
index 0f368ba9c..63ea73e43 100644
--- a/src/box/lua/tuple.lua
+++ b/src/box/lua/tuple.lua
@@ -296,20 +296,31 @@ end

  methods["__serialize"] = tuple_totable -- encode hook for 
msgpack/yaml/json

+local tuple_field = function(tuple, field_n)
+    local field = builtin.box_tuple_field(tuple, field_n - 1)
+    if field == nil then
+        return nil
+    end
+    -- Use () to shrink stack to the first return value
+    return (msgpackffi.decode_unchecked(field))
+end
+
  ffi.metatype(tuple_t, {
      __len = function(tuple)
          return builtin.box_tuple_field_count(tuple)
      end;
      __tostring = internal.tuple.tostring;
      __index = function(tuple, key)
-        if type(key) == "string" or type(key) == "number" then
-            -- Try to get a field by json path or by [index]. If
-            -- it was not found (rc ~= 0) then return a method
-            -- from the vtable. If a collision occurred, then
-            -- fields have higher priority. For example, if a
-            -- tuple T has a field with name 'bsize', then T.bsize
-            -- returns field value, not tuple_bsize function. To
-            -- access hidden methods use
+        if type(key) == "number" then
+            return tuple_field(tuple, key)
+        elseif type(key) == "string" then
+            -- Try to get a field by JSON path. If it was not
+            -- found (rc ~= 0) then return a method from the
+            -- vtable. If a collision occurred, then fields have
+            -- higher priority. For example, if a tuple T has a
+            -- field with name 'bsize', then T.bsize returns
+            -- field value, not tuple_bsize function. To access
+            -- hidden methods use
              -- 'box.tuple.<method_name>(T, [args...])'.
              local res = tuple_field_by_path(tuple, key)
              if res ~= nil then

  reply	other threads:[~2018-04-13 21:51 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-10  8:31 [PATCH v3 0/3] Implement " Vladislav Shpilevoy
2018-04-10  8:31 ` [PATCH v3 1/3] Allow gcov on Mac Vladislav Shpilevoy
2018-04-10 10:49   ` Vladimir Davydov
     [not found] ` <f1302082b4457a03b5d2b3c44526815428de4a0e.1523349020.git.v.shpilevoy@tarantool.org>
2018-04-10 16:36   ` [PATCH v3 2/3] Introduce json_path_parser with Unicode support Vladimir Davydov
2018-04-10 18:42     ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-11  9:20       ` Vladimir Davydov
     [not found] ` <c3b64b7b4e638970864995c895bbd5f736282560.1523349020.git.v.shpilevoy@tarantool.org>
2018-04-13 11:33   ` [PATCH v3 3/3] Lua: implement json path access to tuple fields Vladimir Davydov
2018-04-13 21:51     ` Vladislav Shpilevoy [this message]
2018-04-16  8:35       ` [tarantool-patches] " Vladimir Davydov
2018-04-16 10:02         ` Vladislav Shpilevoy
2018-04-22 14:21         ` Vladislav Shpilevoy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=48a37669-c959-1f31-1bee-ecd85787046f@tarantool.org \
    --to=v.shpilevoy@tarantool.org \
    --cc=kshcherbatov@tarantool.org \
    --cc=tarantool-patches@freelists.org \
    --cc=vdavydov.dev@gmail.com \
    --subject='Re: [tarantool-patches] Re: [PATCH v3 3/3] Lua: implement json path access to tuple fields' \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox