Realm "observer.next create #[native code]" exception - react-native

I am trying to fetch data with apollo and then write it to realm. I have created a js file that I know works, because it has worked before. But, when I try to write to a particular model I get an error message. More details as follows:
Code (Not entire code) LocationQuery.js:
const realm = new Realm({ schema: [testBuilding1], schemaVersion: 1 });
let buildingTypeArray = [];
const temp = [];
class LocationQuery extends Component {
static get propTypes() {
return {
data: React.PropTypes.shape({
loading: React.PropTypes.bool,
error: React.PropTypes.object,
sites: React.PropTypes.array,
}).isRequired,
};
}
render() {
if (this.props.data.loading) {
return (null);
}
if (this.props.data.error) {
return (<Text>An unexpected error occurred</Text>);
}
if (this.props.data.sites) {
this.props.data.sites.map((value) => {
buildingTypeArray.push(value.locations);
});
buildingTypeArray.forEach((locationValues) => {
realm.write(() => {
realm.create('testBuilding1', {
building: '273',
});
});
});
}
return null;
}
}
const locationQueryCall = gql`
query locationQueryCall($id: String!){
sites(id: $id){
locations {
building
type
}
}
}`;
const ViewWithData = graphql(locationQueryCall, {
options: props => ({
variables: {
id: 'SCH1',
},
}),
})(LocationQuery);
export default connect(mapStateToProp)(ViewWithData);
The error I get is a big red screen that read:
console.error: "Error in observe.next.... blah blah blah"
The Model I am using:
export const testBuilding1 = {
name: 'testBuilding1',
properties: {
building: 'string',
},
};
The weird thing is that the code works when I use this model:
export const locationScene = {
name: 'locationScene',
properties: {
building: 'string',
},
};
I am calling LocationQuery.js in another piece of code passing it through at render.
Thank you in advance for the help!

Related

Why am I not getting updates from my subscription?

I am trying to set up GraphQL Subscriptions but it seems to get connected to the backend but it's not pushing any updates.
On frontend, I am using Nuxt 2 and that's how I am trying to get it working:
That's my test query
export const pendingInquiresSubscription = () => {
return gql`
subscription PendingInquires {
countPendingInquires {
amount
}
}`
}
My smartQuery on the page component
apollo: {
$subscribe: {
pendingInquires: {
query: pendingInquiresSubscription(),
result({ data, loading }) {
this.loading = loading;
console.log(data)
},
error(err) {
this.$notify({ message: `Что-то пошло не так пытаясь обновить количество новый запросов: ${err.message}`, type: 'error' })
},
}
}
},
Backend:
my pubsub
import { RedisPubSub } from 'graphql-redis-subscriptions';
import Redis from 'ioredis';
const REDIS_DOMAIN_NAME = '127.0.0.1'
const PORT_NUMBER = 6379
const options = {
host: REDIS_DOMAIN_NAME,
port: PORT_NUMBER,
retryStrategy: (times: any) => {
return Math.min(times * 50, 2000);
}
}
export const pubsub = new RedisPubSub({
publisher: new Redis(options),
subscriber: new Redis(options)
})
My Schema:
extend type Subscription {
countPendingInquires: PendingInquires!
}
type PendingInquires {
amount: Int!
}
My resolver
...
Subscription: {
countPendingInquires: {
subscribe: () => pubsub.asyncIterator(['countPendingInquires'])
},
},
...
That's the way I am trying to push the event:
pubsub.publish('countPendingInquires', {
PendingInquires: {
amount: await TelegramInguireModel.find({ }).countDocuments()
}
})
And I also wonder if there is any built-in way to set the initial state for subscriptions.
The issue was in the way I was trying to push the event
The correct way of pushing is like this:
pubsub.publish('countPendingInquires', {
countPendingInquires: { // <- here was the issue
amount: await TelegramInquireModel.find({ }).countDocuments()
}
)
I've just set wrong subscription name

How to mock vue composable functions with jest

I'm using vue2 with composition Api, vuex and apollo client to request a graphql API and I have problems when mocking composable functions with jest
// store-service.ts
export function apolloQueryService(): {
// do some graphql stuff
return { result, loading, error };
}
// store-module.ts
import { apolloQueryService } from 'store-service'
export StoreModule {
state: ()=> ({
result: {}
}),
actions: {
fetchData({commit}) {
const { result, loading, error } = apolloQueryService()
commit('setState', result);
}
},
mutations: {
setState(state, result): {
state.result = result
}
}
}
The Test:
// store-module.spec.ts
import { StoreModule } from store-module.ts
const store = StoreModule
describe('store-module.ts', () => {
beforeEach(() => {
jest.mock('store-service', () => ({
apolloQueryService: jest.fn().mockReturnValue({
result: { value: 'foo' }, loading: false, error: {}
})
}))
})
test('action', async ()=> {
const commit = jest.fn();
await store.actions.fetchData({ commit });
expect(commit).toHaveBeenCalledWith('setData', { value: 'foo' });
})
}
The test fails, because the commit gets called with ('setData', { value: undefined }) which is the result from the original apolloQueryService. My Mock doesn't seem to work. Am I doing something wrong? Appreciate any help, thanks!
Try this :
// store-module.spec.ts
import { StoreModule } from store-module.ts
// first mock the module. use the absolute path to store-service.ts from the project root
jest.mock('store-service');
// then you import the mocked module.
import { apolloQueryService } from 'store-service';
// finally, you add the mock return values for the mock module
apolloQueryService.mockReturnValue({
result: { value: 'foo' }, loading: false, error: {}
});
/* if the import order above creates a problem for you,
you can extract the first step (jest.mock) to an external setup file.
You should do this if you are supposed to mock it in all tests anyway.
https://jestjs.io/docs/configuration#setupfiles-array */
const store = StoreModule
describe('store-module.ts', () => {
test('action', async ()=> {
const commit = jest.fn();
await store.actions.fetchData({ commit });
expect(commit).toHaveBeenCalledWith('setData', { value: 'foo' });
})
}

useMutation not mutating the local state

I'm getting this error while trying to mutate the local state in apollo.
errInvariant Violation: Expecting a parsed GraphQL document. Perhaps you need to wrap the query string in a "gql" tag? http://docs.apollostack.com/apollo-client/core.html#gql
Initial state
registration: {
__typename: 'Registration',
tempMerchantId: '',
authorizeProfile: {
__typename: 'AuthorizePersonProfile',
nid_front: '',
nid_back: '',
authorized_person_photo: ''
}
}
My mutation
export const setAuthorizePersonQuery = gql`
mutation setAuthorizePersonProfileInfo($authorizePerosnData: Object!){
setAuthorizePersonProfileInfo(authorizePersonData: $authorizePerosnData) #client
}
`;
My resolver
export const setAuthorizePersonProfileInfo = (
_, { authorizePersonData }, { cache }
) => {
try {
const prevData = cache.readQuery({ getAuthorizePersonProfileQuery });
cache.writeQuery({
getAuthorizePersonProfileQuery,
data: {
registration: {
__typename: 'Registration',
authorizeProfile: {
__typename: 'AuthorizePersonProfile',
...prevData.registration.authorizeProfile,
...authorizePersonData
}
}
}
});
} catch (e) {
console.log(`err${e}`);
}
return null;
};
I'm trying to mutate the local state on button press, the function is
const handlePressedNext = () => {
Promise.all([
setAuthorizePersonProfileInfo({
variables: { authorizePersonData: generateNidData() }
})
])
.then(() => {
navigation.navigate('Photograph');
});
};
generateNidData function is like bellow
const generateNidData = () => ({
nid_front: nidFrontImage,
nid_back: nidBackImage
});
I'm new to apollo client. I can not understand what I'm doing wrong. Can anyone help me figure out the problem?
getAuthorizePersonProfileQuery is not a valid option for readQuery. Presumably, you meant use query instead.

Vue Apollo: How can I query GraphQL using an object as Input argument?

I would like to create a checkout object via the GraphQL API provided by the Saleor eCommerce platform.
According to the gql playground there is a mutation to do so that takes a CheckoutCreateInput object as it's argument.
Here is an example mutation that works fine within the playground.
Here is the current code that I have tried (I am doing this within a vuex action)
export const actions = {
addToCart({ commit, dispatch }, cartItem) {
const currentCartItems = this.state.cartItems
// Check to see if we already have a checkout object
if (this.state.checkoutId !== '') {
// Create a new checkout ID
console.log('creating new checkout object')
try {
this.app.apolloProvider.defaultClient
.mutate({
mutation: CREATE_CART_MUTATION,
variables: {
checkoutInput: {
lines: { quantity: 10, variantId: 'UHJvZHVjdFZhcmlhbnQ6NQ==' },
email: 'test#test.com'
}
}
})
.then(({ data }) => {
console.log(data)
})
} catch (e) {
console.log(e)
}
} else {
console.log('checkout id already set')
}
// TODO: Check to see if the cart already contains the current Cart Item
commit('ADD_CART_ITEM', cartItem)
}
and here is the CREATE_CART_MUTATION:
import gql from 'graphql-tag'
export const CREATE_CART_MUTATION = gql`
mutation($checkoutInput: CheckoutCreateInput!) {
checkoutCreate(input: $checkoutInput) {
checkout {
id
created
lastChange
lines {
id
variant {
id
name
}
quantity
totalPrice {
gross {
localized
}
net {
localized
}
}
}
totalPrice {
gross {
localized
}
net {
localized
}
}
}
}
}
`
On the server this comes back with the following error:
graphql.error.base.GraphQLError: Variable "$checkoutInput" got invalid value {"email": "test#test.com", "lines": {"quantity": 10, "variantId": "UHJvZHVjdFZhcmlhbnQ6NQ=="}}.
In field "lines": In element #0: Expected "CheckoutLineInput", found not an object.
Looks like I was most of the way there, I was just passing a single lines object rather than an array of them. The correct code is as follows:
try {
this.app.apolloProvider.defaultClient
.mutate({
mutation: CREATE_CART_MUTATION,
variables: {
checkoutInput: {
lines: [
{ quantity: cartItem.quantity, variantId: cartItem.variantId }
],
email: 'test#test.com'
}
}
})
.then(({ data }) => {
console.log('mutation done!')
commit('SET_CHECKOUT_OBJECT', data.checkoutCreate.checkout)
})
} catch (e) {
console.log('error:')
console.log(e)
}

How to use realm with async fetch request?

I have meet this situation for my requirements:
step 1. save data to local db which in the mobile phone (realm)
step 2. upload the local data to the server, and the server will return the data ids if success
step 3. delete the records in local db by the returned ids which get by step2
Realm.open({schema:[MySchame],encryptionKey:getRealmKey()})
.then(realm =>{
realm.write(() => {
// 1. get all step data from db
let objetcs = realm.objects('MySchema');
// 2. upload obtained data to server
if(objetcs.length > 0){
let recordArr = [];
for (let o of steps){
recordArr.push(o.get());
}
uploadDataToServer(recordArr,(res)=>{
//3. filter the uploaded steps and delete them
let uploadedSteps = realm.objects('MySchema').filtered('id=$0',res.id);
if(uploadedSteps.length > 0){
realm.delete(uploadedSteps);
}
});
}
});
realm.close();
})
.catch(error =>{
console.log(error);
});
but this is not works as expected, it seems DB is closed too early than networks success callback.
Thanks for any ideas.
Finally ,I use realm like this:
let realm = new Realm({schema:[JOB_SCHEMA.jobTrack],encryptionKey:getRealmKey()});
let objects = realm.objects('JobTrack');
realm.beginTransaction();
realm.delete(objects);
realm.commitTransaction();
realm.close();
First create a service like one below
import repository from "./realmConfig";
let CatalogsService = {
findAll: function () {
return repository.objects("CatalogsModel");
},
save: function (catalogs) {
repository.write(() => {
repository.create("CatalogsModel", catalogs);
});
},
delete: function () {
repository.write(() => {
let all = repository.objects("CatalogsModel");
repository.delete(all);
});
},
update: function (catalogs, callback) {
if (!callback) return;
repository.write(() => {
callback();
catalogs.updatedAt = new Date();
});
}
};
module.exports = CatalogsService;
where my realmConfig file is as
import Realm from "realm";
class CatalogsModel extends Realm.Object { }
CatalogsModel.schema = {
name: "CatalogsModel",
primaryKey: "id",
properties: {
id: "string",
name: "string",
url: "string",
status: "int"
}
};
class OffersModel extends Realm.Object { }
OffersModel.schema = {
name: "OffersModel",
primaryKey: "id",
properties: {
id: "string",
name: "string",
url: "string",
status: "int",
machineId: "string",
machineName: "string"
}
};
export default new Realm({
schema: [CatalogsModel, OffersModel],
schemaVersion: 1,
deleteRealmIfMigrationNeeded: true
});
Now import Service.js where you are calling async server call and do your job. For reference see below code
import CatalogService from './path/to/CatalogService .js'
//get objects
var catalogs = CatalogsService.findAll();
// fire async function , I prefer axios for network calls
Axios.post("SERVER_URL", {
data: catalogs
})
.then(function (response) {
if (response.success)
CatalogsService.delete()
}
I assume you can easily modify findAll() and delete() method as per your need