From 35ffdced8931955f69ce1c237f8fa4e819f34991 Mon Sep 17 00:00:00 2001
From: mahsashadi <70196035+mahsashadi@users.noreply.github.com>
Date: Sun, 29 Aug 2021 10:49:37 +0430
Subject: [PATCH 01/10] Improve unserialization  of VFS URL query parameters

---
 src/vfs.js | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/src/vfs.js b/src/vfs.js
index 54d98b6..23be9b2 100644
--- a/src/vfs.js
+++ b/src/vfs.js
@@ -111,7 +111,7 @@ const createMiddleware = core => {
 };
 
 const createOptions = req => {
-  const options = req.fields.options;
+  const options = req.fields.options ? req.fields.options : decodeOptions(req.fields);
   const range = req.headers && req.headers.range;
   const session = {...req.session || {}};
   let result = options || {};
@@ -134,6 +134,30 @@ const createOptions = req => {
   };
 };
 
+const decodeOptions = (reqFileds) => {
+  let options = {};
+  let keyPath = [];
+  Object.keys(reqFileds).map((item) => {
+    keyPath = item.split('.');
+    assignObject(options, keyPath, reqFileds[item]);
+  });
+  console.log(options)
+  return options;
+};
+
+const assignObject = (obj, keyPath, value) => {
+  let lastKeyIndex = keyPath.length - 1;
+  let key;
+  for (let i = 0; i < lastKeyIndex; i++) {
+    key = keyPath[i];
+    if (!(key in obj)) {
+      obj[key] = {};
+    }
+    obj = obj[key];
+  }
+  obj[keyPath[lastKeyIndex]] = value;
+};
+
 // Standard request with only a target
 const createRequestFactory = findMountpoint => (getter, method, readOnly, respond) => async (req, res) => {
   const options = createOptions(req);

From b2bd640a6b69eadb347e200ac53a3d4fc37111cd Mon Sep 17 00:00:00 2001
From: mahsa shadi <mahsa.shadi@mail.um.ac.ir>
Date: Fri, 3 Sep 2021 11:41:14 -0400
Subject: [PATCH 02/10] add unserialization of VFS URL query parameters into
 utils

---
 src/utils/vfs.js | 31 +++++++++++++++++++++++++++++--
 src/vfs.js       | 28 ++--------------------------
 2 files changed, 31 insertions(+), 28 deletions(-)

diff --git a/src/utils/vfs.js b/src/utils/vfs.js
index e4dd10c..e02a782 100644
--- a/src/utils/vfs.js
+++ b/src/utils/vfs.js
@@ -176,10 +176,37 @@ const mountpointResolver = core => async (path) => {
  */
 const parseGet = req => {
   const {query} = url.parse(req.url, true);
-
-  return Promise.resolve({fields: query, files: {}});
+  const assembledQuery = assembleQueryData(query);
+  
+  return Promise.resolve({fields: assembledQuery, files: {}});
 };
 
+/*
+ * Assembles a given object query
+ */
+const assembleQueryData = (object) => {
+  const assembled = {}
+  const keys = Object.keys(object)
+
+  for (let i = 0; i < keys.length; i++) {
+    const key = keys[i]
+    const dots = key.split('.')
+
+    let last = assembled
+    for (let j = 0; j < dots.length; j++) {
+      const dot = dots[j]
+      if (j >= dots.length - 1) {
+        last[dot] = object[key]
+      } else {
+        last[dot] = last[dot] || {}
+      }
+
+      last = last[dot]
+    }
+  }
+  return assembled;
+}
+
 /*
  * Parses Json Body
  */
diff --git a/src/vfs.js b/src/vfs.js
index 23be9b2..17fb2be 100644
--- a/src/vfs.js
+++ b/src/vfs.js
@@ -111,7 +111,7 @@ const createMiddleware = core => {
 };
 
 const createOptions = req => {
-  const options = req.fields.options ? req.fields.options : decodeOptions(req.fields);
+  const options = req.fields.options;
   const range = req.headers && req.headers.range;
   const session = {...req.session || {}};
   let result = options || {};
@@ -134,30 +134,6 @@ const createOptions = req => {
   };
 };
 
-const decodeOptions = (reqFileds) => {
-  let options = {};
-  let keyPath = [];
-  Object.keys(reqFileds).map((item) => {
-    keyPath = item.split('.');
-    assignObject(options, keyPath, reqFileds[item]);
-  });
-  console.log(options)
-  return options;
-};
-
-const assignObject = (obj, keyPath, value) => {
-  let lastKeyIndex = keyPath.length - 1;
-  let key;
-  for (let i = 0; i < lastKeyIndex; i++) {
-    key = keyPath[i];
-    if (!(key in obj)) {
-      obj[key] = {};
-    }
-    obj = obj[key];
-  }
-  obj[keyPath[lastKeyIndex]] = value;
-};
-
 // Standard request with only a target
 const createRequestFactory = findMountpoint => (getter, method, readOnly, respond) => async (req, res) => {
   const options = createOptions(req);
@@ -321,4 +297,4 @@ module.exports = core => {
   });
 
   return {router, methods};
-};
+};
\ No newline at end of file

From 7be875504ed4d1a73b020f855b0bc07cc104bade Mon Sep 17 00:00:00 2001
From: mahsa shadi <mahsa.shadi@mail.um.ac.ir>
Date: Sat, 4 Sep 2021 09:54:59 +0430
Subject: [PATCH 03/10] export assembleQueryData method and add tests

---
 __tests__/utils/vfs.js | 32 ++++++++++++++++++++++++++++++++
 src/utils/vfs.js       | 40 ++++++++++++++++++++--------------------
 2 files changed, 52 insertions(+), 20 deletions(-)

diff --git a/__tests__/utils/vfs.js b/__tests__/utils/vfs.js
index 85e968a..ae2bef7 100644
--- a/__tests__/utils/vfs.js
+++ b/__tests__/utils/vfs.js
@@ -243,4 +243,36 @@ describe('VFS Utils', () => {
   test('parseFields - POST w/Form', () => {
     // TODO
   });
+
+  test('assembleQueryData', () => {
+    const result = utils.assembleQueryData({
+      'a': 'b',
+      'b.a': 'foo',
+      'b.b.a': 'foo',
+      'b.b.b': 'foo',
+      'b.b.c': 'foo',
+      'b.b.d': 'foo',
+      'b.b.e': 'foo',
+      'c': 'null',
+      'd': 'true',
+      'e': '1'
+    });
+
+    expect(result).toEqual({
+      a: 'b',
+      b: {
+        a: 'foo',
+        b: {
+          a: 'foo',
+          b: 'foo',
+          c: 'foo',
+          d: 'foo',
+          e: 'foo'
+        }
+      },
+      c: 'null',
+      d: 'true',
+      e: '1'
+    });
+  });
 });
diff --git a/src/utils/vfs.js b/src/utils/vfs.js
index e02a782..1e1d341 100644
--- a/src/utils/vfs.js
+++ b/src/utils/vfs.js
@@ -171,42 +171,41 @@ const mountpointResolver = core => async (path) => {
   return Object.freeze({mount, adapter});
 };
 
-/*
- * Parses URL Body
- */
-const parseGet = req => {
-  const {query} = url.parse(req.url, true);
-  const assembledQuery = assembleQueryData(query);
-  
-  return Promise.resolve({fields: assembledQuery, files: {}});
-};
-
 /*
  * Assembles a given object query
  */
 const assembleQueryData = (object) => {
-  const assembled = {}
-  const keys = Object.keys(object)
+  const assembled = {};
+  const keys = Object.keys(object);
 
   for (let i = 0; i < keys.length; i++) {
-    const key = keys[i]
-    const dots = key.split('.')
+    const key = keys[i];
+    const dots = key.split('.');
 
-    let last = assembled
+    let last = assembled;
     for (let j = 0; j < dots.length; j++) {
-      const dot = dots[j]
+      const dot = dots[j];
       if (j >= dots.length - 1) {
-        last[dot] = object[key]
+        last[dot] = object[key];
       } else {
-        last[dot] = last[dot] || {}
+        last[dot] = last[dot] || {};
       }
 
-      last = last[dot]
+      last = last[dot];
     }
   }
   return assembled;
 }
 
+/*
+ * Parses URL Body
+ */
+const parseGet = req => {
+  const {query} = url.parse(req.url, true);
+  const assembledQuery = assembleQueryData(query);
+  return Promise.resolve({fields: assembledQuery, files: {}});
+};
+
 /*
  * Parses Json Body
  */
@@ -281,5 +280,6 @@ module.exports = {
   getPrefix,
   parseFields,
   errorCodes,
-  methodArguments
+  methodArguments,
+  assembleQueryData
 };

From 3ecb734b1afafbf8982ad277ec12ea7509236e2e Mon Sep 17 00:00:00 2001
From: mahsa shadi <mahsa.shadi@mail.um.ac.ir>
Date: Sat, 4 Sep 2021 10:47:44 +0430
Subject: [PATCH 04/10] fixed some eslint newLine errors

---
 src/utils/vfs.js | 2 +-
 src/vfs.js       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/utils/vfs.js b/src/utils/vfs.js
index 1e1d341..790b86f 100644
--- a/src/utils/vfs.js
+++ b/src/utils/vfs.js
@@ -195,7 +195,7 @@ const assembleQueryData = (object) => {
     }
   }
   return assembled;
-}
+};
 
 /*
  * Parses URL Body
diff --git a/src/vfs.js b/src/vfs.js
index 17fb2be..54d98b6 100644
--- a/src/vfs.js
+++ b/src/vfs.js
@@ -297,4 +297,4 @@ module.exports = core => {
   });
 
   return {router, methods};
-};
\ No newline at end of file
+};

From d1335a2a96c5d0b4f68816c8e7cf2af87272439c Mon Sep 17 00:00:00 2001
From: mahsa shadi <mahsa.shadi@mail.um.ac.ir>
Date: Sun, 5 Sep 2021 15:31:51 -0400
Subject: [PATCH 05/10] add array support in assembleQueryData method

---
 __tests__/utils/vfs.js | 36 ++++++++++++++++++++++++++++++++++--
 src/utils/vfs.js       |  8 +++++++-
 2 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/__tests__/utils/vfs.js b/__tests__/utils/vfs.js
index ae2bef7..3a72c4d 100644
--- a/__tests__/utils/vfs.js
+++ b/__tests__/utils/vfs.js
@@ -245,7 +245,7 @@ describe('VFS Utils', () => {
   });
 
   test('assembleQueryData', () => {
-    const result = utils.assembleQueryData({
+    const result1 = utils.assembleQueryData({
       'a': 'b',
       'b.a': 'foo',
       'b.b.a': 'foo',
@@ -258,7 +258,21 @@ describe('VFS Utils', () => {
       'e': '1'
     });
 
-    expect(result).toEqual({
+    const result2 = utils.assembleQueryData({
+      'a.0': 'foo',
+      'a.1': 'foo',
+      'b.0': 'foo',
+      'b.1': 'foo',
+      'b.a': 'foo',
+      'c.a': 'foo',
+      'c.b.0': 'foo',
+      'c.b.1': 'foo',
+      'c.c.0': 'foo',
+      'c.c.1': 'foo',
+      'c.c.a': 'foo',
+    });
+
+    expect(result1).toEqual({
       a: 'b',
       b: {
         a: 'foo',
@@ -274,5 +288,23 @@ describe('VFS Utils', () => {
       d: 'true',
       e: '1'
     });
+
+    expect(result2).toEqual({
+      a: ['foo', 'foo'],
+      b:{
+        '0': 'foo',
+        '1': 'foo',
+        'a': 'foo',
+      },
+      c: {
+        a: 'foo',
+        b: ['foo', 'foo'],
+        c: {
+          '0': 'foo',
+          '1': 'foo',
+          'a': 'foo'
+        }
+      }
+    });
   });
 });
diff --git a/src/utils/vfs.js b/src/utils/vfs.js
index 790b86f..13237b7 100644
--- a/src/utils/vfs.js
+++ b/src/utils/vfs.js
@@ -183,14 +183,20 @@ const assembleQueryData = (object) => {
     const dots = key.split('.');
 
     let last = assembled;
+    let parent = null;
     for (let j = 0; j < dots.length; j++) {
       const dot = dots[j];
       if (j >= dots.length - 1) {
+        if (!/^\d+$/.test(dot) && Array.isArray(last)) {
+          last = Object.fromEntries(last.map((value, i) => [i, value]));
+          parent[dots[j - 1]] = last;
+        }
         last[dot] = object[key];
       } else {
-        last[dot] = last[dot] || {};
+        last[dot] = last[dot] || (/^\d+$/.test(dots[j + 1]) ? [] : {});
       }
 
+      parent = last;
       last = last[dot];
     }
   }

From 97f5821d22291662da722f205f17a756b5b1d53b Mon Sep 17 00:00:00 2001
From: mahsa shadi <mahsa.shadi@mail.um.ac.ir>
Date: Mon, 6 Sep 2021 14:02:47 +0430
Subject: [PATCH 06/10] Solve type casting in assembleQueryData

---
 __tests__/utils/vfs.js | 52 ++++++++++++++++++++++--------------------
 src/utils/vfs.js       | 16 ++++++++++++-
 2 files changed, 42 insertions(+), 26 deletions(-)

diff --git a/__tests__/utils/vfs.js b/__tests__/utils/vfs.js
index 3a72c4d..43ac987 100644
--- a/__tests__/utils/vfs.js
+++ b/__tests__/utils/vfs.js
@@ -203,7 +203,7 @@ describe('VFS Utils', () => {
     const parser = utils.parseFields();
 
     return expect(parser({
-      url: '/foo/?bar=baz&jazz=bass',
+      url: '/foo/?bar.s=baz&jazz.s=bass',
       method: 'get'
     }))
       .resolves
@@ -246,30 +246,31 @@ describe('VFS Utils', () => {
 
   test('assembleQueryData', () => {
     const result1 = utils.assembleQueryData({
-      'a': 'b',
-      'b.a': 'foo',
-      'b.b.a': 'foo',
-      'b.b.b': 'foo',
-      'b.b.c': 'foo',
-      'b.b.d': 'foo',
-      'b.b.e': 'foo',
-      'c': 'null',
-      'd': 'true',
-      'e': '1'
+      'a.s': 'b',
+      'b.a.s': 'foo',
+      'b.b.a.s': 'foo',
+      'b.b.b.s': 'foo',
+      'b.b.c.s': 'foo',
+      'b.b.d.s': 'foo',
+      'b.b.e.s': 'foo',
+      'c.n': 'null',
+      'd.b': 'true',
+      'e.i': '1',
+      'f.u': 'undefined'
     });
 
     const result2 = utils.assembleQueryData({
-      'a.0': 'foo',
-      'a.1': 'foo',
-      'b.0': 'foo',
-      'b.1': 'foo',
-      'b.a': 'foo',
-      'c.a': 'foo',
-      'c.b.0': 'foo',
-      'c.b.1': 'foo',
-      'c.c.0': 'foo',
-      'c.c.1': 'foo',
-      'c.c.a': 'foo',
+      'a.0.s': 'foo',
+      'a.1.s': 'foo',
+      'b.0.s': 'foo',
+      'b.1.s': 'foo',
+      'b.a.s': 'foo',
+      'c.a.s': 'foo',
+      'c.b.0.s': 'foo',
+      'c.b.1.s': 'foo',
+      'c.c.0.s': 'foo',
+      'c.c.1.s': 'foo',
+      'c.c.a.s': 'foo',
     });
 
     expect(result1).toEqual({
@@ -284,9 +285,10 @@ describe('VFS Utils', () => {
           e: 'foo'
         }
       },
-      c: 'null',
-      d: 'true',
-      e: '1'
+      c: null,
+      d: true,
+      e: 1,
+      f: undefined
     });
 
     expect(result2).toEqual({
diff --git a/src/utils/vfs.js b/src/utils/vfs.js
index 13237b7..e3c3dd9 100644
--- a/src/utils/vfs.js
+++ b/src/utils/vfs.js
@@ -42,6 +42,17 @@ const errorCodes = {
   EACCES: 401
 };
 
+/**
+ * A map of data types
+ */
+const typeMap = {
+  i: str => parseInt(str, 10),
+  s: str => str,
+  b: str => str === 'true',
+  u: str => undefined,
+  n: str => null
+};
+
 /**
  * Gets prefix of a VFS path
  */
@@ -181,6 +192,8 @@ const assembleQueryData = (object) => {
   for (let i = 0; i < keys.length; i++) {
     const key = keys[i];
     const dots = key.split('.');
+    const type = dots[dots.length - 1];
+    dots.pop();
 
     let last = assembled;
     let parent = null;
@@ -191,7 +204,7 @@ const assembleQueryData = (object) => {
           last = Object.fromEntries(last.map((value, i) => [i, value]));
           parent[dots[j - 1]] = last;
         }
-        last[dot] = object[key];
+        last[dot] = typeMap[type](object[key]);
       } else {
         last[dot] = last[dot] || (/^\d+$/.test(dots[j + 1]) ? [] : {});
       }
@@ -208,6 +221,7 @@ const assembleQueryData = (object) => {
  */
 const parseGet = req => {
   const {query} = url.parse(req.url, true);
+  console.log(query);
   const assembledQuery = assembleQueryData(query);
   return Promise.resolve({fields: assembledQuery, files: {}});
 };

From 9dacd351ade98067ed2e7fb8fb5e793059d4309c Mon Sep 17 00:00:00 2001
From: mahsa shadi <mahsa.shadi@mail.um.ac.ir>
Date: Mon, 6 Sep 2021 14:07:12 +0430
Subject: [PATCH 07/10] Remove unnecessary console.log

---
 src/utils/vfs.js | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/utils/vfs.js b/src/utils/vfs.js
index e3c3dd9..67998bf 100644
--- a/src/utils/vfs.js
+++ b/src/utils/vfs.js
@@ -221,7 +221,6 @@ const assembleQueryData = (object) => {
  */
 const parseGet = req => {
   const {query} = url.parse(req.url, true);
-  console.log(query);
   const assembledQuery = assembleQueryData(query);
   return Promise.resolve({fields: assembledQuery, files: {}});
 };

From 9e9359c550f743d3dd7d20a48a3a27dbe85ecedc Mon Sep 17 00:00:00 2001
From: mahsa shadi <mahsa.shadi@mail.um.ac.ir>
Date: Sun, 7 Nov 2021 13:42:46 +0330
Subject: [PATCH 08/10] vfs capabilities, stat totalCount, and stat totalSize
 is added

---
 src/adapters/vfs/system.js | 49 +++++++++++++++++++++++++++++---------
 src/vfs.js                 |  2 ++
 2 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/src/adapters/vfs/system.js b/src/adapters/vfs/system.js
index 1469c7d..2baf6e1 100644
--- a/src/adapters/vfs/system.js
+++ b/src/adapters/vfs/system.js
@@ -36,20 +36,35 @@ const chokidar = require('chokidar');
 /*
  * Creates an object readable by client
  */
-const createFileIter = (core, realRoot, file) => {
+const createFileIter = (core, realRoot, file, options = {}) => {
   const filename = path.basename(file);
   const realPath = path.join(realRoot, filename);
   const {mime} = core.make('osjs/vfs');
 
-  const createStat = stat => ({
-    isDirectory: stat.isDirectory(),
-    isFile: stat.isFile(),
-    mime: stat.isFile() ? mime(realPath) : null,
-    size: stat.size,
-    path: file,
-    filename,
-    stat
-  });
+  const createStat = async stat => {
+    let totalSize = 0;
+    let files = [];
+    if (stat.isDirectory()) {
+      files = await fs.readdir(realPath);
+      if(!options.showHiddenFiles) {
+        files = files.filter(f => f.substr(0, 1) !== '.');
+      }
+      const promises = files.map(f => fs.stat(path.join(realPath, f)));
+      const allPromises = await Promise.all(promises);
+      allPromises.map(s => totalSize += s.size);
+    }
+    return ({
+      isDirectory: stat.isDirectory(),
+      isFile: stat.isFile(),
+      mime: stat.isFile() ? mime(realPath) : null,
+      size: stat.size,
+      path: file,
+      totalCount: files.length,
+      totalSize: totalSize,
+      filename,
+      stat
+    });
+  };
 
   return fs.stat(realPath)
     .then(createStat)
@@ -184,9 +199,21 @@ module.exports = (core) => {
       Promise.resolve(getRealPath(core, options.session, vfs.mount, file))
         .then(realPath => {
           return fs.access(realPath, fs.F_OK)
-            .then(() => createFileIter(core, path.dirname(realPath), realPath));
+            .then(() => createFileIter(core, path.dirname(realPath), realPath, options));
         }),
 
+    /**
+     * Reads directory
+     * @param {String} root The file path from client
+     * @param {Object} [options={}] Options
+     * @return {Object[]}
+     */
+    capabilities: vfs => (file, options = {}) =>
+      Promise.resolve({
+        sort:false,
+        pagination:false
+      }),
+
     /**
      * Reads directory
      * @param {String} root The file path from client
diff --git a/src/vfs.js b/src/vfs.js
index 54d98b6..c4e8fb4 100644
--- a/src/vfs.js
+++ b/src/vfs.js
@@ -238,6 +238,7 @@ const vfs = core => {
     realpath: createRequest(requestPath, 'realpath', false),
     exists: createRequest(requestPath, 'exists', false, respondBoolean),
     stat: createRequest(requestPath, 'stat', false),
+    capabilities: createRequest(requestPath, 'capabilities', false),
     readdir: createRequest(requestPath, 'readdir', false),
     readfile: createRequest(requestPath, 'readfile', false),
     writefile: createRequest(requestFile, 'writefile', true, respondNumber),
@@ -268,6 +269,7 @@ module.exports = core => {
   // Then all VFS routes (needs implementation above)
   router.get('/exists', wrapper(methods.exists));
   router.get('/stat', wrapper(methods.stat));
+  router.get('/capabilities', wrapper(methods.capabilities));
   router.get('/readdir', wrapper(methods.readdir));
   router.get('/readfile', wrapper(methods.readfile));
   router.post('/writefile', wrapper(methods.writefile));

From 6191979f62d8c6def0828c3362e50ae48453f7b4 Mon Sep 17 00:00:00 2001
From: mahsa shadi <mahsa.shadi@mail.um.ac.ir>
Date: Sun, 7 Nov 2021 13:48:30 +0330
Subject: [PATCH 09/10] description in comment is fixed

---
 src/adapters/vfs/system.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/adapters/vfs/system.js b/src/adapters/vfs/system.js
index 2baf6e1..1a689c5 100644
--- a/src/adapters/vfs/system.js
+++ b/src/adapters/vfs/system.js
@@ -203,10 +203,10 @@ module.exports = (core) => {
         }),
 
     /**
-     * Reads directory
-     * @param {String} root The file path from client
+     * Get vfs capabilities
+     * @param {String} file The optional file path from client
      * @param {Object} [options={}] Options
-     * @return {Object[]}
+     * @return {Object}
      */
     capabilities: vfs => (file, options = {}) =>
       Promise.resolve({

From 23b3c5756e67eda6b6bfd8cf3967284db25bfe0a Mon Sep 17 00:00:00 2001
From: mahsa shadi <mahsa.shadi@mail.um.ac.ir>
Date: Sun, 24 Jul 2022 10:43:19 +0430
Subject: [PATCH 10/10] Support unserialization of VFS URL query parameters

---
 __tests__/utils/vfs.js | 63 +++++++-----------------------------------
 src/utils/vfs.js       | 48 +++++++-------------------------
 2 files changed, 20 insertions(+), 91 deletions(-)

diff --git a/__tests__/utils/vfs.js b/__tests__/utils/vfs.js
index 43ac987..7dd3e17 100644
--- a/__tests__/utils/vfs.js
+++ b/__tests__/utils/vfs.js
@@ -203,7 +203,7 @@ describe('VFS Utils', () => {
     const parser = utils.parseFields();
 
     return expect(parser({
-      url: '/foo/?bar.s=baz&jazz.s=bass',
+      url: '/foo/?bar=baz&jazz=bass',
       method: 'get'
     }))
       .resolves
@@ -246,65 +246,22 @@ describe('VFS Utils', () => {
 
   test('assembleQueryData', () => {
     const result1 = utils.assembleQueryData({
-      'a.s': 'b',
-      'b.a.s': 'foo',
-      'b.b.a.s': 'foo',
-      'b.b.b.s': 'foo',
-      'b.b.c.s': 'foo',
-      'b.b.d.s': 'foo',
-      'b.b.e.s': 'foo',
-      'c.n': 'null',
-      'd.b': 'true',
-      'e.i': '1',
-      'f.u': 'undefined'
-    });
-
-    const result2 = utils.assembleQueryData({
-      'a.0.s': 'foo',
-      'a.1.s': 'foo',
-      'b.0.s': 'foo',
-      'b.1.s': 'foo',
-      'b.a.s': 'foo',
-      'c.a.s': 'foo',
-      'c.b.0.s': 'foo',
-      'c.b.1.s': 'foo',
-      'c.c.0.s': 'foo',
-      'c.c.1.s': 'foo',
-      'c.c.a.s': 'foo',
+      'a': 'b',
+      'b': '{"a":"foo"}',
+      'c': '{"a":false,"c":null,"d":1,"e":{"a":"foo"}}'
     });
 
     expect(result1).toEqual({
       a: 'b',
       b: {
-        a: 'foo',
-        b: {
-          a: 'foo',
-          b: 'foo',
-          c: 'foo',
-          d: 'foo',
-          e: 'foo'
-        }
-      },
-      c: null,
-      d: true,
-      e: 1,
-      f: undefined
-    });
-
-    expect(result2).toEqual({
-      a: ['foo', 'foo'],
-      b:{
-        '0': 'foo',
-        '1': 'foo',
-        'a': 'foo',
+        a: 'foo'
       },
       c: {
-        a: 'foo',
-        b: ['foo', 'foo'],
-        c: {
-          '0': 'foo',
-          '1': 'foo',
-          'a': 'foo'
+        a: false,
+        c: null,
+        d: 1,
+        e: {
+          a: 'foo'
         }
       }
     });
diff --git a/src/utils/vfs.js b/src/utils/vfs.js
index 67998bf..9c6d7fc 100644
--- a/src/utils/vfs.js
+++ b/src/utils/vfs.js
@@ -42,17 +42,6 @@ const errorCodes = {
   EACCES: 401
 };
 
-/**
- * A map of data types
- */
-const typeMap = {
-  i: str => parseInt(str, 10),
-  s: str => str,
-  b: str => str === 'true',
-  u: str => undefined,
-  n: str => null
-};
-
 /**
  * Gets prefix of a VFS path
  */
@@ -185,35 +174,18 @@ const mountpointResolver = core => async (path) => {
 /*
  * Assembles a given object query
  */
-const assembleQueryData = (object) => {
-  const assembled = {};
-  const keys = Object.keys(object);
-
-  for (let i = 0; i < keys.length; i++) {
-    const key = keys[i];
-    const dots = key.split('.');
-    const type = dots[dots.length - 1];
-    dots.pop();
-
-    let last = assembled;
-    let parent = null;
-    for (let j = 0; j < dots.length; j++) {
-      const dot = dots[j];
-      if (j >= dots.length - 1) {
-        if (!/^\d+$/.test(dot) && Array.isArray(last)) {
-          last = Object.fromEntries(last.map((value, i) => [i, value]));
-          parent[dots[j - 1]] = last;
-        }
-        last[dot] = typeMap[type](object[key]);
-      } else {
-        last[dot] = last[dot] || (/^\d+$/.test(dots[j + 1]) ? [] : {});
+const assembleQueryData = (data) => {
+  const entries = Object
+    .entries(data)
+    .map(([k, v]) => {
+      try {
+        return [k, JSON.parse(v)];
+      } catch (e) {
+        return [k, v];
       }
+    });
 
-      parent = last;
-      last = last[dot];
-    }
-  }
-  return assembled;
+  return Object.fromEntries(entries);
 };
 
 /*