expo-sqlite don't keep data inserted in react native - reactjs

i create a program that save data to database in react native but when reopen expo and run again program
database were deleted and create new empty database
async save() {
if (!(await FileSystem.getInfoAsync(FileSystem.documentDirectory + 'SQLite')).exists) {
await FileSystem.makeDirectoryAsync(FileSystem.documentDirectory + 'SQLite');
}
await FileSystem.downloadAsync(
Asset.fromModule(require('../assets/factor.db')).uri,
FileSystem.documentDirectory + 'SQLite/factor.db'
);
const db = SQLite.openDatabase('factor.db');
db.transaction((tx) => {
tx.executeSql("INSERT INTO factors (created_at,customer,sender,pay,off,description,customer_id)
values(?,?,?,?,?,?,1)",
[this.state.date, this.state.customer, this.state.sender, this.state.payment, this.state.offset,
this.state.description],
(trans, rows) => {
alert('factor added');
console.log(rows);
db._db.close();
},
(err, msg) => {
console.log(msg);
});
tx.executeSql(
"SELECT * FROM factors",
[],
(trans, res) => {
console.log(res.rows);
db._db.close();
},
(err, msg) => {
console.log(msg);
});
}, null);
}
and after run select sql return one row and dont show prev rows added before

Responding as I had this issue last week and it took me a while to find the answer. When running expo on my device the database changes are made to the local database on the device, not the pre-populated or blank database included as an asset in my code. Reloading the app without re-running "expo start" preserves the database on the device but stopping the server and re-running "expo start" will initiate a new app build which will overwrite any changes made in previous instances.

Related

Create React App PWA - change caching strategy of service worker

I have created a PWA template using CRA v4 and enabled the service worker that comes with it by registering it, because I needed to create a pop up notification about installing the PWA.
The lighthouse test has to pass for the app to be PWA compatible so that the browser would fire the beforeinstallprompt event listener needed to detect if the user has already installed the PWA or not.
The problem now is that this service worker is using cache-first strategy. As a result refreshing the page does not trigger an update and I am left with an older version of the app appearing after I have deployed an update.
How can I change the caching strategy of CRA v4's service worker such that the user would get a new version of the app by simply refreshing the page?
I am also interested in knowing why this cache-first strategy is used by default. To me it seems bad that the user has to close every tab to get a new version. Why haven't more people brought this up? This is clearly not user friendly...
To change the strategy you need to implement your own code changing service-worker.js and potentially
serviceWorkerRegistration.js. (https://developers.google.com/web/tools/workbox/modules/workbox-strategies)
I implement my own strategy:
check for updates at the very beginning check for updates each 3 min if there is a update in the very beginning update
cache and refresh the website. if it is after show a popup asking to fresh
serviceWorkerRegistration.ts
/**
* ...... previous code
**/
const CHECK_INTERVAL_TIME = 1000 * 60 * 3 // 3 min
function registerValidSW(swUrl: string, config?: Config) {
navigator.serviceWorker
.register(swUrl)
.then((registration) => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://cra.link/PWA.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.info('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
/****************************
start new code
*****************************/
registration.update().then(() => console.debug("Checked for update...")).catch(console.error)
setInterval(() => {
console.debug("Checked for update...");
registration.update().catch(console.error);
}, CHECK_INTERVAL_TIME);
/****************************
end new code
*****************************/
})
.catch((error) => {
console.error('Error during service worker registration:', error);
});
}
App.tsx
/**
* ...... previous code
**/
function App() {
const time = useRef(Date.now()); //can be let, depending of your logic
useEffect(() => {
serviceWorkerRegistration.register({
onSuccess(registration) {
console.debug('serviceWorkerRegistration success')
},
onUpdate(registration) {
console.debug('serviceWorkerRegistration updated',Date.now()-time.current)
const refresh=async ()=>{
await registration?.waiting.postMessage({type: 'SKIP_WAITING'}); //send message to update the code (stop waiting)
if ('caches' in window) { //delete cache, i think is no necessary but you lose nothing
const names = await caches.keys()
for (const name of names) {
await caches.delete(name)
}
}
window.location.reload();
}
if (Date.now()-time.current<=2000){
return refresh()
}
logicToShowPopup({
onClick: refresh
})
}
})
}, [])
return (<div>My App</div>)
}
I hope this suits for your needs

Can't figure out where to initiate CronJob in react app

I have a react app, which must perform a weekly task every Monday #7:58 am. The task is setup as a separate function "notification()". And I want to use the 'CRON' package from NPM to call notification() at the appropriate time.
I have CRON wrapped inside of a function like this:
let mondayNotif = () => {
new CronJob('* 58 7 * * 2', function() {
notification()
}, null, true, 'America/Los_Angeles');
};
My question: where should I call the function mondayNotif(), to make sure that the CronJob is initiated correctly? I thought at first it must be on the backend, but the NPM package doesn't seem to support server-side. But if I call mondayNotif() on the client side, will the CronJob still happen if the site is inactive?
From what I know React JS is front end - it runs on client side. You need a server. In this case a node.js based server. Theroetically if nobody opens the website nothing will be fired up in react js. Look up how to schedule cron jobs on node.js
enter link description here
I found my own answer. But first, a few insights on CronJobs that would have helped me:
CronJobs are essentially a third-party function with an embedded clock. Once they are "initiated", you don't have to call them. The third-party calls them remotely, based on the time that you scheduled in the parameters (ie: "30 6 * * 5").
There is some discrepancy in different blogs about the CRON time. For instance some blogs insisted there are 6 time variables, but I found it worked with 5.
CronJobs should be in a separate file from the body of your main code, typically at the top of your folder structure near your "package.json" & "server.js" files.
It seems to be cleanest to setup all of your CronJob utilities directly inside the cronjob.js file. For instance: I used a separate database connection directly in cronjob.js and by-passed the api routes completely.
CronJobs should be initiated exactly once, at the beginning of the app launch. There are a few ways to do this: package.json or server.js are the most obvious choices.
Here is the file structure I ended up using:
-App
--package.json
--server.js
--cronjob.js
--/routes
--/src
--/models
--/public
...And then I imported the cronjob.js into "server.js". This way the cronjob function is initiated one time, when the server.js file is loaded during "dev" or "build".
For reference, here's the raw cronjob.js file (this is for an email notification):
const CronJob = require('cron').CronJob;
const Department = require('./models/department.js');
const template_remind = require('./config/remindEmailTemplate.js');
const SparkPost = require('sparkpost');
const client = new SparkPost('#############################');
const mongoose = require("mongoose");
const MONGODB_URI =
process.env.MONGODB_URI || "mongodb://localhost:27017/app";
mongoose.Promise = Promise;
// -------------------------- MongoDB -----------------------------
// Connect to the Mongo DB
mongoose.connect(MONGODB_URI, { useNewUrlParser: true }, (err, db) => {
if (err) {
console.log("Unable to connect to the mongoDB server. Error:", err);
} else {
console.log("Connection established to", MONGODB_URI);
}
});
const db = mongoose.connection;
// Show any mongoose errors
db.on("error", error => {
console.log("Mongoose Error: ", error);
});
// Once logged in to the db through mongoose, log a success message
db.once("open", () => {
console.log("Mongoose CRON connection successful.");
});
// ------------------------ Business Logic --------------------------
function weekday(notifications) {
Department.find({"active": true, "reminders": notifications, "week": {$lt: 13}}).distinct('participants', function(err, doc) {
if(err){
// console.log("The error: "+err)
} else {
console.log("received from database... "+JSON.stringify(doc))
for(let i=0; i<doc.length; i++){
client.transmissions.send({
recipients: [{address: doc[i]}],
content: {
from: 'name#sparkmail.email.com',
subject: 'Your email notification',
html: template_remind()
},
options: {sandbox: false}
}).then(data => {})
}
}
})
}
function weeklyNotif() {
new CronJob('45 7 * * 1', function() {weekday(1)}, null, true, 'America/New_York');
new CronJob('25 15 * * 3', function() {weekday(2)}, null, true, 'America/New_York');
new CronJob('15 11 * * 5', function() {weekday(3)}, null, true, 'America/New_York');
}
module.exports = weeklyNotif()
As you can see, I setup a unique DB connection and email server connection (separate from my API file), and ran all of the logic inside this one file, and then exported the initiation function.
Here's what appears in server.js:
const cronjob = require("./cronjob.js");
All you have to do here is require the file, and because it is exported as a function, this automatically initiates the cronjob.
Thanks for reading. If you have feedback, please share.
Noway, do call CronJob from client-side, because if there are 100 users, CronJob will be triggered 100 times. You need to have it on Server-Side for sure

How to run schema creation sql script in mssql with nodejs?

I have my code deployed in Azure Function App and using NodeJS I am trying to execute a sql script on SQL Server database. To work this out I have used NPM package sqlcmd-runner.
Here is the code I am using:
module.exports.dumpScriptinDatabase = (dbConfig, context) => {
return new Promise((resolve, reject) => {
sqlcmd({
server: dbConfig.server,
database: dbConfig.options.database,
username: dbConfig.userName,
password: dbConfig.password,
encryptedConnection: true,
inputFiles: [`${__dirname}\\db.sql`]
})
.catch((error) => {
reject('Error dumping script!!')
})
.done(() => {
resolve('Dumping script completed.')
});
});
I am getting all the database details in dbConfig variable. Also db.sql creates the tables, views etc. in the schema.
The issue I am facing is this module never returns me error in case of failure and it also does not executes successfully. The server returns 502 error code on execution.
One thing I am able to debug is that the npm package code uses sqlcmd to execute the script.
Can someone help me on this?
So I've tested this using several source files, it's working ok, scripts are run successfully.
index.js
const dbConfig = require('./dbconfig.json');
const dumpScript = require('./dumpScript.js');
console.log('Running script');
dumpScript.dumpScriptinDatabase(dbConfig, 'context').then(() => {
console.log('Script complete');
}).catch ( (err) => {
console.error('Script error: ', err);
});
dumpScript.js
const sqlcmd = require('sqlcmd-runner');
module.exports.dumpScriptinDatabase = (dbConfig, context) => {
return sqlcmd({
server: dbConfig.server,
database: dbConfig.options.database,
username: dbConfig.userName,
password: dbConfig.password,
encryptedConnection: true,
inputFiles: [`${__dirname}\\db.sql`]
});
}
dbConfig.json
{
"server": "sql_server",
"options": {
"database": "test_db"
},
"userName": "user",
"password": "password"
}
I've simplified the dumpScript.js file, we can simply return the promise from the sqlcmd function rather than using .then and .catch.
We then handle this in index.js.
A couple of things I'd mention, you need the sqlcmd utility of a fairly recent version on PATH for this to work.
Also, you might need to modify the index.js script, I'm loading dbConfig from a .json file, you're probably doing something different.

Node.js mssql close open connection

I am building an API integration application in Node.js using the "mssql" package. I have the data pulling from the third-party API, and stored in my SQL Server. However, my DB connection stays open forever and keeps my app running. Everything that I have tried ends the connection before the data can be stored. So, I can either store my data and keep the connection open forever, or end my connection and not store the data. The best that I have found is something like this answer: https://stackoverflow.com/a/45681751/5552707.
And I have tried that in my app, which still kills my connection before data is stored:
sql.connect(sqlConfig).then(pool => {
var request = new sql.Request(pool);
var result = request.bulk(table, (err, result) => {
if(err){
console.log("fail. " + err);
return;
}
})
}).catch(err => {
console.log('There was an error processing the request. ' + err);
}).then(() => {
console.log('done');
process.exit(1);
});
They docs don't explain how to do this, which is frustrating.
Any ideas would be awesome!
Thanks!
Adding
process.exit();
to the callback function did the trick.
var request = new sql.Request(pool);
var result = request.bulk(table, (err) => {
if(err){
console.log("fail. " + err);
return;
}
process.exit(1);
})

unity build webGL with SQLite database

I'm developing a game for web(html5) which connects to a SQLite database to access the game's questions (which I learned in here: http://answers.unity3d.com/questions/743400/database-sqlite-setup-for-unity.html). the database in question is located in a .db file located inside the Assets folder of my project.
When I run it in unity, it connects to the database just right and exctracts the questions. When I build the game, it doesn't. Can anyone help me with this problem? Where should I put my .db file?
because You database file is not True Location
Db file would on data folder After The Make Build
Here is an answer on Reddit:
"Other options you might want to consider are to build a JavaScript
bridge to something like the browser IndexedDB or WebSQL APIs."
Personally, how I would approach this is with my WebGL build communicating to a React App it is embedded in. You can use npm package "React Unity WebGL" then have functions that access WebSQL database.
const db = openDatabase("my.db", '1.0', "My WebSQL Database", 2 * 1024 * 1024);
useEffect(function () {
unityContext.on("Create", function (sqlcommand) {
db.transaction(function (tx) {
tx.executeSql("data");
});
});
unityContext.on("InsertData", function (sqlcommand, data) {
db.transaction(function (tx) {
tx.executeSql(sqlcommand, data);
});
});
unityContext.on("SelectData", function (sqlcommand, callback) {
db.transaction(function (tx) {
tx.executeSql(sqlcommand, [], function(tx, results) {
if(results.rows.length > 0) {
for(var i = 0; i < results.rows.length; i++) {
console.log("Result -> " + results.rows.item(i).firstname + " " + results.rows.item(i).lastname);
}
unityContext.send("GameController", callback, results);
}
});
});
});
}, []);
Now you can start using SQL in your WebGL applications.

Resources