This is an automated email from the ASF dual-hosted git repository.

joshinnis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-age.git


The following commit(s) were added to refs/heads/master by this push:
     new 50fce50  fix: (driver/nodejs) fix problems that occur when an object 
is empty or nested. (#104)
50fce50 is described below

commit 50fce50480ff7beabf72aadf8386c10dbd6402dd
Author: Alex Kwak <[email protected]>
AuthorDate: Wed Dec 1 05:21:59 2021 +0900

    fix: (driver/nodejs) fix problems that occur when an object is empty or 
nested. (#104)
---
 drivers/nodejs/src/antlr4/CustomAgTypeListener.ts | 219 ++++++++++++++--------
 drivers/nodejs/test/Agtype.test.ts                |  36 +++-
 2 files changed, 173 insertions(+), 82 deletions(-)

diff --git a/drivers/nodejs/src/antlr4/CustomAgTypeListener.ts 
b/drivers/nodejs/src/antlr4/CustomAgTypeListener.ts
index 0319f5c..e2e662c 100644
--- a/drivers/nodejs/src/antlr4/CustomAgTypeListener.ts
+++ b/drivers/nodejs/src/antlr4/CustomAgTypeListener.ts
@@ -30,102 +30,159 @@ import { ParseTreeListener } from 
'antlr4ts/tree/ParseTreeListener'
 type MapOrArray = Map<string, any> | any[];
 
 class CustomAgTypeListener implements AgtypeListener, ParseTreeListener {
-    rootObject?: MapOrArray;
-    objectInsider: MapOrArray[] = [];
-    lastValue: any = null;
-
-    exitStringValue (ctx: StringValueContext): void {
-      this.lastValue = this.stripQuotes(ctx.text)
+  rootObject?: MapOrArray;
+  objectInsider: MapOrArray[] = [];
+  prevObject?: MapOrArray;
+  lastObject?: MapOrArray;
+  lastValue: any = undefined;
+
+  mergeArrayOrObject (key: string) {
+    if (this.prevObject instanceof Array) {
+      this.mergeArray()
+    } else {
+      this.mergeObject(key)
+    }
+  }
+
+  mergeArray () {
+    if (this.prevObject !== undefined && this.lastObject !== undefined && 
this.prevObject instanceof Array) {
+      this.prevObject.push(this.lastObject)
+      this.lastObject = this.prevObject
+      this.objectInsider.shift()
+      this.prevObject = this.objectInsider[1]
+    }
+  }
+
+  mergeObject (key: string) {
+    if (this.prevObject !== undefined && this.lastObject !== undefined && 
this.prevObject instanceof Map) {
+      this.prevObject.set(key, this.lastObject)
+      this.lastObject = this.prevObject
+      this.objectInsider.shift()
+      this.prevObject = this.objectInsider[1]
     }
-
-    exitIntegerValue (ctx: IntegerValueContext): void {
-      this.lastValue = parseInt(ctx.text)
+  }
+
+  createNewObject () {
+    const newObject = new Map()
+    this.objectInsider.unshift(newObject)
+    this.prevObject = this.lastObject
+    this.lastObject = newObject
+  }
+
+  createNewArray () {
+    const newObject: any[] = []
+    this.objectInsider.unshift(newObject)
+    this.prevObject = this.lastObject
+    this.lastObject = newObject
+  }
+
+  pushIfArray (value: any) {
+    if (this.lastObject instanceof Array) {
+      this.lastObject.push(value)
+      return true
     }
+    return false
+  }
+
+  exitStringValue (ctx: StringValueContext): void {
+    const value = this.stripQuotes(ctx.text)
+    if (!this.pushIfArray(value)) {
+      this.lastValue = value
+    }
+  }
+
+  exitIntegerValue (ctx: IntegerValueContext): void {
+    const value = parseInt(ctx.text)
+    if (!this.pushIfArray(value)) {
+      this.lastValue = value
+    }
+  }
+
+  exitFloatValue (ctx: FloatValueContext): void {
+    const value = parseFloat(ctx.text)
+    if (!this.pushIfArray(value)) {
+      this.lastValue = value
+    }
+  }
+
+  exitTrueBoolean (): void {
+    const value = true
+    if (!this.pushIfArray(value)) {
+      this.lastValue = value
+    }
+  }
+
+  exitFalseBoolean (): void {
+    const value = false
+    if (!this.pushIfArray(value)) {
+      this.lastValue = value
+    }
+  }
+
+  exitNullValue (): void {
+    const value = null
+    if (!this.pushIfArray(value)) {
+      this.lastValue = value
+    }
+  }
+
+  exitFloatLiteral (ctx: FloatLiteralContext): void {
+    const value = ctx.text
+    if (!this.pushIfArray(value)) {
+      this.lastValue = value
+    }
+  }
 
-    exitFloatValue (ctx: FloatValueContext): void {
-      this.lastValue = parseFloat(ctx.text)
-    }
+  enterObjectValue (): void {
+    this.createNewObject()
+  }
 
-    exitTrueBoolean (): void {
-      this.lastValue = true
-    }
+  enterArrayValue (): void {
+    this.createNewArray()
+  }
 
-    exitFalseBoolean (): void {
-      this.lastValue = false
-    }
+  exitObjectValue (): void {
+    this.mergeArray()
+  }
 
-    exitNullValue (): void {
-      this.lastValue = null
-    }
+  exitPair (ctx: PairContext): void {
+    const name = this.stripQuotes(ctx.STRING().text)
 
-    enterObjectValue (): void {
-      this.objectInsider.unshift(new Map())
-      this.lastValue = this.objectInsider[0]
+    if (this.lastValue !== undefined) {
+      (this.lastObject as Map<string, any>).set(name, this.lastValue)
+      this.lastValue = undefined
+    } else {
+      this.mergeArrayOrObject(name)
     }
+  }
 
-    exitObjectValue (): void {
-      if (this.objectInsider.length >= 2 && this.objectInsider[1] instanceof 
Array) {
-        const currentObject = this.objectInsider.shift()!;
-        (this.objectInsider[0]! as any[]).push(currentObject)
-      }
-    }
+  exitAgType (): void {
+    this.rootObject = this.objectInsider.shift()
+  }
 
-    enterArrayValue (): void {
-      this.objectInsider.unshift([])
-      this.lastValue = this.objectInsider[0]
-    }
+  stripQuotes (quotesString: string) {
+    return JSON.parse(quotesString)
+  }
 
-    exitArrayValue (): void {
-      if (this.objectInsider.length >= 2 && this.objectInsider[1] instanceof 
Array) {
-        // if objectInsider == Object then is pair or root
-        const currentObject = this.objectInsider.shift();
-        (this.objectInsider[0]! as any[]).push(currentObject)
-      }
-    }
+  getResult () {
+    this.objectInsider = []
+    this.prevObject = undefined
+    this.lastObject = undefined
+    this.lastValue = undefined
+    return this.rootObject
+  }
 
-    exitPair (ctx: PairContext): void {
-      const name = this.stripQuotes(ctx.STRING().text)
-
-      if (this.lastValue !== undefined) {
-        (this.objectInsider[0] as Map<string, any>).set(name, this.lastValue)
-        this.lastValue = undefined
-      } else {
-        const lastValue = this.objectInsider.shift()
-        if (this.objectInsider[0] instanceof Array) {
-          this.objectInsider[0].push(lastValue)
-        } else {
-          (this.objectInsider[0] as Map<string, any>).set(name, lastValue)
-        }
-      }
-    }
+  enterEveryRule (): void {
+  }
 
-    exitFloatLiteral (ctx: FloatLiteralContext): void {
-      this.lastValue = ctx.text
-    }
+  exitEveryRule (): void {
+  }
 
-    exitAgType (): void {
-      this.rootObject = this.objectInsider.shift()
-    }
+  visitErrorNode (): void {
+  }
 
-    stripQuotes (quotesString: string) {
-      return JSON.parse(quotesString)
-    }
-
-    getResult () {
-      return this.rootObject
-    }
-
-    enterEveryRule (): void {
-    }
-
-    exitEveryRule (): void {
-    }
-
-    visitErrorNode (): void {
-    }
-
-    visitTerminal (): void {
-    }
+  visitTerminal (): void {
+  }
 }
 
 export default CustomAgTypeListener
diff --git a/drivers/nodejs/test/Agtype.test.ts 
b/drivers/nodejs/test/Agtype.test.ts
index e19a21d..27f5f4e 100644
--- a/drivers/nodejs/test/Agtype.test.ts
+++ b/drivers/nodejs/test/Agtype.test.ts
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-import { AGTypeParse } from '../dist'
+import { AGTypeParse } from '../src'
 
 describe('Parsing', () => {
   it('Vertex', async () => {
@@ -33,6 +33,7 @@ describe('Parsing', () => {
       }))
     })))
   })
+
   it('Edge', async () => {
     expect(
       AGTypeParse('{"id": 1125899906842625, "label": "used_by", "end_id": 
844424930131970, "start_id": 844424930131969, "properties": {"quantity": 
1}}::edge')
@@ -44,6 +45,7 @@ describe('Parsing', () => {
       properties: new Map(Object.entries({ quantity: 1 }))
     })))
   })
+
   it('Path', async () => {
     expect(
       AGTypeParse('[{"id": 844424930131969, "label": "Part", "properties": 
{"part_num": "123"}}::vertex, {"id": 1125899906842625, "label": "used_by", 
"end_id": 844424930131970, "start_id": 844424930131969, "properties": 
{"quantity": 1}}::edge, {"id": 844424930131970, "label": "Part", "properties": 
{"part_num": "345"}}::vertex]::path')
@@ -67,4 +69,36 @@ describe('Parsing', () => {
       }))
     ])
   })
+
+  it('Null Properties', async () => {
+    expect(
+      AGTypeParse('{"id": 1688849860263937, "label": "car", "properties": 
{}}::vertex')
+    ).toStrictEqual(new Map<string, any>(Object.entries({
+      id: 1688849860263937,
+      label: 'car',
+      properties: new Map(Object.entries({}))
+    })))
+  })
+
+  it('Nested Agtype', () => {
+    expect(
+      AGTypeParse('{"id": 1688849860263937, "label": "car", "properties": 
{"a": {"b":{"c":{"d":[1, 2, "A"]}}}}}::vertex')
+    ).toStrictEqual(new Map<string, any>(Object.entries({
+      id: 1688849860263937,
+      label: 'car',
+      properties: new Map<string, any>(Object.entries({
+        a: new Map<string, any>(Object.entries({
+          b: new Map<string, any>(Object.entries({
+            c: new Map<string, any>(Object.entries({
+              d: [
+                1,
+                2,
+                'A'
+              ]
+            }))
+          }))
+        }))
+      }))
+    })))
+  })
 })

Reply via email to