sqlite: sqllite.ImportFromJson not working

Describe the bug When importing json it doens’t create the route table. When we try to collect things it give the error that the routes table doesn’t excist

To Reproduce Steps to reproduce the behavior:

Use this json object: const JSONSchema = { database: 'storage', version: 1, encrypted: false, mode: 'full', tables: [ { name: 'routes', schema: [ { column: 'id', value: 'TEXT NOT NULL'}, { column: 'name', value: 'TEXT NOT NULL' }, { column: 'date', value: 'TEXT NOT NULL' }, { constraint: 'routes_pk', value: 'PRIMARY KEY (id)'}, ], indexes: [ { name: 'routes_id_uindex', value: 'id' }, { name: 'routes_id_uindex', value: 'name' }, ], }, { name: 'route_points', schema: [ { column: 'id', value: 'INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL' }, { column: 'route_id', value: 'TEXT NOT NULL' }, { column: 'accuracy', value: 'REAL' }, { column: 'altitude', value: 'REAL' }, { column: 'altitudeAccuracy', value: 'REAL' }, { column: 'heading', value: 'REAL' }, { column: 'latitude', value: 'REAL' }, { column: 'longitude', value: 'REAL' }, { column: 'speed', value: 'REAL' }, { column: 'TIMESTAMP', value: 'INTEGER' }, { foreignkey: 'route_id', value: 'REFERENCES routes ON DELETE CASCADE', }, ], indexes: [ { name: 'route_points_id_uindex', value: 'id' }, ], }, ], }; and import it like this: const tableQuery = SELECT name FROM sqlite_master WHERE type=‘table’ AND name=‘routes’; const tableResult = await db.query(tableQuery); if (tableResult.values.length === 0) { await console.log('table bestaat niet') const result = await sqlite.isJsonValid(JSON.stringify(JSONSchema)); await console.log(result) if(!result.result) { throw new Error(isJsonValid: “schemaToImport179” is not valid); } const resJson = await sqlite.importFromJson(JSON.stringify(JSONSchema)); await console.log(resJson) if(resJson.changes && resJson.changes.changes && resJson.changes.changes < 0) { throw new Error(importFromJson: “full” failed); }

Expected behavior Create the routes table

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: Windows
  • Browser: Chrome

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 21

Most upvoted comments

@DanielvdSpoel if found the solution in fact the importFromJson requires to not have a connection open and close the connection after the import so the code should be

    try {
    if(platform === "web") {
      // Create the 'jeep-sqlite' Stencil component
      const jeepSqlite = document.createElement('jeep-sqlite');
      document.body.appendChild(jeepSqlite);
      await customElements.whenDefined('jeep-sqlite');
      // Initialize the Web store
      await sqlite.initWebStore();
    }

    let db = await getConnection("storage", sqlite)
    await db.open()

    // here you can initialize some database schema if required
    const isTable = await db.isTable('routes')
    console.log(`$$$ isTable ${JSON.stringify(isTable)}`);
    await sqlite.closeConnection("storage");
    if (!isTable.result) {
      await console.log('table bestaat niet')
      const result = await sqlite.isJsonValid(JSON.stringify(JSONSchema));
      console.log(result)
      if(!result.result) {
        throw new Error(`isJsonValid: "schemaToImport179" is not valid`);
      }
      const resJson = await sqlite.importFromJson(JSON.stringify(JSONSchema));
      console.log(JSON.stringify(resJson))
      if(resJson.changes && resJson.changes.changes && resJson.changes.changes < 0) {
        throw new Error(`importFromJson: "full" failed`);
      }
      db = await getConnection("storage", sqlite)
      await db.open()
      const isTable1 = await db.isTable('routes')
      console.log(`$$$ isTable1 ${JSON.stringify(isTable1)}`);
      await sqlite.closeConnection("storage");
    }

    router.isReady().then(() => {
      app.mount('#app');
    });
  } catch (err) {
    console.log(`Error: ${err}`);
    throw new Error(`Error: ${err}`)
  }

the database is stored as an Uint8Array in a localforage key/value pair database.

Voilà, it is now working fine. the closeConnection close also the db so you do not need to have db.close and sqliteCloseConnection. as sometimes in RouteModule you close the db without closing the connection you may change your connection.js as follows:

export async function getConnection(database, sqlite) {
    const ret = await sqlite.checkConnectionsConsistency();
    const isConn = (await sqlite.isConnection(database)).result;
    let db
    let isOpen
    if (ret.result && isConn) {
        db = await sqlite.retrieveConnection(database);
        isOpen = await db.isDBOpen();
        console.log(`>>> isOpen ${JSON.stringify(isOpen)}`)
        if (!isOpen.result) {
            await db.open();            
        }
    } else {
        db = await sqlite.createConnection(database, false, "no-encryption", 1);
        await db.open();
    }
    return db;
}

and then remove all the db.open() in main.js and RouteModule.js.

an other thing is about the db.close in RouteModule.js i do not think it is required if you have modified the getConnection as above. The only reason for it is for the web version as it will save the data to store which i think is a good idea. so better to use for the web the sqlite.saveToStore(database) for the web only so the RouteModules should be modified as follows:

const RouteModule = {
    namespaced: true,
    getters: {
        getRoutes: () => async (sqlite) => {
            try {
                const platform = Capacitor.getPlatform();
                const db = await getConnection("storage", sqlite);
                const query = `SELECT * FROM routes;`
                const result = await db.query(query);
                const routes = []
                for (const route in result.values) {
                    const query = `SELECT * FROM route_points where route_id = '${result.values[route].id}';`
                    const pointsResult = await db.query(query);
                    await routes.push(new Route(result.values[route], pointsResult.values))
                }
                console.log(routes)
                if(platform === "web") {
                    await sqlite.saveToStore("storage");
                }
                return routes;

            } catch (e) {
                console.log("Routes ophalen is fout gegaan")
                console.log(e)
            }
        },
        getRoute: () => async (id, sqlite) => {
            try {
                const platform = Capacitor.getPlatform();
                const db = await getConnection("storage", sqlite)
                const routeQuery = `SELECT * FROM routes where id = '${id}';`
                const routeResults = await db.query(routeQuery);
                const route = routeResults.values[0]
                console.log(route)
                const pointQuery = `SELECT * FROM route_points where route_id = '${route.id}';`
                const pointsResult = await db.query(pointQuery);
                if(platform === "web") {
                    await sqlite.saveToStore("storage");
                }
                return new Route(route, pointsResult.values)

            } catch (e) {
                console.log("Routes ophalen is fout gegaan")
                console.log(e)
            }
        }
    },
    actions: {

        /* eslint-disable no-unused-vars */
        /** Save the recorded route to the database
         *
         * @param commit
         * @param state
         * @param dispatch
         * @param getters
         * @param payload
         */
        async saveRoute({commit, state, dispatch, getters}, payload) {

            //Collect name
            let name = payload.name
            if (!name) {
                const routes = await getters['getRoutes'](payload.sqlite)
                const routeNumber = routes.length + 1
                name = 'Fietstocht ' + routeNumber
            }

            //Collect date
            const first_location_point = payload.locationPoints[0]
            const date = new Date(first_location_point.timestamp).toISOString().split("T")[0]
            console.log(date)

            //Save to db
            try {

                const platform = Capacitor.getPlatform();
                const db = await getConnection("storage", payload.sqlite);
                const routeId = uuidv4()
                const query = `INSERT INTO routes (id, name, date) VALUES ('${routeId}', '${name}', '${date}');`
                const res = await db.run(query);

                for (const locationPoint of payload.locationPoints) {
                    const query = `INSERT INTO route_points (route_id, accuracy, altitude, altitudeAccuracy, heading, latitude, longitude, speed, timestamp) VALUES (
                    '${routeId}', '${locationPoint.accuracy}', '${locationPoint.accuracy}', '${locationPoint.altitudeAccuracy}', '${locationPoint.heading}', '${locationPoint.latitude}', '${locationPoint.longitude}', '${locationPoint.speed}', '${locationPoint.timestamp}');`
                    const res = await db.run(query);
                }

                if(platform === "web") {
                    await payload.sqlite.saveToStore("storage");
                }

            } catch (e) {
                console.log("Opslaan is fout gegaan")
                console.log(e)
            }

        },
    }
}

like this it is working fine on web on android i got an error with the timestamp of undefined but i test on the simulator Hope with this you will make some progress and find the solution for Android keep me in the loop