mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
feat(storage): new Local and WebSQL/SQLite key value storage service
This commit is contained in:
47
ionic/components/app/test/storage/index.ts
Normal file
47
ionic/components/app/test/storage/index.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import {Component} from 'angular2/angular2';
|
||||||
|
import {Control, ControlGroup} from 'angular2/forms';
|
||||||
|
|
||||||
|
import {App, Http, Storage, LocalStorage, SQLStorage} from 'ionic/ionic';
|
||||||
|
|
||||||
|
let testUrl = 'https://ionic-api-tester.herokuapp.com/json';
|
||||||
|
let testUrl404 = 'https://ionic-api-tester.herokuapp.com/404';
|
||||||
|
|
||||||
|
|
||||||
|
@App({
|
||||||
|
templateUrl: 'main.html'
|
||||||
|
})
|
||||||
|
class IonicApp {
|
||||||
|
constructor() {
|
||||||
|
this.local = new Storage(LocalStorage);
|
||||||
|
this.sql = new Storage(SQLStorage);
|
||||||
|
}
|
||||||
|
getLocal() {
|
||||||
|
this.local.get('name').then(value => {
|
||||||
|
alert('Your name is: ' + value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setLocal() {
|
||||||
|
let name = prompt('Your name?');
|
||||||
|
|
||||||
|
this.local.set('name', name);
|
||||||
|
}
|
||||||
|
removeLocal() {
|
||||||
|
this.local.remove('name');
|
||||||
|
}
|
||||||
|
|
||||||
|
getSql() {
|
||||||
|
this.sql.get('name').then(value => {
|
||||||
|
alert('Your name is: ' + value);
|
||||||
|
}, (errResult) => {
|
||||||
|
console.error('Unable to get item from SQL db:', errResult);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setSql() {
|
||||||
|
let name = prompt('Your name?');
|
||||||
|
|
||||||
|
this.sql.set('name', name);
|
||||||
|
}
|
||||||
|
removeSql() {
|
||||||
|
this.sql.remove('name');
|
||||||
|
}
|
||||||
|
}
|
13
ionic/components/app/test/storage/main.html
Normal file
13
ionic/components/app/test/storage/main.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<ion-view>
|
||||||
|
<ion-content padding>
|
||||||
|
<h2>Local Storage</h2>
|
||||||
|
<button primary (click)="getLocal()">Get</button>
|
||||||
|
<button primary (click)="setLocal()">Set</button>
|
||||||
|
<button primary (click)="removeLocal()">Remove</button>
|
||||||
|
|
||||||
|
<h2>SQL Storage</h2>
|
||||||
|
<button primary (click)="getSql()">Get</button>
|
||||||
|
<button primary (click)="setSql()">Set</button>
|
||||||
|
<button primary (click)="removeSql()">Remove</button>
|
||||||
|
</ion-content>
|
||||||
|
</ion-view>
|
@ -10,6 +10,10 @@ export * from './components'
|
|||||||
export * from './platform/platform'
|
export * from './platform/platform'
|
||||||
export * from './platform/registry'
|
export * from './platform/registry'
|
||||||
|
|
||||||
|
export * from './storage/storage'
|
||||||
|
export * from './storage/local-storage'
|
||||||
|
export * from './storage/sql'
|
||||||
|
|
||||||
export * from './util/click-block'
|
export * from './util/click-block'
|
||||||
export * from './util/focus'
|
export * from './util/focus'
|
||||||
|
|
||||||
|
37
ionic/storage/local-storage.ts
Normal file
37
ionic/storage/local-storage.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import {StorageStrategy} from './storage';
|
||||||
|
|
||||||
|
export class LocalStorage extends StorageStrategy {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
get(key) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
let value = window.localStorage.getItem(key);
|
||||||
|
resolve(value);
|
||||||
|
} catch(e) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
set(key, value) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
window.localStorage.setItem(key, value);
|
||||||
|
resolve();
|
||||||
|
} catch(e) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
remove(key) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
window.localStorage.removeItem(key);
|
||||||
|
resolve();
|
||||||
|
} catch(e) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
128
ionic/storage/sql.ts
Normal file
128
ionic/storage/sql.ts
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
import {StorageStrategy} from './storage';
|
||||||
|
|
||||||
|
import * as util from 'ionic/util';
|
||||||
|
|
||||||
|
const DB_NAME = '__ionicstorage';
|
||||||
|
|
||||||
|
export class SQLStorage extends StorageStrategy {
|
||||||
|
static BACKUP_LOCAL = 2
|
||||||
|
static BACKUP_LIBRARY = 1
|
||||||
|
static BACKUP_DOCUMENTS = 0
|
||||||
|
|
||||||
|
constructor(options) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
let dbOptions = util.defaults({
|
||||||
|
name: DB_NAME,
|
||||||
|
backupFlag: SQLStorage.BACKUP_NONE,
|
||||||
|
existingDatabase: false
|
||||||
|
}, options);
|
||||||
|
|
||||||
|
|
||||||
|
if(window.sqlitePlugin) {
|
||||||
|
let location = this._getBackupLocation(dbOptions);
|
||||||
|
|
||||||
|
this._db = window.sqlitePlugin.openDatabase(util.extend({
|
||||||
|
name: dbOptions.name,
|
||||||
|
location: location,
|
||||||
|
createFromLocation: dbOptions.existingDatabase ? 1 : 0
|
||||||
|
}, dbOptions));
|
||||||
|
} else {
|
||||||
|
console.warn('Storage: SQLite plugin not installed, falling back to WebSQL. Make sure to install cordova-sqlite-storage in production!');
|
||||||
|
|
||||||
|
this._db = window.openDatabase(dbOptions.name, '1.0', 'database', 5 * 1024 * 1024);
|
||||||
|
}
|
||||||
|
this._tryInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
_getBackupLocation(dbFlag) {
|
||||||
|
switch(dbFlag) {
|
||||||
|
case SQLStorage.BACKUP_LOCAL:
|
||||||
|
return 2;
|
||||||
|
case SQLStorage.BACKUP_LIBRARY:
|
||||||
|
return 1;
|
||||||
|
case SQLStorage.BACKUP_DOCUMENTS:
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
throw Error('Invalid backup flag: ' + dbFlag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the DB with our required tables
|
||||||
|
_tryInit() {
|
||||||
|
this._db.transaction((tx) => {
|
||||||
|
tx.executeSql('CREATE TABLE IF NOT EXISTS kv (key text primary key, value text)', [], (tx, res) => {
|
||||||
|
}, (tx, err) => {
|
||||||
|
console.error('Storage: Unable to create initial storage tables', tx, err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
|
||||||
|
this._db.transaction(tx => {
|
||||||
|
tx.executeSql("select key, value from kv where key = ? limit 1", [key], (tx, res) => {
|
||||||
|
if(res.rows.length > 0) {
|
||||||
|
let item = res.rows.item(0);
|
||||||
|
resolve(item.value);
|
||||||
|
}
|
||||||
|
resolve(null);
|
||||||
|
}, (tx, err) => {
|
||||||
|
reject({
|
||||||
|
tx: tx,
|
||||||
|
err: err
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}, err => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch(e) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
set(key, value) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
this._db.transaction(tx => {
|
||||||
|
tx.executeSql('insert or replace into kv(key, value) values (?, ?)', [key, value], (tx, res) => {
|
||||||
|
resolve();
|
||||||
|
}, (tx, err) => {
|
||||||
|
reject({
|
||||||
|
tx: tx,
|
||||||
|
err: err
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}, err => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
} catch(e) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
remove(key) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
try {
|
||||||
|
this._db.transaction(tx => {
|
||||||
|
tx.executeSql('delete from kv where key = ?', [key], (tx, res) => {
|
||||||
|
resolve();
|
||||||
|
}, (tx, err) => {
|
||||||
|
reject({
|
||||||
|
tx: tx,
|
||||||
|
err: err
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}, err => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
} catch(e) {
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
30
ionic/storage/storage.ts
Normal file
30
ionic/storage/storage.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/**
|
||||||
|
* Storage is an easy way to store key/value pairs and other complicated
|
||||||
|
* data in a way that uses the best possible storage layer underneath.
|
||||||
|
*/
|
||||||
|
export class Storage {
|
||||||
|
constructor(strategyCls: StorageStrategy) {
|
||||||
|
this._strategy = new strategyCls();
|
||||||
|
}
|
||||||
|
get(key) {
|
||||||
|
return this._strategy.get(key);
|
||||||
|
}
|
||||||
|
set(key, value) {
|
||||||
|
return this._strategy.set(key, value);
|
||||||
|
}
|
||||||
|
remove(key) {
|
||||||
|
return this._strategy.remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class StorageStrategy {
|
||||||
|
get(key, value) {
|
||||||
|
throw Error("Not implemented");
|
||||||
|
}
|
||||||
|
set(key, value) {
|
||||||
|
throw Error("Not implemented");
|
||||||
|
}
|
||||||
|
remove(key) {
|
||||||
|
throw Error("Not implemented");
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user