How to backup and restore an SQLite database? - react-native

I have an app built using React-Native and Expo's Managed workflow. I'm using Expo SDK 45. I'm managing the db using 'expo-sqlite'.
I need to provide the user the capability of backing up and restoring a local SQLite database.
My attempt was to use 'expo-file-system' and 'expo-sharing' to allow the user to save a copy of the database to the location of their choosing. This was done successfully.
My issue is in the user restoring the database. What I'm trying:
const importedFile = await DocumentPicker.getDocumentAsync();
await FileSystem.copyAsync({ "from": importedFile.uri, "to": FileSystem.documentDirectory + 'SQLite/tempDB.db' });
I then verify tempDB.db to ensure the structure is correct, i.e. the user isn't trying to import a wrong file.
I now have 2 issues:
If the user tries importing another database, I can delete the current tempDB.db but when the new one is imported, any attempt to access the new database fails with error Error code 10: disk I/O error. It seems that perhaps the system still believes it has an open connection to the deleted database.
If I overwrite the actual app database with the imported one, again there is no connection and nothing loads.
If I manually restart the app, all database connections are opened with the new files and everything works.
So, is there a better way to attempt this backup/restore functionality or is there a way to force the user to restart the app?

Related

Backup data with Async Storage - React Native

I am creating a note-taking app.
I want to enable users to backup their data manually by clicking 'backup' button, which will create a db backup file.
Upon reinstalling the app, users should be able to restore their data by importing the db backup file.
Would this be possible? I've already seen posts about using Gdrive and ICloud, but this is automatic. I wish to export and import the db file of AsyncStorage manually. For example, expecting API something like AsyncStorage.createDbFile or equivalent.
Alternative would be to JSON.stringify all the data in AsyncStorage and put that on a txt file and export that, but I don't think this is a good idea (or is it perfectly fine to do this?).
Thank you!

Storing large data in react native for offline usage

For our app we need the app the work offline 100% with the most recent data.
Normally the app uses a symfony api platform API to fetch data paginated server side.
But when someone is using the app in a area without Internet he still need to be able to access all data to make a new job and que it for when he is online.
So our tough is to make a json that has all the data and send it to the phone when the phone has connection.
When the phone is using the app live, it will use pagination from server and fetch data.
And when offline it will use the local downloaded data file.
Problem is the data is large, so storing it is the problem.
We are now using redux persist and we see so many people have problems with crashes and mobile ram.
We also thought of using sqlite or just async to store a json file, or download a sqlite file from the app.
How do you guys feel about this
You can use react-native-local-mongodb. This can help you store a json database on your phone.
Other option is to have react-native-sqlite-storage in case your database has to be relational and requires table.
You will have to sync this local copy with the server once this user is online. This too can be done if you have the timestamp saved of the last sync. So after that, you ll just have to sync the data created after that timestamp.
However, I had also implemented react redux persist and it didnt crash. I suppose, the reason for crash must me something else.

'Key not valid for use in specified state. (System.Security)' on registered server import (SSMS)

My computer recently crashed and I am getting things re-installed.
I would like to import the list of registered servers I had on my previous PC. I have both the RegSrvr.xml file from G:\Users\<user>\AppData\Roaming\Microsoft\Microsoft SQL Server\140\Tools\Shell
as well as backups (with username/passwords) of *.regsrvr files which I can move from my laptop.
I see that moving over the RegSrvr.xml file to the same location in the new PC does nothing at all.
And when I try to import the *.regsrvr files - I get an error 'Key not valid for use in specified state. (System.Security)' and only about half the list actually import.
Is there a way around this?
I had this issue after importing my SSMS Server registration file WITH PASSWORDS from a different computer. To fix this, I re-exported the Server registration "without passwords" from my other computer and re-imported that file without passwords. This worked however, you can edit the registrations as you go.
The issue is that the passwords are stored in an encrypted string in the file, and the encryption key used is specific to that machine where SSMS is installed. So when you export them then import on a new machine, you get that error because it can't decrypt/use the passwords.
Most people just re-export from the old machine without passwords, then after importing into the new SSMS on the new machine, they manually go fix all the passwords.
What I wanted to add was that since it's "just a text file", you can save a LOT of work by manually editing C:\Users\{user}\AppData\Roaming\Microsoft\SQL Server Management Studio\RegSrvr.xml.
What I did was import the file and ignore all of those errors
===================================
Key not valid for use in specified state. (System.Security)
------------------------------ Program Location:
at System.Security.Cryptography.ProtectedData.Unprotect(Byte[]
encryptedData, Byte[] optionalEntropy, DataProtectionScope scope)
at
Microsoft.SqlServer.Management.RegisteredServers.RegisteredServer.ProtectData(String
input, Boolean encrypt) at
Microsoft.SqlServer.Management.RegisteredServers.RegisteredServer.get_SecureConnectionString()
at
Microsoft.SqlServer.Management.RegisteredServers.RegisteredServer.get_ConnectionString()
at
Microsoft.SqlServer.Management.RegisteredServers.RegisteredServer.get_ServerName()
at
Microsoft.SqlServer.Management.RegisteredServers.RegisteredServerTree.AddRegisteredServerNode(RegisteredServer
regSrv, TreeNodeCollection nodes)
Then I went through this process:
In SSMS, fix a "server".
Over in the file, copy/paste that "good" encrypted password string over to all of the other "servers" that had a connection using the same password.
Restart SSMS.
Repeat as needed.
I like Granger's answer above because it's cumbersome for me to re-export from the other computer.
But instead of swapping password like Granger did above, I just deleted them (and you can re-input password from SSMS if needed). To remove password easily, use Notepad++ and search for password=[^;]*;
Use Regular Expression search.
Replace with blank.
I had a hard time migrating between two computers & was getting this error. Even after re-importing and deleting the xml file, I still got it. I ended up running the Import and Export Settings wizard & selecting "Reset all settings" which did work.

How do I create a Realm DB for a React Native app?

Maybe I'm thinking of this the wrong way, but how do I create a pre-populated Realm DB? For example, let's say I want to create a dictionary with 1000 words and definitions in it. The user can change the definitions from within the app, but initially the DB will have default definitions.
Can I create a .realm file with the 1000 words and definitions and include it in my app?
FYI: I am using Realm with React Native and I am currently testing using emulator -avd CordovaAVD to launch my Android emulator.
I think I've figured this out so I'll post my solution in case anyone else might find it useful.
I have a function that will populate a Realm DB. Once I run that function, however, I want to grab that static DB and use it instead of generating the DB every time the app starts up. That's what prompted my effort. However, these steps will also be useful if you just want to back up a DB.
I am primarily testing using an emulator, but I think these steps will work if you test on an actual device.
To grab the Realm DB from the emulator:
Find the path to your realm file within the phone by adding this somewhere in your code:
let YourRealmDB = new Realm({schema: [YourSchema]});
console.log('YourRealmDB path =', YourRealmDB.path);
The path will be something like
/data/data/(package.name)/files/(filename).realm
"filename" will probably be "default"
From the command line, run
adb exec-out run-as (package.name) cat files/(filename).realm > (filename).realm
This will copy your Realm db to your current directory
Now, to use that DB in your app:
Create a realm object:
let YourRealmDB = new Realm({schema: [YourSchema]});
Set the objects path to your DB:
YourRealmDB.defaultPath = 'path/to/your/db/(filename).realm';
NOTE: If you use a 'local' DB like this and your app performs a write operation, it will not write
to your local DB. It will write to the db at YourRealmDB.path. So if you want to copy or
view the updated DB, you will need to run adb exec-out run-as (package.name) cat files/(filename).realm > (filename).realm
again to get the most current version of your DB.
I hope that helps. It took me quite a while to piece that all together.

Ideal location of db on IOS

I am using phonegap for IOS app development. Now, phonegap tries to find the db by default in 'NSCachesDirectory', but whenever IOS runs into memory problems, it tries to delete data from 'NSCachesDirectory', so, the data is not secured. If i am not mistaken, this problem was solved in cordova 2.1.0, where the back-up of data is taken and then restored afterwards. So, just wanted to confirm if i am heading in the right direction or data itself can be stored in 'NSDocumentDirectory' so that data is secured and somehow phonegap looks for db in 'NSDocumentDirectory' and not Caches direcory. Thanks.
Only documents and other data that is user-generated, or that cannot otherwise be recreated by your application, should be stored in the /Documents directory(You can store DB in Documents directory)
Data that can be downloaded again or regenerated should be stored in the /Library/Caches directory.