在Ionic中,SQLite模拟无法正常工作

3
我遇到了SQLiteMock提供程序无法被识别的问题。在使用"{ provide: SQLite, useClass: SQLiteMock }"时,我的理解是应该使用SQLiteMock类而不是SQLite。但实际上除非我明确指定要使用SQLiteMock并将其传递给Techdao.ts,否则我不会有这种体验。我错过了什么或做错了什么吗?
我正在使用Ionic 3。 app.module.ts
import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { StatusBar, Splashscreen } from 'ionic-native';
import { SQLite, SQLiteDatabaseConfig } from '@ionic-native/sqlite';
import { MyApp } from './app.component';
import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { Page1 } from '../pages/page1/page1';

declare var SQL;
class SQLiteMock {
    public create(config: SQLiteDatabaseConfig): Promise<SQLiteObject> {
        console.log("Create Mock SQLite Database.");
        var db = new SQL.Database();
        return new Promise((resolve, reject) => {
            resolve(new SQLiteObject(db));
        });
    }
}

class SQLiteObject {
    _objectInstance: any;
    constructor(_objectInstance: any) {
        this._objectInstance = _objectInstance;
    };
    public create(config: SQLiteDatabaseConfig): Promise<SQLiteObject> {
        var db;

        console.log("Open Mock SQLite Database.");
        var storeddb = localStorage.getItem("database");

        var arr = storeddb.split(',');
        if (storeddb) {
            db = new SQL.Database(arr);
        }
        else {
            db = new SQL.Database();
        }

        return new Promise((resolve, reject) => {
            resolve(new SQLiteObject(db));
        });
    }
    executeSql(statement: string, params: any): Promise<any> {
        console.log("Mock SQLite executeSql: " + statement);

        return new Promise((resolve, reject) => {
            try {
                var st = this._objectInstance.prepare(statement, params);
                var rows: Array<any> = [];
                while (st.step()) {
                    var row = st.getAsObject();
                    rows.push(row);
                }
                var payload = {
                    rows: {
                        item: function (i) {
                            return rows[i];
                        },
                        length: rows.length
                    },
                    rowsAffected: this._objectInstance.getRowsModified() || 0,
                    insertId: this._objectInstance.insertId || void 0
                };

                //save database after each sql query 
                var arr: ArrayBuffer = this._objectInstance.export();
                localStorage.setItem("database", String(arr));
                resolve(payload);
            } catch (e) {
                reject(e);
            }
        });
    };
}

@NgModule({
  declarations: [
    MyApp,
    Page1
  ],
  imports: [
      BrowserModule,
      HttpModule,
      IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    Page1
  ],
  providers: [
      StatusBar,
      Splashscreen,
      { provide: SQLite, useClass: SQLiteMock },
      { provide: ErrorHandler, useClass: IonicErrorHandler }
  ]
})
export class AppModule { }`

app.component.ts

import { Component, ViewChild } from '@angular/core';
import { Nav, Platform } from 'ionic-angular';
import { StatusBar, Splashscreen } from 'ionic-native';
import { SQLite, SQLiteObject } from '@ionic-native/sqlite';

@Component({
  templateUrl: 'app.html'
})
export class MyApp {
  @ViewChild(Nav) nav: Nav;

  rootPage: any = Page1;

  public sqlstorage: SQLite;
  techdao: TechDAO;

  pages: Array<{title: string, component: any}>;

  constructor(public platform: Platform) {
      console.log("Platforms: " + platform.platforms());
      this.initializeApp();
  }

  initializeApp() {
    this.platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      StatusBar.styleDefault();

      this.initializeSQLite();

      Splashscreen.hide();

    });
  }

  initializeSQLite() {
      this.sqlstorage = new SQLite();
      this.techdao = new TechDAO(this.sqlstorage);

      this.techdao.createTables(); 
  }

  openPage(page) {
    // Reset the content nav to have just this page
    // we wouldn't want the back button to show in this scenario
    this.nav.setRoot(page.component);
  }  
}

techdao.ts

import { SQLite, SQLiteDatabaseConfig, SQLiteObject } from '@ionic-native/sqlite';

export class TechDAO {
    sqlite: any;
    db: SQLiteObject;

    constructor(private _sqlite: SQLite) {
        this.sqlite = _sqlite;
    };

    public createTables() {
        this.sqlite.create({
            name: 'tech.db',
            location: 'default'
        }).then((_db: SQLiteObject) => {
            console.log("Create Database tables if they don't exist.");
            this.db = _db;

            this.createAppointmentTable();
        }).catch(e => console.log(e));  
    }

    createAppointmentTable() {
        this.db.executeSql(
            'create table if not exists appointment(' +
            'ticketnumber TEXT PRIMARY KEY,' +
            'customername TEXT,' +
            'contactemail TEXT,' +
            'contactphone TEXT' +
            ')', {})
            .then(() => console.log('Executed SQL - Create Appointment Table'))
            .catch(e => console.log(e));
    }    
}
1个回答

1
你已经接近成功了。
添加 { provide: SQLite, useClass: SQLiteMock } 是不够的。
你需要导入和使用自己的 SQLiteMock 而不是标准库。
所以,如果你有以下的 Camera 模拟程序:
import { NgModule, ErrorHandler } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';

import { Camera } from '@ionic-native/camera';

class CameraMock extends Camera {
  getPicture(options) {
    return new Promise((resolve, reject) => {
      resolve("BASE_64_ENCODED_DATA_GOES_HERE");
    })
  }
}

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    { provide: Camera, useClass: CameraMock }
  ]
})
export class AppModule {}

然后在另一个 .ts 文件中,您将使用 Camera 的地方,您必须使用自己的 CameraMock

import { CameraMock } from "../mocks/camera-mock";

当你完成了功能的开发后,编辑你的代码以切换回使用实际的相机。你甚至可以通过环境变量巧妙地使用不同的库来进行开发和生产构建。

啊,好的,那么我最初的想法实际上已经存在了。我已经在使用SQLite的地方添加了我的SQLiteMock导入。当我不处于开发状态并且需要进行生产构建或UAT构建时,我希望能够将SQLiteMock替换为SQLite。 - Adam
这超出了您最初问题的范围。无论如何,正如我所说,您可以使用Angular的函数isDevMode()并在每种情况下使用不同的库(SQLite或SQLiteMock)。如果一个功能足够小,我更喜欢在完成后直接交换导入,但您也可以选择任一种方法。 - maninak
谢谢你的帮助!我非常感激,isDevMode()给了我另一个提示!谢谢! - Adam
总是很高兴能够提供帮助。干杯,伙计! :) - maninak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接