gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-wallet-webex] 03/07: idb: more tests working


From: gnunet
Subject: [GNUnet-SVN] [taler-wallet-webex] 03/07: idb: more tests working
Date: Tue, 25 Jun 2019 14:31:58 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-webex.

commit 859a9e72e1e0431d729e429865d6272e2fb03ff7
Author: Florian Dold <address@hidden>
AuthorDate: Sun Jun 23 22:16:03 2019 +0200

    idb: more tests working
---
 packages/idb-bridge/src/BridgeIDBCursor.ts         |  48 ++++++++--
 .../idb-bridge/src/BridgeIDBCursorWithValue.ts     |  11 ++-
 packages/idb-bridge/src/BridgeIDBIndex.ts          |   1 -
 packages/idb-bridge/src/BridgeIDBTransaction.ts    |   3 +
 packages/idb-bridge/src/MemoryBackend.test.ts      |  65 +++++++++----
 packages/idb-bridge/src/MemoryBackend.ts           | 103 ++++++++++++---------
 packages/idb-bridge/src/backend-interface.ts       |   4 +-
 packages/idb-bridge/src/util/cmp.ts                |   2 +
 packages/idb-bridge/src/util/valueToKey.ts         |  88 +++++++++---------
 9 files changed, 206 insertions(+), 119 deletions(-)

diff --git a/packages/idb-bridge/src/BridgeIDBCursor.ts 
b/packages/idb-bridge/src/BridgeIDBCursor.ts
index 8321e2a1..ed5aa3e8 100644
--- a/packages/idb-bridge/src/BridgeIDBCursor.ts
+++ b/packages/idb-bridge/src/BridgeIDBCursor.ts
@@ -52,9 +52,9 @@ class BridgeIDBCursor {
 
   private _gotValue: boolean = false;
   private _range: CursorRange;
-  private _position = undefined; // Key of previously returned record
+  private _indexPosition = undefined; // Key of previously returned record
   private _objectStorePosition = undefined;
-  private _keyOnly: boolean = false;
+  private _keyOnly: boolean;
 
   private _source: CursorSource;
   private _direction: BridgeIDBCursorDirection;
@@ -63,6 +63,8 @@ class BridgeIDBCursor {
   private _indexName: string | undefined;
   private _objectStoreName: string;
 
+  protected _value: Value = undefined;
+
   constructor(
     source: CursorSource,
     objectStoreName: string,
@@ -128,7 +130,7 @@ class BridgeIDBCursor {
     const recordGetRequest: RecordGetRequest = {
       direction: this.direction,
       indexName: this._indexName,
-      lastIndexPosition: this._position,
+      lastIndexPosition: this._indexPosition,
       lastObjectStorePosition: this._objectStorePosition,
       limit: 1,
       range: this._range,
@@ -140,15 +142,38 @@ class BridgeIDBCursor {
 
     const { btx } = this.source._confirmActiveTransaction();
 
-    let response = await this._backend.getRecords(
-      btx,
-      recordGetRequest,
-    );
+    let response = await this._backend.getRecords(btx, recordGetRequest);
 
     if (response.count === 0) {
+      console.log("cursor is returning empty result");
       return null;
     }
 
+    if (response.count !== 1) {
+      throw Error("invariant failed");
+    }
+
+    console.log("request is:", JSON.stringify(recordGetRequest));
+    console.log("get response is:", JSON.stringify(response));
+
+    if (this._indexName !== undefined) {
+      this._key = response.indexKeys![0];
+    } else {
+      this._key = response.primaryKeys![0];
+    }
+
+    this._primaryKey = response.primaryKeys![0];
+
+    if (!this._keyOnly) {
+      this._value = response.values![0];
+    }
+
+    this._gotValue = true;
+    this._objectStorePosition = structuredClone(response.primaryKeys![0]);
+    if (response.indexKeys !== undefined && response.indexKeys.length > 0) {
+      this._indexPosition = structuredClone(response.indexKeys[0]);
+    }
+
     return this;
   }
 
@@ -171,6 +196,7 @@ class BridgeIDBCursor {
     if (this._effectiveObjectStore._deleted) {
       throw new InvalidStateError();
     }
+
     if (
       !(this.source instanceof BridgeIDBObjectStore) &&
       this.source._deleted
@@ -232,8 +258,12 @@ class BridgeIDBCursor {
 
     if (key !== undefined) {
       key = valueToKey(key);
+      let lastKey =
+        this._indexName === undefined
+          ? this._objectStorePosition
+          : this._indexPosition;
 
-      const cmpResult = compareKeys(key, this._position);
+      const cmpResult = compareKeys(key, lastKey);
 
       if (
         (cmpResult <= 0 &&
@@ -250,7 +280,7 @@ class BridgeIDBCursor {
     }
 
     const operation = async () => {
-      this._iterate(key);
+      return this._iterate(key);
     };
 
     transaction._execRequestAsync({
diff --git a/packages/idb-bridge/src/BridgeIDBCursorWithValue.ts 
b/packages/idb-bridge/src/BridgeIDBCursorWithValue.ts
index 2739a6f1..b2f23147 100644
--- a/packages/idb-bridge/src/BridgeIDBCursorWithValue.ts
+++ b/packages/idb-bridge/src/BridgeIDBCursorWithValue.ts
@@ -22,9 +22,12 @@ import {
     Value,
 } from "./util/types";
 
-class FDBCursorWithValue extends BridgeIDBCursor {
-    public value: Value = undefined;
+class BridgeIDBCursorWithValue extends BridgeIDBCursor {
 
+    get value(): Value {
+        return this._value;
+    }
+    
     constructor(
         source: CursorSource,
         objectStoreName: string,
@@ -33,7 +36,7 @@ class FDBCursorWithValue extends BridgeIDBCursor {
         direction: BridgeIDBCursorDirection,
         request?: any,
     ) {
-        super(source, objectStoreName, indexName, range, direction, request, 
true);
+        super(source, objectStoreName, indexName, range, direction, request, 
false);
     }
 
     public toString() {
@@ -41,4 +44,4 @@ class FDBCursorWithValue extends BridgeIDBCursor {
     }
 }
 
-export default FDBCursorWithValue;
+export default BridgeIDBCursorWithValue;
diff --git a/packages/idb-bridge/src/BridgeIDBIndex.ts 
b/packages/idb-bridge/src/BridgeIDBIndex.ts
index 6001bc05..8179be83 100644
--- a/packages/idb-bridge/src/BridgeIDBIndex.ts
+++ b/packages/idb-bridge/src/BridgeIDBIndex.ts
@@ -19,7 +19,6 @@ import BridgeIDBCursorWithValue from 
"./BridgeIDBCursorWithValue";
 import BridgeIDBKeyRange from "./BridgeIDBKeyRange";
 import BridgeIDBObjectStore from "./BridgeIDBObjectStore";
 import BridgeIDBRequest from "./BridgeIDBRequest";
-import enforceRange from "./util/enforceRange";
 import {
   ConstraintError,
   InvalidStateError,
diff --git a/packages/idb-bridge/src/BridgeIDBTransaction.ts 
b/packages/idb-bridge/src/BridgeIDBTransaction.ts
index 09f324df..a9f0201d 100644
--- a/packages/idb-bridge/src/BridgeIDBTransaction.ts
+++ b/packages/idb-bridge/src/BridgeIDBTransaction.ts
@@ -215,6 +215,9 @@ class BridgeIDBTransaction extends FakeEventTarget {
         let event;
         try {
           const result = await operation();
+          if (BridgeIDBFactory.enableTracing) {
+            console.log("TRACE: tx operation finished with success");
+          }
           request.readyState = "done";
           request.result = result;
           request.error = undefined;
diff --git a/packages/idb-bridge/src/MemoryBackend.test.ts 
b/packages/idb-bridge/src/MemoryBackend.test.ts
index 213bff75..c882b976 100644
--- a/packages/idb-bridge/src/MemoryBackend.test.ts
+++ b/packages/idb-bridge/src/MemoryBackend.test.ts
@@ -4,7 +4,8 @@ import BridgeIDBFactory from "./BridgeIDBFactory";
 import BridgeIDBRequest from "./BridgeIDBRequest";
 import BridgeIDBDatabase from "./BridgeIDBDatabase";
 import BridgeIDBTransaction from "./BridgeIDBTransaction";
-
+import BridgeIDBKeyRange from "./BridgeIDBKeyRange";
+import BridgeIDBCursorWithValue from "./BridgeIDBCursorWithValue";
 
 function promiseFromRequest(request: BridgeIDBRequest): Promise<any> {
   return new Promise((resolve, reject) => {
@@ -17,11 +18,13 @@ function promiseFromRequest(request: BridgeIDBRequest): 
Promise<any> {
   });
 }
 
-function promiseFromTransaction(transaction: BridgeIDBTransaction): 
Promise<any> {
+function promiseFromTransaction(
+  transaction: BridgeIDBTransaction,
+): Promise<any> {
   return new Promise((resolve, reject) => {
     console.log("attaching event handlers");
     transaction.oncomplete = () => {
-      console.log("oncomplete was called from promise")
+      console.log("oncomplete was called from promise");
       resolve();
     };
     transaction.onerror = () => {
@@ -51,7 +54,6 @@ test("Spec: Example 1 Part 1", async t => {
   t.pass();
 });
 
-
 test("Spec: Example 1 Part 2", async t => {
   const backend = new MemoryBackend();
   const idb = new BridgeIDBFactory(backend);
@@ -70,21 +72,20 @@ test("Spec: Example 1 Part 2", async t => {
 
   const tx = db.transaction("books", "readwrite");
   tx.oncomplete = () => {
-    console.log("oncomplete called")
+    console.log("oncomplete called");
   };
 
   const store = tx.objectStore("books");
-  
-  store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
-  store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
-  store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});
+
+  store.put({ title: "Quarry Memories", author: "Fred", isbn: 123456 });
+  store.put({ title: "Water Buffaloes", author: "Fred", isbn: 234567 });
+  store.put({ title: "Bedrock Nights", author: "Barney", isbn: 345678 });
 
   await promiseFromTransaction(tx);
 
   t.pass();
 });
 
-
 test("Spec: Example 1 Part 3", async t => {
   const backend = new MemoryBackend();
   const idb = new BridgeIDBFactory(backend);
@@ -102,15 +103,12 @@ test("Spec: Example 1 Part 3", async t => {
   t.is(db.name, "library");
 
   const tx = db.transaction("books", "readwrite");
-  tx.oncomplete = () => {
-    console.log("oncomplete called")
-  };
 
   const store = tx.objectStore("books");
-  
-  store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
-  store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
-  store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});
+
+  store.put({ title: "Bedrock Nights", author: "Barney", isbn: 345678 });
+  store.put({ title: "Quarry Memories", author: "Fred", isbn: 123456 });
+  store.put({ title: "Water Buffaloes", author: "Fred", isbn: 234567 });
 
   await promiseFromTransaction(tx);
 
@@ -122,5 +120,38 @@ test("Spec: Example 1 Part 3", async t => {
 
   t.is(result2.author, "Barney");
 
+  const tx3 = db.transaction(["books"], "readonly");
+  const store3 = tx3.objectStore("books");
+  const index3 = store3.index("by_author");
+  const request3 = index3.openCursor(BridgeIDBKeyRange.only("Fred"));
+
+  await promiseFromRequest(request3);
+
+  let cursor: BridgeIDBCursorWithValue;
+  cursor = request3.result as BridgeIDBCursorWithValue;
+  t.is(cursor.value.author, "Fred");
+  t.is(cursor.value.isbn, 123456);
+
+  cursor.continue();
+
+  await promiseFromRequest(request3);
+
+  cursor = request3.result as BridgeIDBCursorWithValue;
+  t.is(cursor.value.author, "Fred");
+  t.is(cursor.value.isbn, 234567);
+
+  await promiseFromTransaction(tx3);
+
+  const tx4 = db.transaction("books", "readonly");
+  const store4 = tx4.objectStore("books");
+  const request4 = store4.openCursor();
+
+  await promiseFromRequest(request4);
+
+  cursor = request4.result;
+  t.is(cursor.value.isbn, 123456);
+
+  db.close();
+
   t.pass();
 });
diff --git a/packages/idb-bridge/src/MemoryBackend.ts 
b/packages/idb-bridge/src/MemoryBackend.ts
index 83197488..75e583a8 100644
--- a/packages/idb-bridge/src/MemoryBackend.ts
+++ b/packages/idb-bridge/src/MemoryBackend.ts
@@ -132,8 +132,11 @@ function nextStoreKey<T>(
   return res[1].primaryKey;
 }
 
-
-function furthestKey(forward: boolean, key1: Key | undefined, key2: Key | 
undefined) {
+function furthestKey(
+  forward: boolean,
+  key1: Key | undefined,
+  key2: Key | undefined,
+) {
   if (key1 === undefined) {
     return key2;
   }
@@ -668,6 +671,7 @@ export class MemoryBackend implements Backend {
   ): Promise<RecordGetResponse> {
     if (this.enableTracing) {
       console.log(`TRACING: getRecords`);
+      console.log("query", req);
     }
     const myConn = this.connectionsByTransaction[btx.transactionCookie];
     if (!myConn) {
@@ -687,15 +691,15 @@ export class MemoryBackend implements Backend {
 
     let range;
     if (req.range == null || req.range === undefined) {
-      range = new BridgeIDBKeyRange(null, null, true, true);
+      range = new BridgeIDBKeyRange(undefined, undefined, true, true);
     } else {
       range = req.range;
     }
 
     let numResults = 0;
     let indexKeys: Key[] = [];
-    let primaryKeys = [];
-    let values = [];
+    let primaryKeys: Key[] = [];
+    let values: Value[] = [];
 
     const forward: boolean =
       req.direction === "next" || req.direction === "nextunique";
@@ -797,8 +801,6 @@ export class MemoryBackend implements Backend {
         primkeySubPos = forward ? 0 : indexEntry.primaryKeys.length - 1;
       }
 
-      // FIXME: filter out duplicates
-
       while (1) {
         if (req.limit != 0 && numResults == req.limit) {
           break;
@@ -821,6 +823,16 @@ export class MemoryBackend implements Backend {
             break;
           }
         }
+        if (
+          unique &&
+          indexKeys.length > 0 &&
+          compareKeys(indexEntry.indexKey, indexKeys[indexKeys.length - 1]) ===
+            0
+        ) {
+          // We only return the first result if subsequent index keys are the 
same.
+          continue;
+        }
+        indexKeys.push(indexEntry.indexKey);
         primaryKeys.push(indexEntry.primaryKeys[primkeySubPos]);
         numResults++;
         primkeySubPos = forward ? 0 : indexEntry.primaryKeys.length - 1;
@@ -850,48 +862,53 @@ export class MemoryBackend implements Backend {
 
       storePos = furthestKey(forward, req.advancePrimaryKey, storePos);
 
-      // Advance store position if we are either still at the last returned
-      // store key, or if we are currently not on a key.
-      const storeEntry = storeData.get(storePos);
-      if (
-        !storeEntry ||
-        (req.lastObjectStorePosition !== undefined &&
-          compareKeys(req.lastObjectStorePosition, storeEntry.primaryKey))
-      ) {
-        storePos = storeData.nextHigherKey(storePos);
+      if (storePos !== null && storePos !== undefined) {
+        // Advance store position if we are either still at the last returned
+        // store key, or if we are currently not on a key.
+        const storeEntry = storeData.get(storePos);
+        if (
+          !storeEntry ||
+          (req.lastObjectStorePosition !== undefined &&
+            compareKeys(req.lastObjectStorePosition, storeEntry.primaryKey))
+        ) {
+          storePos = storeData.nextHigherKey(storePos);
+        }
+      } else {
+        storePos = forward ? storeData.minKey() : storeData.maxKey();
+        console.log("setting starting store store pos to", storePos);
       }
 
-      if (req.lastObjectStorePosition)
-        while (1) {
-          if (req.limit != 0 && numResults == req.limit) {
-            break;
-          }
-          if (storePos === null || storePos === undefined) {
-            break;
-          }
-          if (!range.includes(storePos)) {
-            break;
-          }
+      while (1) {
+        if (req.limit != 0 && numResults == req.limit) {
+          break;
+        }
+        if (storePos === null || storePos === undefined) {
+          break;
+        }
+        if (!range.includes(storePos)) {
+          break;
+        }
 
-          const res = storeData.get(storePos);
+        const res = storeData.get(storePos);
 
-          if (!res) {
-            break;
-          }
+        if (res === undefined) {
+          break;
+        }
 
-          if (req.resultLevel >= ResultLevel.OnlyKeys) {
-            primaryKeys.push(res.primaryKey);
-          }
+        if (req.resultLevel >= ResultLevel.OnlyKeys) {
+          primaryKeys.push(structuredClone(storePos));
+        }
 
-          if (req.resultLevel >= ResultLevel.Full) {
-            values.push(res.value);
-          }
-          numResults++;
-          storePos = nextStoreKey(forward, storeData, storePos);
+        if (req.resultLevel >= ResultLevel.Full) {
+          values.push(res);
         }
+
+        numResults++;
+        storePos = nextStoreKey(forward, storeData, storePos);
+      }
     }
     if (this.enableTracing) {
-      console.log(`TRACING: getRecords got ${numResults} results`)
+      console.log(`TRACING: getRecords got ${numResults} results`);
     }
     return {
       count: numResults,
@@ -962,7 +979,7 @@ export class MemoryBackend implements Backend {
     }
   }
 
-  insertIntoIndex(
+  private insertIntoIndex(
     index: Index,
     primaryKey: Key,
     value: Value,
@@ -987,7 +1004,9 @@ export class MemoryBackend implements Backend {
         } else {
           const newIndexRecord = {
             indexKey: indexKey,
-            primaryKeys: [primaryKey].concat(existingRecord.primaryKeys),
+            primaryKeys: [primaryKey]
+              .concat(existingRecord.primaryKeys)
+              .sort(compareKeys),
           };
           index.modifiedData = indexData.with(indexKey, newIndexRecord, true);
         }
diff --git a/packages/idb-bridge/src/backend-interface.ts 
b/packages/idb-bridge/src/backend-interface.ts
index c963b189..ab093d9c 100644
--- a/packages/idb-bridge/src/backend-interface.ts
+++ b/packages/idb-bridge/src/backend-interface.ts
@@ -36,9 +36,9 @@ export interface DatabaseTransaction {
 }
 
 export enum ResultLevel {
-  Full,
-  OnlyKeys,
   OnlyCount,
+  OnlyKeys,
+  Full,
 }
 
 export interface RecordGetRequest {
diff --git a/packages/idb-bridge/src/util/cmp.ts 
b/packages/idb-bridge/src/util/cmp.ts
index 9d0dc99a..078c0a9b 100644
--- a/packages/idb-bridge/src/util/cmp.ts
+++ b/packages/idb-bridge/src/util/cmp.ts
@@ -39,6 +39,8 @@ const getType = (x: any) => {
 
 // https://w3c.github.io/IndexedDB/#compare-two-keys
 const compareKeys = (first: any, second: any): -1 | 0 | 1 => {
+    console.log("comparing keys", first, second);
+    
     if (second === undefined) {
         throw new TypeError();
     }
diff --git a/packages/idb-bridge/src/util/valueToKey.ts 
b/packages/idb-bridge/src/util/valueToKey.ts
index 3a9e3678..85c8c409 100644
--- a/packages/idb-bridge/src/util/valueToKey.ts
+++ b/packages/idb-bridge/src/util/valueToKey.ts
@@ -14,57 +14,57 @@
  permissions and limitations under the License.
  */
 
-
 import { DataError } from "./errors";
 import { Key } from "./types";
 
 // https://w3c.github.io/IndexedDB/#convert-a-value-to-a-input
 function valueToKey(input: any, seen?: Set<object>): Key | Key[] {
-    if (typeof input === "number") {
-        if (isNaN(input)) {
-            throw new DataError();
-        }
-        return input;
-    } else if (input instanceof Date) {
-        const ms = input.valueOf();
-        if (isNaN(ms)) {
-            throw new DataError();
-        }
-        return new Date(ms);
-    } else if (typeof input === "string") {
-        return input;
-    } else if (
-        input instanceof ArrayBuffer ||
-        (typeof ArrayBuffer !== "undefined" &&
-            ArrayBuffer.isView &&
-            ArrayBuffer.isView(input))
-    ) {
-        if (input instanceof ArrayBuffer) {
-            return new Uint8Array(input).buffer;
-        }
-        return new Uint8Array(input.buffer).buffer;
-    } else if (Array.isArray(input)) {
-        if (seen === undefined) {
-            seen = new Set();
-        } else if (seen.has(input)) {
-            throw new DataError();
-        }
-        seen.add(input);
+  if (typeof input === "number") {
+    if (isNaN(input)) {
+      throw new DataError();
+    }
+    return input;
+  } else if (input instanceof Date) {
+    const ms = input.valueOf();
+    if (isNaN(ms)) {
+      throw new DataError();
+    }
+    return new Date(ms);
+  } else if (typeof input === "string") {
+    return input;
+  } else if (
+    input instanceof ArrayBuffer ||
+    (typeof ArrayBuffer !== "undefined" &&
+      ArrayBuffer.isView &&
+      ArrayBuffer.isView(input))
+  ) {
+    if (input instanceof ArrayBuffer) {
+      return new Uint8Array(input).buffer;
+    }
+    return new Uint8Array(input.buffer).buffer;
+  } else if (Array.isArray(input)) {
+    if (seen === undefined) {
+      seen = new Set();
+    } else if (seen.has(input)) {
+      throw new DataError();
+    }
+    seen.add(input);
 
-        const keys = [];
-        for (let i = 0; i < input.length; i++) {
-            const hop = input.hasOwnProperty(i);
-            if (!hop) {
-                throw new DataError();
-            }
-            const entry = input[i];
-            const key = valueToKey(entry, seen);
-            keys.push(key);
-        }
-        return keys;
-    } else {
+    const keys = [];
+    for (let i = 0; i < input.length; i++) {
+      const hop = input.hasOwnProperty(i);
+      if (!hop) {
         throw new DataError();
+      }
+      const entry = input[i];
+      const key = valueToKey(entry, seen);
+      keys.push(key);
     }
-};
+    return keys;
+  } else {
+    
+    throw new DataError();
+  }
+}
 
 export default valueToKey;

-- 
To stop receiving notification emails like this one, please contact
address@hidden.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]