Skip to content

Commit

Permalink
Start porting to TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
dumbmatter committed Apr 19, 2017
1 parent fc9f9d9 commit f8d31dd
Show file tree
Hide file tree
Showing 65 changed files with 970 additions and 746 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
node_modules
npm-debug.log
dist
build
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Or you can import individual functions directly. Variable names of all the objec

```js
var fakeIndexedDB = require('fake-indexeddb');
var FDBKeyRange = require('fake-indexeddb/FDBKeyRange');
var FDBKeyRange = require('fake-indexeddb/FDBKeyRange').default;

// ...same code as last example, but fakeIndexedDB instead of indexedDB and FDBKeyRange instead of IDBKeyRange
```
Expand Down
23 changes: 21 additions & 2 deletions TODO
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ binary search tree

TypeScript
- tslint
- re-enable disabled rules
- provide type defs to consumer
- remove eslint - all files and comments
- remove babel
- improve types
- Database.transactions
- FDBCursorWithValue any
- types.ts any
- EventTarget addEventListener callback can be null?
- FDBRequest null/any variables
- ObjectStore rawDatabase, rawIndexes
- Index rawObjectStore, transaction any
- FDBCursor source any
- FDBIndex objectStore, rawIndex any
- FDBObjectStore transaction any
- FDBTransaction db any
- circular import problems (search) - define interface in types.ts
- public APIs should accept any - errors are part of spec, not to be prevented by types?
- make sure it's still usable by normal ES5 code, not weird exports
- change target in tsconfig

Run on real W3C tests

Expand All @@ -15,8 +35,6 @@ open issues

addDomStringListMethods - make it a class

add lib.js for 1.x compatability, and test

make sure it works in node 4

---
Expand All @@ -32,6 +50,7 @@ multiple readonly transactions should be allowed to run at the same time (but no

readonly properties need to actually be readonly
- done in FDBCursor
- typescript annotation is easier (like in FDBKeyRange), but not actually binding for compiled JS version

share some code between Index and ObjectStore, like getValue, confirmActiveTransaction, count
- similar thing between open and deleteDatabase
Expand Down
17 changes: 10 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@
],
"main": "src/index.js",
"scripts": {
"lint": "eslint 'src/**/*.js'",
"mocha": "mocha --timeout 5000 src/test/w3c src/test/fakeIndexedDB",
"build-qunit": "rm -rf dist && mkdir dist && browserify src/test/exports-qunit.js -o dist/exports-qunit.js -t [ babelify --presets [ es2015 ] ]",
"qunit": "npm run build-qunit && node-qunit-phantomjs ./src/test/indexedDBmock/index.html",
"test": "npm run lint && npm run mocha && npm run qunit"
"build": "rm -rf build && tsc",
"lint": "tslint 'src/**/*.ts' && eslint 'src/**/*.js'",
"mocha": "mocha --timeout 10000 build/test/w3c build/test/fakeIndexedDB",
"build-qunit": "browserify build/test/exports-qunit.js -o build/exports-qunit-bundle.js -t [ babelify --presets [ es2015 ] ] && cp src/test/indexedDBmock/index.html build/test/indexedDBmock/index.html",
"qunit": "npm run build-qunit && node-qunit-phantomjs build/test/indexedDBmock/index.html",
"test": "npm run lint && npm run build && npm run mocha && npm run qunit"
},
"author": "Jeremy Scheff <[email protected]> (http://dumbmatter.com/)",
"license": "Apache-2.0",
Expand All @@ -35,13 +36,15 @@
"setimmediate": "^1.0.5"
},
"devDependencies": {
"@types/node": "^7.0.13",
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.24.1",
"babelify": "^7.3.0",
"browserify": "^14.0.0",
"eslint": "^3.15.0",
"mocha": "^3.2.0",
"node-qunit-phantomjs": "^1.5.0",
"qunitjs": "^1.23.1"
"qunitjs": "^1.23.1",
"tslint": "^5.1.0",
"typescript": "^2.2.2"
}
}
133 changes: 80 additions & 53 deletions src/FDBCursor.js → src/FDBCursor.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
const structuredClone = require('./lib/structuredClone');
const FDBKeyRange = require('./FDBKeyRange');
const {DataError, InvalidStateError, ReadOnlyError, TransactionInactiveError} = require('./lib/errors');
const cmp = require('./lib/cmp');
const extractKey = require('./lib/extractKey');
const validateKey = require('./lib/validateKey');

const getEffectiveObjectStore = (cursor) => {
if (cursor.source.hasOwnProperty('_rawIndex')) {
import FDBKeyRange from "./FDBKeyRange";
import FDBRequest from "./FDBRequest";
import cmp from "./lib/cmp";
const {DataError, InvalidStateError, ReadOnlyError, TransactionInactiveError} = require("./lib/errors");
import extractKey from "./lib/extractKey";
import structuredClone from "./lib/structuredClone";
import {FDBCursorDirection, Key, Value} from "./lib/types";
import validateKey from "./lib/validateKey";

type Range = Key | FDBKeyRange | void;

const getEffectiveObjectStore = (cursor: FDBCursor) => {
if (cursor.source.hasOwnProperty("_rawIndex")) {
return cursor.source.objectStore;
}
return cursor.source;
Expand All @@ -16,7 +20,7 @@ const getEffectiveObjectStore = (cursor) => {
// range. It does not handle gt/gte distinctions, because it doesn't really matter much anyway, since for next/prev
// cursor iteration it'd also have to look at values to be precise, which would be complicated. This should get us 99%
// of the way there.
const makeKeyRange = (range, lowers, uppers) => {
const makeKeyRange = (range: FDBKeyRange, lowers: Array<Key | void>, uppers: Array<Key | void>) => {
// Start with bounds from range
let lower = range !== undefined ? range.lower : undefined;
let upper = range !== undefined ? range.upper : undefined;
Expand Down Expand Up @@ -50,21 +54,27 @@ const makeKeyRange = (range, lowers, uppers) => {
if (upper !== undefined) {
return FDBKeyRange.upperBound(upper);
}
}
};

// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#cursor
class FDBCursor {
constructor(source, range, direction = 'next', request) {
this._gotValue = false;
this._range = range;
this._position = undefined; // Key of previously returned record
this._objectStorePosition = undefined;
this._request = request;
public _request: FDBRequest | void;

private _gotValue: boolean = false;
private _range: Range;
private _position = undefined; // Key of previously returned record
private _objectStorePosition = undefined;

private _source: any;
private _direction: FDBCursorDirection;
private _key = undefined;
private _primaryKey: Key | void = undefined;

constructor(source: any, range: Range, direction: FDBCursorDirection = "next", request?: FDBRequest) {
this._range = range;
this._source = source;
this._direction = direction;
this._key = undefined;
this._primaryKey = undefined;
this._request = request;
}

// Read only properties
Expand All @@ -82,8 +92,8 @@ class FDBCursor {
}

// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-iterating-a-cursor
_iterate(key) {
const sourceIsObjectStore = !this.source.hasOwnProperty('_rawIndex');
public _iterate(key?: Key): this | null {
const sourceIsObjectStore = !this.source.hasOwnProperty("_rawIndex");

const records = sourceIsObjectStore ? this.source._rawObjectStore.records : this.source._rawIndex.records;

Expand Down Expand Up @@ -144,7 +154,7 @@ class FDBCursor {
}
} else if (this.direction === "prev") {
const range = makeKeyRange(this._range, [], [key, this._position]);
for (const record of records.values(range, 'prev')) {
for (const record of records.values(range, "prev")) {
if (key !== undefined) {
if (cmp(record.key, key) === 1) {
continue;
Expand Down Expand Up @@ -175,7 +185,7 @@ class FDBCursor {
} else if (this.direction === "prevunique") {
let tempRecord;
const range = makeKeyRange(this._range, [], [key, this._position]);
for (const record of records.values(range, 'prev')) {
for (const record of records.values(range, "prev")) {
if (key !== undefined) {
if (cmp(record.key, key) === 1) {
continue;
Expand Down Expand Up @@ -204,8 +214,11 @@ class FDBCursor {
if (!foundRecord) {
this._key = undefined;
if (!sourceIsObjectStore) { this._objectStorePosition = undefined; }
if (this.constructor.name === 'FDBCursorWithValue') {
this.value = undefined;

// "this instanceof FDBCursorWithValue" would be better and not require (this as any), but causes runtime
// error due to circular dependency.
if (this.constructor.name === "FDBCursorWithValue") {
(this as any).value = undefined;
}
result = null;
} else {
Expand All @@ -214,13 +227,14 @@ class FDBCursor {
this._key = foundRecord.key;
if (sourceIsObjectStore) {
this._primaryKey = structuredClone(foundRecord.key);
if (this.constructor.name === 'FDBCursorWithValue') {
this.value = structuredClone(foundRecord.value);
if (this.constructor.name === "FDBCursorWithValue") {
(this as any).value = structuredClone(foundRecord.value);
}
} else {
this._primaryKey = structuredClone(foundRecord.value);
if (this.constructor.name === 'FDBCursorWithValue') {
this.value = structuredClone(this.source.objectStore._rawObjectStore.getValue(foundRecord.value));
if (this.constructor.name === "FDBCursorWithValue") {
const value = this.source.objectStore._rawObjectStore.getValue(foundRecord.value);
(this as any).value = structuredClone(value);
}
}
this._gotValue = true;
Expand All @@ -231,14 +245,14 @@ class FDBCursor {
}

// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-update-IDBRequest-any-value
update(value) {
public update(value: Value) {
if (value === undefined) { throw new TypeError(); }

const effectiveObjectStore = getEffectiveObjectStore(this);
const effectiveKey = this.source.hasOwnProperty('_rawIndex') ? this.primaryKey : this._position;
const effectiveKey = this.source.hasOwnProperty("_rawIndex") ? this.primaryKey : this._position;
const transaction = effectiveObjectStore.transaction;

if (transaction.mode === 'readonly') {
if (transaction.mode === "readonly") {
throw new ReadOnlyError();
}

Expand All @@ -250,7 +264,7 @@ class FDBCursor {
throw new InvalidStateError();
}

if (!this._gotValue || !this.hasOwnProperty('value')) {
if (!this._gotValue || !this.hasOwnProperty("value")) {
throw new InvalidStateError();
}

Expand All @@ -268,17 +282,22 @@ class FDBCursor {

const record = {
key: effectiveKey,
value: structuredClone(value)
value: structuredClone(value),
};

return transaction._execRequestAsync({
operation: effectiveObjectStore._rawObjectStore.storeRecord.bind(
effectiveObjectStore._rawObjectStore,
record,
false,
transaction._rollbackLog,
),
source: this,
operation: effectiveObjectStore._rawObjectStore.storeRecord.bind(effectiveObjectStore._rawObjectStore, record, false, transaction._rollbackLog)
});
}

// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-advance-void-unsigned-long-count
advance(count) {
public advance(count: number) {
if (!Number.isInteger(count) || count <= 0) { throw new TypeError(); }

const effectiveObjectStore = getEffectiveObjectStore(this);
Expand All @@ -296,9 +315,10 @@ class FDBCursor {
throw new InvalidStateError();
}

this._request.readyState = 'pending';
if (this._request) {
this._request.readyState = "pending";
}
transaction._execRequestAsync({
source: this.source,
operation: () => {
let result;
for (let i = 0; i < count; i++) {
Expand All @@ -311,14 +331,15 @@ class FDBCursor {
}
return result;
},
request: this._request
request: this._request,
source: this.source,
});

this._gotValue = false;
}

// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-continue-void-any-key
continue(key) {
public continue(key?: Key) {
const effectiveObjectStore = getEffectiveObjectStore(this);
const transaction = effectiveObjectStore.transaction;

Expand All @@ -339,28 +360,30 @@ class FDBCursor {

const cmpResult = cmp(key, this._position);

if ((cmpResult <= 0 && (this.direction === 'next' || this.direction === 'nextunique')) ||
(cmpResult >= 0 && (this.direction === 'prev' || this.direction === 'prevunique'))) {
if ((cmpResult <= 0 && (this.direction === "next" || this.direction === "nextunique")) ||
(cmpResult >= 0 && (this.direction === "prev" || this.direction === "prevunique"))) {
throw new DataError();
}
}

this._request.readyState = 'pending';
if (this._request) {
this._request.readyState = "pending";
}
transaction._execRequestAsync({
source: this.source,
operation: this._iterate.bind(this, key),
request: this._request
request: this._request,
source: this.source,
});

this._gotValue = false;
}

delete() {
public delete() {
const effectiveObjectStore = getEffectiveObjectStore(this);
const effectiveKey = this.source.hasOwnProperty('_rawIndex') ? this.primaryKey : this._position;
const effectiveKey = this.source.hasOwnProperty("_rawIndex") ? this.primaryKey : this._position;
const transaction = effectiveObjectStore.transaction;

if (transaction.mode === 'readonly') {
if (transaction.mode === "readonly") {
throw new ReadOnlyError();
}

Expand All @@ -372,19 +395,23 @@ class FDBCursor {
throw new InvalidStateError();
}

if (!this._gotValue || !this.hasOwnProperty('value')) {
if (!this._gotValue || !this.hasOwnProperty("value")) {
throw new InvalidStateError();
}

return transaction._execRequestAsync({
operation: effectiveObjectStore._rawObjectStore.deleteRecord.bind(
effectiveObjectStore._rawObjectStore,
effectiveKey,
transaction._rollbackLog,
),
source: this,
operation: effectiveObjectStore._rawObjectStore.deleteRecord.bind(effectiveObjectStore._rawObjectStore, effectiveKey, transaction._rollbackLog)
});
}

toString() {
return '[object IDBCursor]';
public toString() {
return "[object IDBCursor]";
}
}

module.exports = FDBCursor;
export default FDBCursor;
15 changes: 0 additions & 15 deletions src/FDBCursorWithValue.js

This file was deleted.

Loading

0 comments on commit f8d31dd

Please sign in to comment.