gnunet-svn
[Top][All Lists]
Advanced

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

[GNUnet-SVN] [taler-wallet-webex] 02/03: memidb work in progress


From: gnunet
Subject: [GNUnet-SVN] [taler-wallet-webex] 02/03: memidb work in progress
Date: Sun, 04 Jun 2017 17:56:59 +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 e0e496b87837080b98caa002725768a497836c9f
Author: Florian Dold <address@hidden>
AuthorDate: Sun Jun 4 01:14:05 2017 +0200

    memidb work in progress
---
 node_modules/nyc/node_modules/yargs/package.json | 138 +++++++--
 package.json                                     |   1 +
 src/memidb-test.ts                               | 114 ++++++++
 src/memidb.ts                                    | 352 ++++++++++++++++++++---
 tsconfig.json                                    |   1 +
 yarn.lock                                        |   4 +
 6 files changed, 545 insertions(+), 65 deletions(-)

diff --git a/node_modules/nyc/node_modules/yargs/package.json 
b/node_modules/nyc/node_modules/yargs/package.json
index a396ea7b..42fa3bd3 100644
--- a/node_modules/nyc/node_modules/yargs/package.json
+++ b/node_modules/nyc/node_modules/yargs/package.json
@@ -1,16 +1,57 @@
 {
-  "name": "yargs",
-  "version": "7.1.0",
-  "description": "yargs the modern, pirate-themed, successor to optimist.",
-  "main": "./index.js",
-  "files": [
-    "index.js",
-    "yargs.js",
-    "lib",
-    "locales",
-    "completion.sh.hbs",
-    "LICENSE"
+  "_args": [
+    [
+      {
+        "raw": "address@hidden",
+        "scope": null,
+        "escapedName": "yargs",
+        "name": "yargs",
+        "rawSpec": "^7.1.0",
+        "spec": ">=7.1.0 <8.0.0",
+        "type": "range"
+      },
+      "/Users/benjamincoe/oss/nyc"
+    ]
+  ],
+  "_from": "yargs@>=7.1.0 <8.0.0",
+  "_id": "address@hidden",
+  "_inCache": true,
+  "_location": "/yargs",
+  "_nodeVersion": "6.9.5",
+  "_npmOperationalInternal": {
+    "host": "packages-12-west.internal.npmjs.com",
+    "tmp": "tmp/yargs-7.1.0.tgz_1492119927787_0.18849953636527061"
+  },
+  "_npmUser": {
+    "name": "bcoe",
+    "email": "address@hidden"
+  },
+  "_npmVersion": "4.5.0",
+  "_phantomChildren": {
+    "string-width": "1.0.2",
+    "strip-ansi": "3.0.1",
+    "wrap-ansi": "2.1.0"
+  },
+  "_requested": {
+    "raw": "address@hidden",
+    "scope": null,
+    "escapedName": "yargs",
+    "name": "yargs",
+    "rawSpec": "^7.1.0",
+    "spec": ">=7.1.0 <8.0.0",
+    "type": "range"
+  },
+  "_requiredBy": [
+    "/"
   ],
+  "_resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz";,
+  "_shasum": "6ba318eb16961727f5d284f8ea003e8d6154d0c8",
+  "_shrinkwrap": null,
+  "_spec": "address@hidden",
+  "_where": "/Users/benjamincoe/oss/nyc",
+  "bugs": {
+    "url": "https://github.com/yargs/yargs/issues";
+  },
   "dependencies": {
     "camelcase": "^3.0.0",
     "cliui": "^3.2.0",
@@ -26,6 +67,7 @@
     "y18n": "^3.2.1",
     "yargs-parser": "^5.0.0"
   },
+  "description": "yargs the modern, pirate-themed, successor to optimist.",
   "devDependencies": {
     "chai": "^3.4.1",
     "chalk": "^1.1.3",
@@ -41,22 +83,31 @@
     "standard-version": "^3.0.0",
     "which": "^1.2.9"
   },
-  "scripts": {
-    "pretest": "standard",
-    "test": "nyc --cache mocha --require ./test/before.js --timeout=8000 
--check-leaks",
-    "coverage": "nyc report --reporter=text-lcov | coveralls",
-    "release": "standard-version"
+  "directories": {},
+  "dist": {
+    "shasum": "6ba318eb16961727f5d284f8ea003e8d6154d0c8",
+    "tarball": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz";
   },
-  "repository": {
-    "type": "git",
-    "url": "http://github.com/yargs/yargs.git";
+  "engine": {
+    "node": ">=0.10"
   },
-  "homepage": "http://yargs.js.org/";,
-  "standard": {
+  "files": [
+    "index.js",
+    "yargs.js",
+    "lib",
+    "locales",
+    "completion.sh.hbs",
+    "LICENSE"
+  ],
+  "gitHead": "e7359d632595c3a5fcfd691994859b66e8943c85",
+  "greenkeeper": {
     "ignore": [
-      "**/example/**"
+      "string-width",
+      "read-pkg-up",
+      "camelcase"
     ]
   },
+  "homepage": "http://yargs.js.org/";,
   "keywords": [
     "argument",
     "args",
@@ -67,14 +118,43 @@
     "command"
   ],
   "license": "MIT",
-  "engine": {
-    "node": ">=0.10"
+  "main": "./index.js",
+  "maintainers": [
+    {
+      "name": "bcoe",
+      "email": "address@hidden"
+    },
+    {
+      "name": "chevex",
+      "email": "address@hidden"
+    },
+    {
+      "name": "nexdrew",
+      "email": "address@hidden"
+    },
+    {
+      "name": "nylen",
+      "email": "address@hidden"
+    }
+  ],
+  "name": "yargs",
+  "optionalDependencies": {},
+  "readme": "  yargs\n========\n\nYargs be a node.js library fer hearties 
tryin' ter parse optstrings.\n\nWith yargs, ye be havin' a map that leads 
straight to yer treasure! Treasure of course, being a simple option 
hash.\n\n[![Build Status][travis-image]][travis-url]\n[![Coverage 
Status][coveralls-image]][coveralls-url]\n[![NPM 
version][npm-image]][npm-url]\n[![Windows 
Tests][windows-image]][windows-url]\n[![js-standard-style][standard-image]][standard-url]\n[![Conventional
 Commits][con [...]
+  "readmeFilename": "README.md",
+  "repository": {
+    "type": "git",
+    "url": "git+ssh://address@hidden/yargs/yargs.git"
   },
-  "greenkeeper": {
+  "scripts": {
+    "coverage": "nyc report --reporter=text-lcov | coveralls",
+    "pretest": "standard",
+    "release": "standard-version",
+    "test": "nyc --cache mocha --require ./test/before.js --timeout=8000 
--check-leaks"
+  },
+  "standard": {
     "ignore": [
-      "string-width",
-      "read-pkg-up",
-      "camelcase"
+      "**/example/**"
     ]
-  }
+  },
+  "version": "7.1.0"
 }
diff --git a/package.json b/package.json
index 0bf0ae3c..b4b79b6a 100644
--- a/package.json
+++ b/package.json
@@ -47,6 +47,7 @@
     "pogen": "file:tooling/pogen/",
     "react": "^15.5.4",
     "react-dom": "^15.5.4",
+    "structured-clone": "^0.2.2",
     "through2": "^2.0.1",
     "ts-loader": "^2.0.3",
     "tslint": "^5.3.2",
diff --git a/src/memidb-test.ts b/src/memidb-test.ts
new file mode 100644
index 00000000..8f8498a6
--- /dev/null
+++ b/src/memidb-test.ts
@@ -0,0 +1,114 @@
+/*
+ This file is part of TALER
+ (C) 2017 Inria and GNUnet e.V.
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
+ */
+
+import {test} from "ava";
+import * as memidb from "./memidb";
+
+test.cb("db open", (t) => {
+  let ncb = 0;
+  const idb = new memidb.MemoryIDBFactory();
+  const req = idb.open("testdb");
+  let called = false;
+  req.onupgradeneeded = (evt) => {
+    ncb += 1;
+    called = true;
+    t.is(req.result, evt.target);
+    t.is(evt.oldVersion, 0);
+    t.is(evt.newVersion, 1);
+    t.truthy(req.result);
+    t.pass();
+  }
+  req.onsuccess = (evt) => {
+    t.is(ncb, 1);
+    t.is(req.result, evt.target);
+    t.truthy(req.result);
+    t.end();
+  }
+});
+
+test.cb("store creation", (t) => {
+  const idb = new memidb.MemoryIDBFactory();
+  const req = idb.open("testdb");
+  req.onupgradeneeded = (evt) => {
+    const db: IDBDatabase = req.result;
+
+    const store1 = db.createObjectStore("b-store");
+    t.is(store1.name, "b-store");
+    t.deepEqual(Array.from(db.objectStoreNames), ["b-store"]);
+
+    const store2 = db.createObjectStore("a-store");
+    t.is(store2.name, "a-store");
+    t.deepEqual(Array.from(db.objectStoreNames), ["a-store", "b-store"]);
+
+    const store3 = db.createObjectStore("c-store");
+    t.is(store3.name, "c-store");
+    t.deepEqual(Array.from(db.objectStoreNames), ["a-store", "b-store", 
"c-store"]);
+    t.pass();
+  }
+  req.onsuccess = (evt) => {
+    t.end();
+  }
+});
+
+
+test.cb("put and get", (t) => {
+  const idb = new memidb.MemoryIDBFactory();
+  const req = idb.open("testdb");
+  req.onupgradeneeded = (evt) => {
+    const db: IDBDatabase = req.result;
+    const store1 = db.createObjectStore("mystore");
+    store1.put({answer: 42}, "a");
+  }
+  req.onsuccess = (evt) => {
+    t.end()
+  }
+});
+
+
+test("key path evaluation", (t) => {
+  const obj = {
+    a: {
+      b: {
+        c: 42,
+      },
+    },
+    b: "hello",
+    "": "spam",
+    arr: ["foo", "bar"],
+  }
+  t.deepEqual(memidb.evaluateKeyPath(obj, ""), obj);
+  t.deepEqual(memidb.evaluateKeyPath(obj, "a.b.c"), 42);
+  t.deepEqual(memidb.evaluateKeyPath(obj, "a.b"), {c: 42});
+  t.deepEqual(memidb.evaluateKeyPath(obj, "foo"), undefined);
+  t.deepEqual(memidb.evaluateKeyPath(obj, ["a.b.c", "foo"]), undefined);
+  t.deepEqual(memidb.evaluateKeyPath(obj, ["a.b.c", "b"]), [42, "hello"]);
+  t.deepEqual(memidb.evaluateKeyPath(obj, "arr.0"), "foo");
+  t.deepEqual(memidb.evaluateKeyPath(obj, "."), "spam");
+});
+
+test("key path evaluation with replacement", (t) => {
+  const obj: any = {
+    a: {
+      b: {
+        c: 42,
+      },
+    },
+  }
+  memidb.evaluateKeyPath(obj, "a.b.c", 24);
+  t.is(obj.a.b.c, 24);
+  memidb.evaluateKeyPath(obj, "a.b", 24);
+  t.is(obj.a.b, 24);
+});
diff --git a/src/memidb.ts b/src/memidb.ts
index 36607d71..14a1efbe 100644
--- a/src/memidb.ts
+++ b/src/memidb.ts
@@ -29,20 +29,25 @@
 
 
 const structuredClone = require("structured-clone");
-const structuredSerialize = require("structured-clone").serialize;
 
 
-interface StoredObject {
-  key: any;
-  object: string;
-}
-
 interface Store {
   name: string;
-  keyPath: string | string[];
+  keyPath?: string | string[];
   keyGenerator: number;
   autoIncrement: boolean;
-  objects: { [strKey: string]: StoredObject };
+  objects: { [primaryKey: string]: any };
+  indices: { [indexName: string]: Index };
+}
+
+interface Index {
+  multiEntry: boolean;
+  unique: boolean;
+
+  /**
+   * Map the index's key to the primary key.
+   */
+  map: { [indexKey: string]: string[] };
 }
 
 
@@ -80,11 +85,80 @@ class MyDomStringList extends Array<string> implements 
DOMStringList {
 }
 
 
-function callEventHandler(h: EventListenerOrEventListenerObject, evt: Event, 
target: any) {
-  if ("handleEvent" in h) {
-    (h as EventListenerObject).handleEvent(evt);
-  } else {
-    (h as EventListener).call(target, evt);
+class MyKeyRange implements IDBKeyRange {
+  static only(value: any): IDBKeyRange {
+    return new MyKeyRange(value, value, false, false);
+  }
+
+  static bound(lower: any, upper: any, lowerOpen: boolean = false, upperOpen: 
boolean = false) {
+    return new MyKeyRange(lower, upper, lowerOpen, upperOpen);
+  }
+
+  static lowerBound(lower: any, lowerOpen: boolean = false) {
+    return new MyKeyRange(lower, undefined, lowerOpen, true);
+  }
+
+  static upperBound(upper: any, upperOpen: boolean = false) {
+    return new MyKeyRange(undefined, upper, true, upperOpen);
+  }
+
+  constructor(public lower: any, public upper: any, public lowerOpen: boolean, 
public upperOpen: boolean) {
+  }
+}
+
+
+/**
+ * Type guard for an IDBKeyRange.
+ */
+export function isKeyRange(obj: any): obj is IDBKeyRange {
+  return (typeof obj === "object" &&
+          "lower" in obj && "upper" in obj &&
+          "lowerOpen" in obj && "upperOpen" in obj);
+}
+
+
+class IndexHandle implements IDBIndex {
+
+  _unique: boolean;
+  _multiEntry: boolean;
+
+  get keyPath(): string | string[] {
+    throw Error("not implemented");
+  }
+
+  get name () {
+    return this.indexName;
+  }
+
+  get unique() {
+    return this._unique;
+  }
+
+  get multiEntry() {
+    return this._multiEntry;
+  }
+
+  constructor(public objectStore: MyObjectStore, public indexName: string) {
+  }
+
+  count(key?: IDBKeyRange | IDBValidKey): IDBRequest {
+    throw Error("not implemented");
+  }
+
+  get(key: IDBKeyRange | IDBValidKey): IDBRequest {
+    throw Error("not implemented");
+  }
+
+  getKey(key: IDBKeyRange | IDBValidKey): IDBRequest {
+    throw Error("not implemented");
+  }
+
+  openCursor(range?: IDBKeyRange | IDBValidKey, direction?: 
IDBCursorDirection): IDBRequest {
+    throw Error("not implemented");
+  }
+
+  openKeyCursor(range?: IDBKeyRange | IDBValidKey, direction?: 
IDBCursorDirection): IDBRequest {
+    throw Error("not implemented");
   }
 }
 
@@ -92,9 +166,10 @@ class MyRequest implements IDBRequest {
   onerror: (this: IDBRequest, ev: Event) => any;
 
   onsuccess: (this: IDBRequest, ev: Event) => any;
-  successHandlers: Array<(this: IDBRequest, ev: Event) => any>;
+  successHandlers: Array<(this: IDBRequest, ev: Event) => any> = [];
 
   done: boolean = false;
+  _result: any;
 
   constructor(public _transaction: Transaction, public runner: () => void) {
   }
@@ -113,7 +188,7 @@ class MyRequest implements IDBRequest {
   }
 
   get result(): any {
-    return null;
+    return this._result;
   }
 
   get source() {
@@ -188,17 +263,78 @@ class OpenDBRequest extends MyRequest implements 
IDBOpenDBRequest {
   }
 }
 
+function follow(x: any, s: string, replacement?: any): any {
+  if (s === "") {
+    return x;
+  }
+  const ptIdx = s.indexOf(".");
+  if (ptIdx < 0) {
+    const v = x[s];
+    if (replacement !== undefined) {
+      x[s] = replacement;
+    }
+    return v;
+  } else {
+    const identifier = s.substring(0, ptIdx);
+    const rest = s.substring(ptIdx + 1);
+    return follow(x[identifier], rest, replacement);
+  }
+}
+
+export function evaluateKeyPath(x: any, path: string | string[], replacement?: 
any): any {
+  if (typeof path === "string") {
+    return follow(x, path, replacement);
+  } else if (Array.isArray(path)) {
+    const res: any[] = [];
+    for (let s of path) {
+      let c = follow(x, s, replacement);
+      if (c === undefined) {
+        return undefined;
+      }
+      res.push(c);
+    }
+    return res;
+  } else {
+    throw Error("invalid key path, must be string or array of strings");
+  }
+}
+
+function stringifyKey(key: any) {
+  return JSON.stringify(key);
+}
+
+export function isValidKey(key: any, memo: any[] = []) {
+  if (typeof key === "string" || typeof key === "number" || key instanceof 
Date) {
+    return true;
+  }
+  if (Array.isArray(key)) {
+    for (const element of key) {
+      if (!isValidKey(element, memo.concat([key]))) {
+        return false;
+      }
+    }
+    return true;
+  }
+  return false;
+}
 
 class MyObjectStore implements IDBObjectStore  {
+
+  _keyPath: string | string[] | undefined;
+  _autoIncrement: boolean;
+
   get indexNames() {
     return new DOMStringList();
   }
 
-  constructor(public transaction: Transaction, public dbName: string, public 
storeName: string) {
+  constructor(public transaction: Transaction, public storeName: string) {
+    this._keyPath = 
this.transaction.transactionDbData.stores[this.storeName].keyPath as (string | 
string[]);
+    this._autoIncrement = 
this.transaction.transactionDbData.stores[this.storeName].autoIncrement;
   }
 
-  get keyPath() {
-    return this.transaction.db.dbData.stores[this.storeName].keyPath;
+  get keyPath(): string | string[] {
+    // TypeScript definitions are wrong here and don't permit a null keyPath
+    return this._keyPath as (string | string[]);
   }
 
   get name() {
@@ -206,15 +342,77 @@ class MyObjectStore implements IDBObjectStore  {
   }
 
   get autoIncrement() {
-    return this.transaction.db.dbData.stores[this.storeName].autoIncrement;
+    return this._autoIncrement;
   }
 
-  add(value: any, key?: any): IDBRequest {
-    throw Error("not implemented");
+  storeImpl(originalValue: any, key: any|undefined, allowExisting: boolean) {
+    if (this.transaction.mode === "readonly") {
+      throw Error();
+    }
+    if (!this.transaction.active) {
+      throw Error();
+    }
+    if 
(!this.transaction.transactionDbData.stores.hasOwnProperty(this.storeName)) {
+      throw Error("object store was deleted");
+    }
+
+    const store = this.transaction.transactionDbData.stores[this.storeName];
+
+    const value = structuredClone(originalValue);
+
+    if (this.keyPath) {
+      // we're dealine with in-line keys
+      if (key) {
+        throw Error("keys not allowed with in-line keys");
+      }
+      key = evaluateKeyPath(value, this.keyPath);
+      if (!key && !this.autoIncrement) {
+        throw Error("key path must evaluate to key for in-line stores without 
autoIncrement");
+      }
+      if (this.autoIncrement) {
+        if (key && typeof key === "number") {
+          store.keyGenerator = key + 1;
+        } else {
+          key = store.keyGenerator;
+          store.keyGenerator += 1;
+          evaluateKeyPath(value, this.keyPath, key);
+        }
+      }
+    } else {
+      // we're dealing with out-of-line keys
+      if (!key && !this.autoIncrement) {
+        throw Error("key must be provided for out-of-line stores without 
autoIncrement");
+      }
+      key = this.transaction.transactionDbData.stores
+      if (this.autoIncrement) {
+        if (key && typeof key === "number") {
+          store.keyGenerator = key + 1;
+        } else {
+          key = store.keyGenerator;
+          store.keyGenerator += 1;
+        }
+      }
+    }
+
+    const stringKey = stringifyKey(key);
+
+    if (store.objects.hasOwnProperty(stringKey) && !allowExisting) {
+      throw Error("key already exists");
+    }
+
+    store.objects[stringKey] = value;
+
+    const req = new MyRequest(this.transaction, () => {
+    });
+    return req;
   }
 
   put(value: any, key?: any): IDBRequest {
-    throw Error("not implemented");
+    return this.storeImpl(value, key, true);
+  }
+
+  add(value: any, key?: any): IDBRequest {
+    return this.storeImpl(value, key, false);
   }
 
   delete(key: any): IDBRequest {
@@ -242,7 +440,7 @@ class MyObjectStore implements IDBObjectStore  {
   }
 
   index(indexName: string): IDBIndex {
-    throw Error("not implemented");
+    return new IndexHandle(this, indexName);
   }
 
   openCursor(range?: IDBKeyRange | IDBValidKey, direction?: 
IDBCursorDirection): IDBRequest {
@@ -257,19 +455,31 @@ class Db implements IDBDatabase {
   onerror: (this: IDBDatabase, ev: Event) => any;
   onversionchange: (ev: IDBVersionChangeEvent) => any;
 
+  _storeNames: string[] = [];
+
   constructor(private _name: string, private _version: number, private 
factory: MemoryIDBFactory) {
+    for (let storeName in this.dbData.stores) {
+      if (this.dbData.stores.hasOwnProperty(storeName)) {
+        this._storeNames.push(storeName);
+      }
+    }
+    this._storeNames.sort();
   }
 
-  get dbData() {
+  get dbData(): Database {
     return this.factory.data[this._name];
   }
 
+  set dbData(data) {
+    this.factory.data[this._name] = data;
+  }
+
   get name() {
     return this._name;
   }
 
   get objectStoreNames() {
-    return new MyDomStringList();
+    return new MyDomStringList(...this._storeNames);
   }
 
   get version() {
@@ -284,11 +494,44 @@ class Db implements IDBDatabase {
     if (tx.mode !== "versionchange") {
       throw Error("invalid mode");
     }
-    throw Error("not implemented");
+
+    const td = tx.transactionDbData;
+    if (td.stores[name]) {
+      throw Error("object store already exists");
+    }
+
+    td.stores[name] = {
+      autoIncrement: !!(optionalParameters && 
optionalParameters.autoIncrement),
+      indices: {},
+      keyGenerator: 1,
+      name,
+      objects: [],
+    };
+
+    this._storeNames.push(name);
+    this._storeNames.sort();
+
+    return new MyObjectStore(tx, name);
   }
 
   deleteObjectStore(name: string): void {
-    throw Error("not implemented");
+    let tx = this.factory.getTransaction();
+    if (tx.mode !== "versionchange") {
+      throw Error("invalid mode");
+    }
+
+    const td = tx.transactionDbData;
+    if (td.stores[name]) {
+      throw Error("object store does not exists");
+    }
+
+    const idx = this._storeNames.indexOf(name);
+    if (idx < 0) {
+      throw Error();
+    }
+    this._storeNames.splice(idx, 1);
+    
+    delete td.stores[name];
   }
 
   transaction(storeNames: string | string[], mode: IDBTransactionMode = 
"readonly"): IDBTransaction {
@@ -342,11 +585,30 @@ class Transaction implements IDBTransaction {
     return this._mode;
   }
 
+  get active(): boolean {
+    return this.state === TransactionState.Running || this.state === 
TransactionState.Created;
+  }
+
   start() {
     if (this.state != TransactionState.Created) {
       throw Error();
     }
+    this.state = TransactionState.Running;
     this._transactionDbData = structuredClone(this.dbHandle.dbData);
+    if (!this._transactionDbData) {
+      throw Error();
+    }
+  }
+
+  commit() {
+    if (this.state != TransactionState.Running) {
+      throw Error();
+    }
+    if (!this._transactionDbData) {
+      throw Error();
+    }
+    this.state = TransactionState.Commited;
+    this.dbHandle.dbData = this._transactionDbData;
   }
 
   get error(): DOMException {
@@ -373,7 +635,7 @@ class Transaction implements IDBTransaction {
   }
 
   objectStore(storeName: string): IDBObjectStore {
-    return new MyObjectStore(this, this.dbName, storeName);
+    return new MyObjectStore(this, storeName);
   }
 
   dispatchEvent(evt: Event): boolean {
@@ -425,8 +687,9 @@ class MyEvent implements Event {
   _timeStamp: number = 0;
   _type: string;
 
-  constructor(typeArg: string) {
+  constructor(typeArg: string, target: any) {
     this._type = typeArg;
+    this._target = target;
   }
 
   get eventPhase() {
@@ -519,10 +782,10 @@ class MyEvent implements Event {
 class VersionChangeEvent extends MyEvent {
   _newVersion: number|null;
   _oldVersion: number;
-  constructor(oldVersion: number, newVersion?: number) {
-    super("VersionChange");
+  constructor(oldVersion: number, newVersion: number|null, target: any) {
+    super("VersionChange", target);
     this._oldVersion = oldVersion;
-    this._newVersion = newVersion || null;
+    this._newVersion = newVersion;
   }
 
   get newVersion() {
@@ -535,7 +798,7 @@ class VersionChangeEvent extends MyEvent {
 }
 
 
-class MemoryIDBFactory implements IDBFactory {
+export class MemoryIDBFactory implements IDBFactory {
   data: Databases = {};
 
   currentRequest: MyRequest|undefined;
@@ -570,7 +833,7 @@ class MemoryIDBFactory implements IDBFactory {
         // auto-commit the transaction that the
         // previous request worked on.
         let lastTx = prevRequest._transaction;
-        this.data[lastTx.dbName] = lastTx.transactionDbData;
+        lastTx.commit();
       }
     };
     alreadyResolved.then(() => {
@@ -604,13 +867,19 @@ class MemoryIDBFactory implements IDBFactory {
     }
 
     let upgradeNeeded = false;
+    let oldVersion: number;
     let mydb: Database;
     if (dbName in this.data) {
       mydb = this.data[dbName];
+      if (!mydb) {
+        throw Error();
+      }
+      oldVersion = mydb.version;
       if (version === undefined || version == mydb.version) {
         // we can open without upgrading
       } else if (version > mydb.version) {
         upgradeNeeded = true;
+        mydb.version = version;
       } else {
         throw Error("version error");
       }
@@ -621,17 +890,21 @@ class MemoryIDBFactory implements IDBFactory {
         version: (version || 1),
       };
       upgradeNeeded = true;
+      oldVersion = 0;
     }
 
+    this.data[dbName] = mydb;
+
     const db = new Db(dbName, mydb.version, this);
     const tx = new Transaction(dbName, db, "versionchange");
 
     const req = new OpenDBRequest(tx, () => {
+      req._result = db;
       if (upgradeNeeded) {
-        let versionChangeEvt = new VersionChangeEvent(mydb.version, version);
+        let versionChangeEvt = new VersionChangeEvent(oldVersion, 
mydb.version, db);
         req.callOnupgradeneeded(versionChangeEvt);
       }
-      let successEvent = new MyEvent("success");
+      let successEvent = new MyEvent("success", db);
       req.callSuccess(successEvent);
     });
 
@@ -640,3 +913,10 @@ class MemoryIDBFactory implements IDBFactory {
     return req;
   }
 }
+
+/**
+ * Inject our IndexedDb implementation in the global namespace,
+ * potentially replacing an existing implementation.
+ */
+export function injectGlobals() {
+}
diff --git a/tsconfig.json b/tsconfig.json
index 1f649ef1..dee558cf 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -40,6 +40,7 @@
     "src/i18n.tsx",
     "src/i18n/strings.ts",
     "src/logging.ts",
+    "src/memidb-test.ts",
     "src/memidb.ts",
     "src/query.ts",
     "src/timer.ts",
diff --git a/yarn.lock b/yarn.lock
index 5bd122cb..0769e283 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4610,6 +4610,10 @@ address@hidden:
   version "2.0.1"
   resolved 
"https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a";
 
address@hidden:
+  version "0.2.2"
+  resolved 
"https://registry.yarnpkg.com/structured-clone/-/structured-clone-0.2.2.tgz#ac92b6be31958a643db30f1335abc6a1b02dfdc2";
+
 address@hidden:
   version "0.2.0"
   resolved 
"https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a";

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



reply via email to

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