capacitor-community / sqlite

Community plugin for native & electron SQLite databases
MIT License
426 stars 104 forks source link

addSQLiteSuffix or moveDatabasesAndAddSuffix doesn't copy data inside the original database #497

Closed GuillaumeUnice closed 3 months ago

GuillaumeUnice commented 4 months ago

Describe the bug I migrate a database from cordova-sqlite-storage plugin to @capacitor-community/sqlite. I deploy on Android and iOS but for now lets focus on Android and even Android studio emulator. When I look on the "databases/" folder of the app the database has been properly copy with the suffix SQLite.db but when I open it it's utterly empty. If I copy myself by hand and adding the suffix ; I obtain the data and everything is alright. I do not have any encryption type or anything and the fact by hand is working is a kind of proof. Maybe I missing something about addSQLiteSuffix

I read all the previous issue and I know @jepiqueau you were quite aware of such issue so If you have any idea or already encounter such misadventure?

Capture d’écran 2023-12-27 à 16 01 56

Expected behavior Create the database but also copy the data inside

Smartphone (please complete the following information):

Thanks in advance

jepiqueau commented 4 months ago

@GuillaumeUnice On Android in which location were the cordova databases. Can you share the part of the code where you do the database conversion

GuillaumeUnice commented 4 months ago

So the location paths is correctly inside 'databases/' directory More accuratly: "/data/data/myappname.app/databases/MYDATABASENAMESQLite.db"

I basically copy past the example of your ionic7-angular-sqlite part 1 here and here tutorial great one by the way.

And to test the database copy I just add inside the SQLiteService initializePlugin method the execution of moveDatabasesAndAddSuffix or addSQLiteSuffix

The code becoming

  async initializePlugin(): Promise<boolean> {
    console.log("initializePlugin");
    Capacitor.Plugins.
    this.platform = Capacitor.getPlatform();
    if (this.platform === "ios" || this.platform === "android") this.native = true;
    this.sqlitePlugin = CapacitorSQLite;
    this.sqliteConnection = new SQLiteConnection(this.sqlitePlugin);
    await this.sqliteConnection.moveDatabasesAndAddSuffix();
    this.isService = true;
    return true;
  }
jepiqueau commented 4 months ago

@GuillaumeUnice Have you read the doc MigratingCordovaDatabases.

GuillaumeUnice commented 4 months ago

Yes sure of course why? does it make no sense to call the function here?

Because the database with suffix is correctly create but not hydratate. And again if I copy paste manually by adding the suffix and extension everything work.

jepiqueau commented 4 months ago

@GuillaumeUnice the doc said addSQLiteSuffix and not moveDatabasesAndAddSuffix

GuillaumeUnice commented 4 months ago

Yes yes I start first with addSQLiteSuffix and no parameter inside because the cordova plugin was default as mentionned into the documentation you forward

jepiqueau commented 4 months ago

@GuillaumeUnice I got the issue identified so i do some more testing and it will be fixed in the next release. Sorry for the inconvenience

GuillaumeUnice commented 4 months ago

Oh great! Let me know whether you need further information or any help around it ;)

You can't ever know how helpful such feature will help on my project.

jepiqueau commented 4 months ago

@GuillaumeUnice this may take some time as after installing the latest release of Android Studio and the API 34, i cannot make a build and i could not find the reason nothing to do with my code so be patient

jepiqueau commented 4 months ago

@GuillaumeUnice an you test the new release and tell me if it works as i still cannot test it myself

jepiqueau commented 4 months ago

@GuillaumeUnice i finally succeed to test it so i close the issue

GuillaumeUnice commented 4 months ago

Sorry I test it only now and it still doesn't copy the data from the original database to the new one.

I check your code you just modify the case whether no "default" was pass down. But it wasn't the problem I encounter because it already was able to create the database with SQLite.db extension but not data was copy from the original one.

I do not have great knowledge in Java but I found the call of addSQLiteSuffix in fine execute copyFileFromFile and I guess it's somewhere here that it doesnt copy it properly.

But I guess you are not able to reproduce?

jepiqueau commented 4 months ago

@GuillaumeUnice i test this:

export class TestIssue497 implements OnInit {
  log: string = "";
  platform: string;
  handlerPermissions: any;
  initPlugin: boolean = false;

  constructor(private _sqlite: SQLiteService) {
    this.platform = this._sqlite.platform;
  }

  async ngOnInit() {
    const showAlert = async (message: string) => {
      await Dialog.alert({
        title: 'Error Dialog',
        message: message,
      });
    };
    try {
      await this.runTest();
      document.querySelector('.sql-allsuccess').classList
        .remove('display');
      console.log("$$$ runTest was successful");
    } catch (err) {
      document.querySelector('.sql-allfailure').classList
        .remove('display');
      console.log(`$$$ runTest failed ${err.message}`);
      await showAlert(err.message);
    }
  }

  async runTest(): Promise<void> {
    this.log += "* Starting testissue497 *\n";

    // test get the Database List in the
    let result = await this._sqlite.getDatabaseList();
    console.log(`test get Database List: ${JSON.stringify(result)}`)
    const nInitDbs = result.values.length;
    console.log(`$$$ nInitDbs: ${nInitDbs}`);

    // Cordova databases in the default folder
    const dbMigratableList = await this._sqlite.getMigratableDbList();
    console.log(`dbMigratableList ${JSON.stringify(dbMigratableList)}`)
    const nInitMgDbs = dbMigratableList.values.length;
    if(nInitMgDbs !== 1) {
      return Promise.reject(new Error("GetMigratableDbList from default failed"));
    }
    await this._sqlite.addSQLiteSuffix();
    result = await this._sqlite.getDatabaseList();
    console.log(`$$$ result.values.length: ${result.values.length}`);
    console.log(`$$$ nInitDbs + 1 : ${(nInitDbs + 1)}`);

    if( result.values.length !== (nInitDbs + 1)){
      return Promise.reject(new Error("AddSQLite from default failed"));
    }

    // Cordova databases in another folder
    const directory: string = this.platform === "ios" ? "Applications/Files/Databases" : "files/databases" ;
    const dbMigratableList1 = await this._sqlite.getMigratableDbList(directory);
    console.log(`dbMigratableList1 ${JSON.stringify(dbMigratableList1)}`)
    const nMgDbs = dbMigratableList1.values.length;
    if(nMgDbs !== 3) {
      return Promise.reject(new Error("GetMigratableDbList failed"));
    }
    await this._sqlite.addSQLiteSuffix(directory, dbMigratableList1.values);
    result = await this._sqlite.getDatabaseList();
    if( result.values.length !== (nInitDbs + 4)){
      return Promise.reject(new Error("AddSQLite final failed"));
    }
    if (this.platform === "ios") {
      // test with folder Library/CapacitorDatabase
      const lcdir = "Library/CapacitorDatabase";
      const dbMigratableList2 = await this._sqlite.getMigratableDbList(lcdir);
      console.log(`dbMigratableList2 ${JSON.stringify(dbMigratableList2)}`)
      const nLCMgDbs = dbMigratableList2.values.length;
      if(nLCMgDbs !== 1) {
        return Promise.reject(new Error("GetMigratableDbList2 failed"));
      }
      await this._sqlite.addSQLiteSuffix(lcdir, dbMigratableList2.values);
      result = await this._sqlite.getDatabaseList();
      if( result.values.length !== (nInitDbs + 5)){
        return Promise.reject(new Error("AddSQLite final ios failed"));
      }
      }
    this.log += "* Ending testissue497 *\n";
  }

}

i had initially image

so i want to migrate testcopy.db from the default folder and keep1.db, testfromfile.db,WOP_DATABASE.db from the files/databases folder

and after running the code

image

this is why i said it is fixed You may still have to delete the cordova databases

jepiqueau commented 4 months ago

@GuillaumeUnice you can see that the size of the db are correct image

jepiqueau commented 4 months ago

@GuillaumeUnice Do your file got an extension .db ?

jepiqueau commented 4 months ago

@GuillaumeUnice I also made a test by removing the extension of the keep1 database and it still work

image

So i do not know what to do more. May be you can debug your app and but some break points

and then Run -> Debug 'app' and do step by step and tell me what is going on

jepiqueau commented 4 months ago

@GuillaumeUnice i thought it may be due to the size of the database so i created a 20Mb database and make the test and it is still running image

So now i am waiting the result of your debug

GuillaumeUnice commented 4 months ago

Wow thank you so much for all the tests. So the problem is related to the .db extension as you mentionned.

But it's when it's located on /databases directory not /files one and that where it cordova plugin create the database. When I add manually the extension all the data are correctly copy when I remove it doesn't work anymore

Could you test that on your side by doing exactly what you do on your last test but instead of keep1 database doing it on large.db without .db extension?

GuillaumeUnice commented 3 months ago

@jepiqueau Could you be able to retest the scenario on large.db? Or you are not in capacity to perform it anymore?

jepiqueau commented 3 months ago

@GuillaumeUnice i did it and it works too.

Initial State

Test_issue#497_init

Final State

Test_issue#497_final

Sorry for the lateness So there is nothing i can do more

jepiqueau commented 3 months ago

@GuillaumeUnice As you do not comment i assume it is fixed so i close the issue

GuillaumeUnice commented 3 months ago

Hi @jepiqueau thanks for your help!

I got something working now and perhaps I wasn't understand properly last time. Because I take your test in consideration and when miming the directory path I obtain an error not found throw:

    const directory: string = this.platform === "ios" ? "Applications/Files/Databases" : "files/databases" ;

Nevertheless without specifying the path it works so with the following code:

const dbMigratableList1 = await this.sqliteConnection.getMigratableDbList();
console.log(`dbMigratableList1 ${JSON.stringify(dbMigratableList1)}`);

await this.sqliteConnection.addSQLiteSuffix(null, dbMigratableList1.values); // here null pass down

So I found a bit strange the lib doesnt work whether I do not pass down dbNameList but perhaps it's logical after all. And it create the empty database only.

So thanks for your help the ticket can be closed now indeed ;)