Pouch Couch DB error when sync and replicate - react-native

I am currently having a problem trying to sync or replicate the data from PouchDB to CouchDB. Whenever I try to sync or replicate I always get this error.
Cannot read properties of undefined (reading 'from').
Here is my code:
function openDB() {
return new PouchDB('cows.db', { adapter: 'react-native-sqlite' });
}
function openRemoteDB() {
return new PouchDB('http://admin:asdasd#127.0.0.1:5984/cows');
}
const runPouchDB = async () => {
const db = openDB();
console.log('db info:', await db.info());
const remotedb = openRemoteDB();
console.log('remote db info:', await remotedb.info());
db.replicate.to(remotedb, {})
.on('complete', async () => {
console.log('done!');
})
.on('error', function (err) {
console.error('failed to replicate:', err.message, err.stack);
});
db.sync(remotedb).on('complete', function () {
console.log('done');
// yay, we're in sync!
}).on('error', function (err) {
console.log('error', err);
// boo, we hit an error!
});
}
React.useEffect(() => {
runPouchDB().then(() => console.log('connected'));
}, [])
both approach always return an error. Not sure if it is a package issue or something I did wrong.
UPDATE:
Based on the example it is looking for global.base64FromArrayBuffer but base64FromArrayBuffer does not exist in my global context.
https://github.com/craftzdog/pouchdb-react-native/blob/138f3d6385238e5cf278366d0fb3d0434abbdced/example/src/App.js#L71
Not sure how to add since since I already added the shim which I though would fix the issue.
import { shim as shimBase64 } from 'react-native-quick-base64';
shimBase64();

Related

Test Express.js routes which rely on a TypeORM connection

I have a very basic Express.js app which I use Jest and Supertest to test. The routes are not set up until the database is connected:
class App {
public app: express.Application;
public mainRoutes: Util = new Util();
constructor() {
this.app = express();
AppDataSource.initialize()
.then(() => {
// add routes which rely on the database
this.mainRoutes.routes(this.app);
})
.catch((error) => console.log(error));
}
}
export default new App().app;
Here is my test:
describe("Util", function () {
test("should return pong object", async () => {
const res = await request(app).get("/ping");
expect(res.statusCode).toEqual(200);
expect(res.body).toEqual({ message: "pong" });
});
});
Since I put in the promise, this has been 404ing. I can't add async to the constructor. I tried refactoring the class to separate the connection with setting up the routes, but it didn't seem to help.
This works:
test("should return pong object", async () => {
setTimeout(async () => {
const res = await request(app).get("/ping");
expect(res.statusCode).toEqual(200);
expect(res.body).toEqual({ message: "pong" });
}, 1000);
});
But obviously I don't want to add a setTimeout. How is this usually done? I am new to testing.
Just remove the setTimeout() and await the call to the application. You should be initializing the application in the beforeAll() method, which I assume you have, to get the application up and running in the testing space. You should also mock your database connection, so you can fake the data you want back, and not have to wait for the external database to actually be available.
// Create a mock for your database, and have it return whatever you need
import <your-database-class> = require('database');
jest.mock('database', () => {
...
});
describe("Util", function () {
beforeAll(async () => {
app = await <whatever you do to launch your application>
});
test('should be defined', () => {
expect(app).toBeDefined();
});
test("should return pong object", async () => {
const res = await request(app).get("/ping");
expect(res.statusCode).toEqual(200);
expect(res.body).toEqual({ message: "pong" });
});
});

Unhandled Promise Rejection when trying to call external function from async function

The error message:
WARN Possible Unhandled Promise Rejection (id: 1):
Error: INVALID_STATE_ERR
send#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:31745:26
initialiseWebsocket#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:100544:21
loadUserData$#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:100610:40
tryCatch#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:7739:23
invoke#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:7912:32
tryCatch#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:7739:23
invoke#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:7812:30
http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:7822:21
tryCallOne#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:28596:16
http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:28697:27
_callTimer#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:29113:17
_callImmediatesPass#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:29152:17
callImmediates#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:29370:33
__callImmediates#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:3279:35
http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:3057:34
__guard#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:3262:15
flushedQueue#http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:3056:21
flushedQueue#[native code]
invokeCallbackAndReturnFlushedQueue#[native code]
The useEffect that is being accused of being a problem:
React.useEffect(() => {
// Fetch the token from storage then navigate to our appropriate place
const loadUserData = async () => {
let userData;
try {
userData = await retrieveUserData();
} catch (e) {}
if(userData){
dispatch({ type: 'RESTORE_USER_DATA', userData: userData });
getChatData(userData, setChats, dispatch);
if(userData && !websocketInitialised){
console.log('web init called from *load user data*')
setWebsocketInitialised(true)
initialiseWebsocket(userData);
}
}
else{
dispatch({ type: 'RESTORE_USER_DATA_FAILED'});
}
};
loadUserData();
}, []);
The initialliseWebsocket function
function initialiseWebsocket(userData){
console.log('sending websocket initialisation data.');
websocket.send(JSON.stringify({
'action': 'init',
'data' : {'token': userData.token}
}));
}
the useState that is used above
const [websocketInitialised, setWebsocketInitialised] = React.useState(false);
async function getChatData(userData, setChats, dispatch){
console.log("fetching chat data");
// if we fail to download chat data, pull the old one from FS
const loadOldChatData = async () => {
let chats;
try {
chats = await retrieveChats();
} catch (e) {}
if(chats){
setChats(chats);
console.log("loaded cached chat data") ;
}
else{
setChats([]);
}
};
const onSuccess = (response) => {
if(response['chats']){
storeChats(response['chats']);
setChats(response['chats']);
console.log("chat data synced");
}
else{
loadOldChatData();
}
};
const onFailure = (response) => {
loadOldChatData();
};
fetch(Settings.siteUrl + '/messenger/get_chats/', {
method: "GET",
headers: {
"Content-type": "application/json; charset=UTF-8",
"Authorization": "Token " + userData.token
},
})
.then(response => response.json())
.then(response => {onSuccess(response)})
.catch(response => {onFailure(response)})
}
retrieveUseData() is most likely not the problem as this only started occuring after I added the other code.
Am I not supposed to use states like this or am I supposed to use the async key worked on functions? I tried that but I still have the same issue. You can see on the 4 line of the errors it mentions the 'initialiseWebsocket' function. I am guessing that is the route cause. I assume the solution will be some async version of it...
This error tell us that you didn't or forget to handle error from async code.
I refectory your code a bit, Tell me if you got any error message from console.log(error);
React.useEffect(() => {
// Fetch the token from storage then navigate to our appropriate place
(async () => {
try {
let userData = await retrieveUserData();
dispatch({ type: 'RESTORE_USER_DATA', userData });
await getChatData(userData, setChats, dispatch);
if (websocketInitialised) return;
console.log('web init called from *load user data*')
setWebsocketInitialised(true)
initialiseWebsocket(userData);
} catch (error) {
console.log(error);
dispatch({ type: 'RESTORE_USER_DATA_FAILED' });
}
})();
}, []);
And you should rename getChatData to setChatData, I also simplify those code also...
async function getChatData(userData, setChats, _dispatch) {
try {
let response = await fetch(Settings.siteUrl + '/messenger/get_chats/', {
method: "GET",
headers: {
"Content-type": "application/json; charset=UTF-8",
"Authorization": "Token " + userData.token
},
}),
data = await response.json(),
chats = data['chats'];
if (!chats?.length) throw "empty chat data, pull the old one from FS";
storeChats(chats);
setChats(chats);
} catch (_) {
// if we fail to download chat data, pull the old one from FS
await retrieveChats()
.then(chats => setChats(chats))
.catch(() => setChats([]))
}
}
"I don't really understand what you are doing with the async stuff."
async/await is just syntax sugar of promise, It allow you to work with async operation in a synchronous manner, some rules of async/await
In other to use await keyword, you need an async function.
you can make any function asynchronous, just by adding async keyword
async function always return promise
Lets see an example:
let delay = (ms, msg, bool) => new Promise((res, rej) => setTimeout(!bool ? res : rej , ms,msg));
This helper function create a promise for our example, it take 3 arguments, it take millisecond as 1st arg, to delay, 2rd is the message as payload. 3nd is Boolean; it true, then it will reject.
let delay = (ms, msg, bool) => new Promise((res, rej) => setTimeout(!bool ? res : rej, ms, msg));
let log = console.log;
async function myAsyncFn() {
let hello = await delay(100, "hello,");
let world = await delay(300, " world!");
// we use a symbol '#' to indicate that, its from `myAsyncFn`
log("#" , hello + world, "printed from async operation");
}
myAsyncFn();
log("As you can see that, this message print first");
// we are creating an async function and called immediately, In other to use `await keyword`
(async () => {
try {
let resolved = await delay(300,"resolved");
console.log(">" , `it ${resolved}!`);
// this will reject and catch via `try/catch` block;
let _ = await delay(600, "Error", true);
log("It will not print!");
// ...
} catch (error) {
log(">" , `we can catch "${error}" with try/catch, as like any sync code!`);
}
})()
As you can see that with async/await its look like everything is synchronous right? even everything execute asynchronously!
You just need to use await keyword to make every async operation synchronous.

React Hook does not set on first API call

So I am sure I am messing something up, but I am not super skilled at API.
So I am trying to make an API call to check if the user exists, if user exists then move about business, if not then do other stuff.
So my first call gets the data, and the user DOES exist, the hook is setting to true, however in my log it fails and the next API is ran. However if I do it a 2nd time, it is true...
What am I doing wrong.
const handleSubmit = async () => {
const data = await axios
.get(`URL`, {
})
.then((resp) => {
if (resp.data.user.name) {
setCheckUser(true);
console.log(resp.data.user.name);
}
return data;
})
.catch((err) => {
// Handle Error Here
console.error(err);
});
console.log(checkUser);
if (!checkUser) {
console.log('No User Found');
//Do Stuff//
}
};
I think the problem here is that setCheckUser(true) is an async operation, so there is no guarantee that the checkUser variable will turn to true right away.
Maybe you can solve this by using a useEffect block like this
//somewhere on the top of your file, below your useState statements
useEffect(()=> {
if (!checkUser) {
console.log('No User Found');
//Do Stuff//
}
}, [checkUser])
const handleSubmit = async () => {
const data = await axios
.get(`URL`, {
})
.then((resp) => {
if (resp.data.user.name) {
setCheckUser(true);
console.log(resp.data.user.name);
}
return data;
})
.catch((err) => {
// Handle Error Here
console.error(err);
});
};

Question reg expo FileSystem.readAsStringAsync

I'm pretty new to react native and need some help reg. the possiblity to read an image from a file (like an image). I'm using the expo filesystem library with the following code:
const uploadImages = (file) => {
let data = null;
try {
data = await FileSystem.readAsStringAsync(file);
console.log(data)
} catch (err) {
console.log(err)
}
The issue I have is that I get: 'await' is only allowed within async functions
How can I call this function to wait until the data is loaded into the data variable ?
FileSystem.readAsStringAsync(...) returns Promise.
You can use Promise api like .then() and .catch():
const uploadImages = (file) => {
FileSystem.readAsStringAsync(file)
.then(data => {
// Do something with your data in this block
console.log(data);
})
.catch(err => {
console.log(err.message)
})
}

Error handling in Express using Axios for API call

I am trying to set up a basic express app to get some API data using axios. I want to do things the right way but I am a bit lost with error handling. Ideally, if there is an error I want to communicate it to users which I could do if the API call was within it the route. But how do you do it if it's a separate function?
axios call function using async:
const getForm = async () => {
try {
const config = {
method: 'get',
url: 'https://api.something.org/niceform'
}
}
const response = await axios(config)
return response
} catch (error) {
return error.message
}
}
express route:
app.get('/niceform', async (req, res) => {
try {
const data = await getForm()
res.send(data)
} catch (error) {
???
}
})
If I understand it correctly the getForm() function will return either the response or the error and then the route will send whatever comes back. But then what does the route's catch block do and how should I use it?
Is this setup considered to be a good practice?
Any advice would be appreciated, I am still learning.
The catch block can be removed from the getForm function. An error will be caught anyways in the get route.
const getForm = async () => {
const config = {
method: 'get',
url: 'https://api.something.org/niceform'
};
const response = await axios(config);
return response;
}
Or the error can be caught inside getForm, in order to do something in that catch block, and be thrown:
const getForm = async () => {
const config = {
method: 'get',
url: 'https://api.something.org/niceform'
};
try {
const response = await axios(config);
return response;
} catch (err) {
// log the error
// add extra information to the error
// else
// (see the attached answer)
throw err;
}
}
Consequently, in the catch block in the get route, an error can be responded:
app.get('/niceform', async (req, res) => {
try {
const data = await getForm();
res.send(data);
} catch (error) {
res.error(error);
}
})
Reference:
https://stackoverflow.com/a/42171508/3563737
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/throw