Header Ads Widget

Ticker

6/recent/ticker-posts

Simulando el complemento nativo SQLite en Ionic 4 y Angular

 En este tutorial, aprenderemos cómo simular el complemento nativo SQLite en proyectos Ionic 4 y Angular.

Gracias a Ionic Native, ahora podemos simular complementos nativos para proporcionar una clase falsa que tiene la misma API que el contenedor nativo para un complemento Cordova específico.

Puede usar simulacros simples que solo devuelven algunos valores proporcionados o puede crear simulacros completamente funcionales que transfieran la funcionalidad de un complemento nativo específico al navegador aprovechando una API de navegador equivalente o una biblioteca de JavaScript.

Así que comencemos creando un nuevo proyecto Ionic 4 basado en Angular e instalemos el contenedor SQLite nativo de Ionic.

Creación de un nuevo proyecto de Ionic 4

Abra su terminal / símbolo del sistema y ejecute el siguiente comando:

ionic start native-sqlite-mock blank --type=angular

Nota : tenga en cuenta que estamos utilizando Ionic CLI 5, que es la última versión. Puede instalar a través de npm ejecutando npm install -g ionic@latest.

Una vez que su proyecto esté completamente creado, navegue dentro de él y ejecute el siguiente comando para instalar el complemento SQLite nativo de Ionic:

cd native-sqlite-mock 
npm install --save @ionic-native/sqlite@4

Nota : No necesitamos agregar una plataforma Cordova o agregar el complemento Cordova SQLite ya que no vamos a desarrollar en el dispositivo real por ahora.

Después de instalar el complemento nativo, abra el src/app/app.module.tsarchivo y agréguelo a la lista de proveedores:

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

@NgModule({
declarations: [
    MyApp
    ],
imports: [
    BrowserModule,
    IonicModule.forRoot(MyApp)
],
bootstrap: [IonicApp],
entryComponents: [
    MyApp  
    ],
providers: [
    StatusBar,
    SplashScreen,
    SQLite 
    ]
})
export class AppModule {} 

Crear una base de datos SQLite

Ahora, creemos nuestra base de datos SQLite. Abra el src/pages/home/home.tsarchivo y hagamos lo siguiente:

  • Inyecte el complemento SQLite,
  • Declare un objeto del SQLiteObjecttipo,
  • Agregue una matriz para almacenar sus datos y una variable del tipo de número que se utilizará como contador.
  • Finalmente, cree una base de datos SQLite.

Abra el src/app/pages/home/home.page.tsarchivo y los siguientes cambios:

import { Component, OnInit } from '@angular/core';
import { SQLite, SQLiteObject } from '@ionic-native/sqlite';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss']
})
export class HomePage {

  public database: SQLiteObject;
  public invoices: Array<Object>; // our data  
  public counter : number = 0;

  constructor(private sqlite : SQLite) { }
  ngOnInit() {
    this.sqlite.create({name: "data.db", location: "default"})      .then((db : SQLiteObject) => {
                    this.database = db;
                }, (error) => {
                    console.log("ERROR: ", error);
     });
  } 
}

Regrese a su terminal y ejecute el siguiente comando para servir su aplicación localmente:

$ ionic serve 

A continuación, vaya a la http://localhost:8100dirección para jugar con su aplicación en el navegador.

Abra la consola del navegador, si cordova no está disponible el mensaje.

Esto se debe a que, a diferencia de los dispositivos reales, en el entorno del navegador, Cordova no está disponible.

Esto significa que el create()método no podrá crear una base de datos SQLite. cambiemos eso!

Burlarse del complemento SQLite

Queremos utilizar los métodos de la API de SQLite cuando desarrollamos en el navegador sin tener que cambiar nada cuando volvemos a un dispositivo real. Es por eso que necesitamos crear una simulación que tenga la misma API.

Los métodos más utilizados del complemento SQlite son:

  • El create()método para crear bases de datos SQLite.
  • El executeSql()método para ejecutar sentencias SQL en la base de datos creada.

Necesitamos crear un simulacro que al menos proporcione estos dos métodos.

Abra el src/app/app.module.tsarchivo y agregue la siguiente clase de TypeScript:

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

class SQLiteMock {
public create(config: SQLiteDatabaseConfig): Promise<SQLiteObject> {

    return new Promise((resolve,reject)=>{
        resolve(new SQLiteObject(new Object()));
    });
}
} 

A continuación, agregue la SQLiteMockclase bajo la useClasspropiedad del proveedor de SQLite:

providers: [
    StatusBar,
    SplashScreen,
    {provide: SQLite, useClass: SQLiteMock},
    {provide: ErrorHandler, useClass: IonicErrorHandler}
]
})

¡Eso es! Ha creado una simulación básica para el complemento SQLite. Ahora, si vuelve a su aplicación, no obtendrá el método Cordova Not Available ya que estamos usando el create()método de nuestra clase simulada en lugar del original.

Pero esta simulación no crea ninguna base de datos, por lo que no podemos simular el mismo entorno que si estuviéramos desarrollando en un dispositivo real, ¡cambiemos eso!

Dado que el navegador no tiene una forma compatible para usar SQLite, usaremos una biblioteca de JavaScript que proporciona una base de datos SQLite en memoria, es decir, la base de datos y todo su contenido vivirá en la memoria.

Así que adelante, tome la biblioteca y luego inclúyala usando una <script>etiqueta en el index.htmlarchivo de su proyecto justo antes de los archivos Ionic:

<script src="assets/sql.js"></script>

Dado que esta es una biblioteca de JavaScript, agregue la siguiente declaración en el src/app/app.module.tspara poder usarla:

declare var SQL;

Implementando el create()Método de SQLite

Ahora implementemos el create()método de nuestra clase simulada:

class SQLiteMock {
    public create(config: SQLiteDatabaseConfig): Promise<SQLiteObject> {

        //since this is an in memory database we can ignore the config parameters 

        var db = new SQL.Database();

        return new Promise((resolve,reject)=>{
            resolve(new SQLiteObject(db));
        });
    }
}

Implementando SQLiteObjectyexecuteSql()

Hasta ahora, estamos usando el original, SQLiteObjectpero necesitamos usar el nuestro para poder proporcionar una implementación del executeSql()método.

Así que adelante, elimine la declaración de importación de SQLiteObjecty cree una nueva clase que tenga un constructor que tome un objeto de base de datos que tenemos en el create()método.

El executeSql()método debe devolver una Promesa que puede rechazarse con una cadena de error o resolverse con una carga útil:

      var payload = {
        rows: {
          item: function(i) {
            return rows[i];
          },
          length: rows.length
        },
        rowsAffected: this._objectInstance.getRowsModified() || 0,
        insertId: this._objectInstance.insertId || void 0
      }; 

Y aquí está la clase completa:

class SQLiteObject{
    _objectInstance: any;

    constructor(_objectInstance: any){
        this._objectInstance = _objectInstance;
    };

    executeSql(statement: string, params: any): Promise<any>{

        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
                };  
                resolve(payload);
            } catch(e){
                reject(e);
            }
        });
    };

}

Nota : Los métodos create()executeSql()deben tener exactamente los mismos parámetros y tipos de retorno que los originales. Entonces podemos obtener el mismo comportamiento, cuando intercambiamos el complemento original en el dispositivo real

Puede mirar el contenedor Ionic Native de SQLite y también el complemento SQLite Cordova para obtener las firmas exactas y los tipos de devolución de estos métodos.

Prueba del complemento SQLite simulado

Ahora, probemos nuestro complemento SQLite falso.

Crear una tabla SQL

Agreguemos un createTable()método para crear una invoicestabla:

public createTable(){
    this.database.executeSql('create table if not exists invoices(name VARCHAR(32))', {})
        .then(() => {
            console.log('Table Invoice created !');

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

Insertar datos en la tabla SQL

A continuación, agregue un método para insertar algunas facturas en la tabla creada:

public counter : number = 0;
public insertInvoice(){
    var c = 'INV' + this.counter; 
    this.database.executeSql("INSERT INTO invoices (name) VALUES (?)", [c]).then((data) => {
            console.log("INSERTED: ");
            this.counter++;
            this.showInvoices();
        }, (error) => {
            console.log("ERROR: " + JSON.stringify(error.err));
        });    
}

Enumere los datos de la tabla

Cree el showInvoices()método que enumera todas las facturas insertadas:

public invoices: Array<Object>;  
public showInvoices(){
    this.database.executeSql("SELECT * FROM invoices", []).then((data) => {
            this.invoices = [];
            if(data.rows.length > 0) {
                for(var i = 0 ; i < data.rows.length ; i++) {
                    this.invoices.push({ name: data.rows.item(i).name });
                }
            }
        }, (error) => {
            console.log("ERROR: " + JSON.stringify(error));
        });    
}

A continuación, cambie el código dentro del ngOnInit()método de la siguiente manera:

ngOnInit(){
        this.sqlite.create({name: "data.db", location: "default"}).then((db : SQLiteObject) => {
                this.database = db;
                this.createTable();
            }, (error) => {
                console.log("ERROR: ", error);
        });    
}

Nota : No olvide inyectar el proveedor SQLite a través del constructor de la página de inicio.

Finalmente, abra el src/app/pages/home/home.page.htmlarchivo y agregue un botón para activar el método para insertar facturas y una lista para mostrar las facturas en nuestra base de datos SQLite

Ejemplo simulado de Ionic 4 SQLite

<ion-content padding>
    <button ion-button (click)="insertInvoice()">Insert Invoice</button>
    <ion-list>
    <ion-item *ngFor="let invoice of invoices">

    </ion-item>
</ion-list>
</ion-content>

Guardar la base de datos SQLite

Dado que estamos usando una base de datos SQLite en memoria, cuando nuestra aplicación se recarga, el contenido de la base de datos se pierde.

Esto no es un problema porque son solo datos de prueba, pero para evitar volver a ingresar los datos cada vez que la aplicación se recarga, guardemos la base de datos SQLite y volvamos a cargarla cuando la aplicación se recargue.

Afortunadamente para nosotros, nuestra biblioteca JavaScript tiene un método de exportación para exportar la base de datos en memoria a una matriz de bytes.

Puede usar el almacenamiento local o la base de datos IndexedDB en el navegador para guardar la base de datos en memoria cada vez executeSql()que se invoca el método.

Cambie de la executeSql()siguiente manera:

executeSql(statement: string, params: any): Promise<any>{

  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);
    }
  });
};

A continuación, cambie el create()método de la SQLiteMocksiguiente manera:

class SQLiteMock {
public create(config: SQLiteDatabaseConfig): Promise<SQLiteObject> {
    var db;
    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));
    });
}
}

El método busca un elemento de la base de datos en el almacenamiento local. Si existe, se pasa a SQL.Database().

La base de datos se guarda como una cadena, por lo que se vuelve a analizar en una matriz de bytes.

Conclusión

Ahora puede desarrollar aplicaciones Ionic 4 que hacen uso del complemento SQLite nativo completamente en el navegador gracias a las simulaciones nativas de Ionic.

Publicar un comentario

0 Comentarios