Updated to v1.3.1.

This commit is contained in:
David Fahlander
2016-03-09 02:02:28 +01:00
parent 9f0f926a12
commit 2f23ff4c61
2 changed files with 49 additions and 289 deletions
+17 -248
View File
@@ -1,256 +1,25 @@
/// <reference path="dexie.d.ts" />
import Dexie = require("dexie");
module Utils {
export class Console {
textarea: HTMLTextAreaElement;
constructor() {
this.textarea = document.createElement('textarea');
}
log(txt: string, type?: string) {
if (type) this.textarea.value += type + " ";
this.textarea.value += txt + "\n";
}
error = function (txt: string) {
this.log(txt, "ERROR!");
}
}
import Dexie from "dexie";
interface IFriend {
id?: number,
name?: string,
age?: number
}
module AppDb {
export class AppDatabase extends Dexie {
contacts: Dexie.Table<Contact, number>;
emails: Dexie.Table<IEmailAddress, number>;
phones: Dexie.Table<IPhoneNumber, number>;
constructor() {
super("MyTypeScriptAppDb");
var db = this;
//
// Define tables and indexes
//
db.version(1).stores({
contacts: '++id, first, last',
emails: '++id, contactId, type, email',
phones: '++id, contactId, type, phone',
});
// Let's physically map Contact class to contacts table.
// This will make it possible to call loadEmailsAndPhones()
// directly on retrieved database objects.
db.contacts.mapToClass(Contact);
}
}
/* Just for code completion and compilation - defines
* the interface of objects stored in the emails table.
*/
export interface IEmailAddress {
id?: number;
contactId: number;
type: string;
email: string;
}
/* Just for code completion and compilation - defines
* the interface of objects stored in the phones table.
*/
export interface IPhoneNumber {
id?: number;
contactId: number;
type: string;
phone: string;
}
/* This is a 'physical' class that is mapped to
* the contacts table. We can have methods on it that
* we could call on retrieved database objects.
*/
export class Contact {
id: number;
first: string;
last: string;
emails: IEmailAddress[];
phones: IPhoneNumber[];
constructor(first: string, last: string, id?: number) {
this.first = first;
this.last = last;
if (id) this.id = id;
}
loadEmailsAndPhones() : Dexie.Promise<Contact> {
return Dexie.Promise.all<any>(
db.emails
.where('contactId').equals(this.id)
.toArray(emails => this.emails = emails)
,
db.phones
.where('contactId').equals(this.id)
.toArray(phones => this.phones = phones)
).then(() => this);
}
save() {
return db.transaction('rw', db.contacts, db.emails, db.phones, () => {
Dexie.Promise.all(
// Save existing arrays
Dexie.Promise.all(this.emails.map(email => db.emails.put(email))),
Dexie.Promise.all(this.phones.map(phone => db.phones.put(phone))))
.then(results => {
// Remove items from DB that is was not saved here:
var emailIds = results[0], // array of resulting primary keys
phoneIds = results[1]; // array of resulting primary keys
db.emails.where('contactId').equals(this.id)
.and(email => emailIds.indexOf(email.id) === -1)
.delete();
db.phones.where('contactId').equals(this.id)
.and(phone => phoneIds.indexOf(phone.id) === -1)
.delete();
// At last, save our own properties.
// (Must not do put(this) because we would get
// reduntant emails/phones arrays saved into db)
db.contacts.put(
new Contact(this.first, this.last, this.id))
.then(id => this.id = id);
});
});
}
}
export var db = new AppDatabase();
db.open();
}
import Console = Utils.Console;
import db = AppDb.db;
document.addEventListener('DOMContentLoaded', () => {
// Initialize our Console widget - it will log browser window.
var console = new Console();
document.getElementById('consoleArea').appendChild(console.textarea);
// Test it:
console.log("Hello world!");
// Make sure to never miss any unexpected error:
Dexie.Promise.on.error.subscribe(e => {
// Log any uncatched error:
console.error(e);
});
//
// Let's clear and re-seed the database:
//
clearDatabase()
.then(seedDatabase)
.then(playALittle_add_phone_to_adam)
.then(printContacts);
function clearDatabase() {
console.log("Clearing database...");
return Dexie.Promise.all(
db.contacts.clear(),
db.emails.clear(),
db.phones.clear());
}
function seedDatabase() {
console.log("Seeding database with some contacts...");
return db.transaction('rw', db.contacts, db.emails, db.phones, () => {
// Populate a contact
db.contacts.add(new AppDb.Contact('Arnold', 'Fitzgerald')).then(id => {
// Populate some emails and phone numbers for the contact
db.emails.add({ contactId: id, type: 'home', email: 'arnold@email.com' });
db.emails.add({ contactId: id, type: 'work', email: 'arnold@abc.com' });
db.phones.add({ contactId: id, type: 'home', phone: '12345678' });
db.phones.add({ contactId: id, type: 'work', phone: '987654321' });
});
// ... and another one...
db.contacts.add(new AppDb.Contact('Adam', 'Tensta')).then(id => {
// Populate some emails and phone numbers for the contact
db.emails.add({ contactId: id, type: 'home', email: 'adam@tensta.se' });
db.phones.add({ contactId: id, type: 'work', phone: '88888888' });
});
class MyDB extends Dexie {
friends: Dexie.Table<IFriend, number>;
constructor() {
super("MyDB");
this.version(1).stores({
friends: "++id,name,age"
});
}
}
function playALittle_add_phone_to_adam() {
// Now, just to examplify how to use the save() method as an alternative
// to db.phones.add(), we will add yet another phone number
// to an existing contact and then re-save it:
console.log("Playing a little: adding another phone entry for Adam Tensta...");
return db.contacts
.where('last').equals('Tensta').first(c => c.loadEmailsAndPhones())
.then(contact => {
// Also add another phone number to Adam Tensta:
contact.phones.push({
contactId: contact.id,
type: 'custom',
phone: '112'
});
contact.save();
});
}
var db = new MyDB();
function printContacts() {
// Now we're gonna list all contacts starting with letter 'A'
// and print them out.
// For each contact, also resolve its collection of
// phone number entries and email addresses by reverse-quering
// the foreign tables.
// For atomicity and speed, use a single transaction for the
// queries to make:
db.transaction('r', [db.contacts, db.phones, db.emails], () => {
// Query some contacts
return db.contacts
.where('first').startsWithIgnoreCase('a')
.sortBy('id')
.then(contacts =>
// Resolve array properties 'emails' and 'phones'
// on each and every contact:
Dexie.Promise.all(
contacts.map(contact =>
contact.loadEmailsAndPhones()))
);
}).then(contacts => {
// Print result
console.log("Database contains the following contacts:");
contacts.forEach(contact => {
console.log(contact.id + ". " + contact.first + " " + contact.last);
console.log(" Phone numbers: ");
contact.phones.forEach(phone => {
console.log(" " + phone.phone + "(" + phone.type + ")");
});
console.log(" Emails: ");
contact.emails.forEach(email => {
console.log(" " + email.email + "(" + email.type + ")");
});
});
});
}
db.friends.add({name: "Kalle", age: 23}).then(()=>{
db.friends.where('age').below(30).count(count => {
console.log("Num yound friends: " + count);
});
});
+32 -41
View File
@@ -1,7 +1,7 @@
// Type definitions for Dexie v1.2
// Type definitions for Dexie 1.3.1
// Project: https://github.com/dfahlander/Dexie.js
// Definitions by: David Fahlander <http://github.com/dfahlander>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
// Date Wed Mar 09 2016
interface Thenable<R> {
then<U>(onFulfilled: (value: R) => Thenable<U>, onRejected: (error: any) => Thenable<U>): Thenable<U>;
@@ -10,6 +10,8 @@ interface Thenable<R> {
then<U>(onFulfilled?: (value: R) => U, onRejected?: (error: any) => U): Thenable<U>;
}
declare type IndexableType = string | number | Date | Array<string | number | Date>;
declare class Dexie {
constructor(databaseName: string);
@@ -38,7 +40,7 @@ declare class Dexie {
static deepClone(obj: Object): Object;
version(versionNumber: number): Dexie.Version;
version(versionNumber: Number): Dexie.Version
on: {
(eventName: string, subscriber: () => any): void;
@@ -48,7 +50,7 @@ declare class Dexie {
populate: Dexie.DexieEvent;
blocked: Dexie.DexieEvent;
versionchange: Dexie.DexieVersionChangeEvent;
};
}
open(): Dexie.Promise<Dexie>;
@@ -103,13 +105,19 @@ declare module Dexie {
then<U>(onFulfilled: (value: R) => U, onRejected: (error: any) => Thenable<U>): Promise<U>;
then<U>(onFulfilled?: (value: R) => U, onRejected?: (error: any) => U): Promise<U>;
catch<U>(onRejected: (error: any) => Promise<U>): Promise<U>;
catch<U>(onRejected: (error: any) => Thenable<U>): Promise<U>;
catch<U>(onRejected: (error: any) => U): Promise<U>;
catch<U>(ExceptionType: Function, onRejected: (error: any) => Promise<U>): Promise<U>;
catch<U>(ExceptionType: Function, onRejected: (error: any) => U): Promise<U>;
catch<U>(errorName: string, onRejected: (error: any) => Promise<U>): Promise<U>;
catch<U>(errorName: string, onRejected: (error: any) => U): Promise<U>;
finally<R>(onFinally: () => any): Promise<R>;
onuncatched: () => any;
@@ -229,42 +237,26 @@ declare module Dexie {
}
interface WhereClause<T, Key> {
above(key: number): Collection<T, Key>;
above(key: string): Collection<T, Key>;
above(key: Date): Collection<T, Key>;
above(key: Array<any>): Collection<T, Key>;
aboveOrEqual(key: number): Collection<T, Key>;
aboveOrEqual(key: string): Collection<T, Key>;
aboveOrEqual(key: Date): Collection<T, Key>;
aboveOrEqual(key: Array<any>): Collection<T, Key>;
anyOf(keys: Array<any>): Collection<T, Key>;
anyOf(...keys: any[]): Collection<T, Key>;
below(key: number): Collection<T, Key>;
below(key: string): Collection<T, Key>;
below(key: Date): Collection<T, Key>;
below(key: Array<any>): Collection<T, Key>;
belowOrEqual(key: number): Collection<T, Key>;
belowOrEqual(key: string): Collection<T, Key>;
belowOrEqual(key: Date): Collection<T, Key>;
belowOrEqual(key: Array<any>): Collection<T, Key>;
between(lower: number, upper: number, includeLower?: boolean, includeUpper?: boolean): Collection<T, Key>;
between(lower: string, upper: string, includeLower?: boolean, includeUpper?: boolean): Collection<T, Key>;
between(lower: Date, upper: Date, includeLower?: boolean, includeUpper?: boolean): Collection<T, Key>;
between(lower: Array<any>, upper: Array<any>, includeLower?: boolean, includeUpper?: boolean): Collection<T, Key>;
equals(key: number): Collection<T, Key>;
equals(key: string): Collection<T, Key>;
equals(key: Date): Collection<T, Key>;
equals(key: Array<any>): Collection<T, Key>;
above(key: IndexableType): Collection<T, Key>;
aboveOrEqual(key: IndexableType): Collection<T, Key>;
anyOf(keys: IndexableType[]): Collection<T, Key>;
anyOf(...keys: IndexableType[]): Collection<T, Key>;
anyOfIgnoreCase(keys: string[]): Collection<T, Key>;
anyOfIgnoreCase(...keys: string[]): Collection<T, Key>;
below(key: IndexableType): Collection<T, Key>;
belowOrEqual(key: IndexableType): Collection<T, Key>;
between(lower: IndexableType, upper: IndexableType, includeLower?: boolean, includeUpper?: boolean): Collection<T, Key>;
equals(key: IndexableType): Collection<T, Key>;
equalsIgnoreCase(key: string): Collection<T, Key>;
inAnyRange(ranges: Array<IndexableType[]>): Collection<T, Key>;
startsWith(key: string): Collection<T, Key>;
startsWithAnyOf(prefixes: string[]): Collection<T, Key>;
startsWithAnyOf(...prefixes: string[]): Collection<T, Key>;
startsWithIgnoreCase(key: string): Collection<T, Key>;
noneOf(keys: Array<any>): Collection<T, Key>;
notEqual(key: number): Collection<T, Key>;
notEqual(key: string): Collection<T, Key>;
notEqual(key: Date): Collection<T, Key>;
notEqual(key: Array<any>): Collection<T, Key>;
startsWithAnyOfIgnoreCase(prefixes: string[]): Collection<T, Key>;
startsWithAnyOfIgnoreCase(...prefixes: string[]): Collection<T, Key>;
noneOf(keys: Array<IndexableType>): Collection<T, Key>;
notEqual(key: IndexableType): Collection<T, Key>;
}
interface Collection<T, Key> {
@@ -323,6 +315,5 @@ declare module Dexie {
}
}
declare module 'dexie' {
export = Dexie;
}
export default Dexie;