Downloading and using an sqlite db file - where does it go?


#1

I’ve been wrestling with this issue for way longer than I care to say…

What I want to do is download an sqlite db via http and use it in the app. I think the http part is working, but the file may not be saved to the correct location (the app folder). Here’s some minimal code:

exports.onLoaded = function (args) {

  var filesFolder = fs.knownFolders.currentApp(); // create folder object
  var dbfile = filesFolder.getFile("sample.db"); // create file object 
  console.log("dbfile.path: " + dbfile.path);

  http.getFile("http://ravenrockramble.org/db/sample.db", dbfile.path)
    .then(function (newFile) {
      console.log("newfile.path: " + newFile.path);
      console.log("FILE LENGTH: " + newFile.readSync().length);

      try {
        if (sqlite.exists("sample.db")) {
          sqlite.deleteDatabase("sample.db");
        }
        sqlite.copyDatabase("sample.db");  // Copy database from /apps folder to appropriate database folder
        if (sqlite.exists("sample.db")) {
          console.log("sample.db exists");
        }
      }
      catch (err) {
        console.log(err.message);
      }
    });
}

And here’s the console output:

JS: dbfile.path: /data/data/org.nativescript.httptest/files/app/sample.db
JS: newfile.path: /data/data/org.nativescript.httptest/files/app/sample.db
JS: FILE LENGTH: 12288
JS: java.io.FileNotFoundException: app/sample.db

I’ve never been able to find the sample.db file via Finder (I’m on a Mac); it may be hidden or obscured in some way, and the path (data/data…) must be some sort of symlink as I can’t find that either. So, here are my questions:

The sqlite docs say any db provided with the app should be placed in the app folder. But, does fs.knownFolders.currentApp() return the same value, just from where the app is running? I’d expect so, but I can’t find anything to confirm this, and I get the missing file error from sqlite.copyDatabase.

I’d really appreciate any pointers here.


#2

So, I ran an additional test, placed the file text.txt in the /app folder, then used

  var txtfile = filesFolder.getFile("text.txt"); // create file object 
  console.log(txtfile.readTextSync());

To correctly echo the contents to the console. So, now my question is, how can I verify that the http.getFile actually saves the file in the specified location? That now seems to be the point of failure.


#3

I may have answered my own question… the knownFolders doc state that the currentApp folder is read-only. So, that would explain why the http.getFile() seems to fail. But, now I seem to be in a catch-22, as sqlite.copyDatabase only copies from the app folder :-(.

So, next new question… if I download the file to the, say, temp folder, is there a way to move it to either the app folder (which seems unlikely) or the database folder required by the sqlite plugin?


#4

For folks following along at home, here’s the solution I ended up with: just download the database file directly to the database folder. Namely,

    if (platform.isAndroid) {
      var context = utils.ad.getApplicationContext();
      dbPath = context.getDatabasePath(db.name).getAbsolutePath();
    }
    else { // (iOS)
      dbFolder = fs.knownFolders.documents().path;
      dbPath = dbFolder + "/" + db.name;
    }

    http.getFile(db.url, dbPath) 

Where db.name = the filename such as “people.db” and db.url is the full, secure http link such as “https://mydomain.com/db/people.db”.

There’s more code, of course, to handle the asynchronous calls and error conditions, but I was ultimately able to get this to work OK.


#5

I may have spoken too early. This seems to work everywhere except actual Android devices, where http-request.js throws a FileNotFoundException with the line,

stream = new java.io.FileOutputStream(javaFile);

From the Java docs:

FileNotFoundException - if the file exists but is a directory rather than a regular file, does not exist but cannot be created, or cannot be opened for any other reason

So, I’m really not certain what the error is, or why it would work on an emulator but not the device.


#6

You were right about sqlite plugin, the copy function presumes that you want to copy from current app directory which could be read only. The solution is to copy the file yourself, try to not read it as text and write. Directly write it as binary data.


#7

@manojdcoder - thanks for the reply. I woke up at 4:00am this morning with the realization that I had seen code in the sqlite plug-in that handles the case where the database folder does not exist by default on some Android systems. That would certainly explain the error I’m seeing. I’ll check that out and report back.


#8

Yep - creating the folder solved the problem. I used basically the same code from sqlite:

    var javaFile = new java.io.File(dbFolder);
    if (!javaFile.exists()) {
      javaFile.mkdirs();
      javaFile.setReadable(true);
      javaFile.setWritable(true);
    }