Has anyone found away of doing composite queries with Vue Apollo (Apollo boost)?
A composite batch query
I have an array if ids [ 12, 34, 56, 76, 76, …] and for each id I need to send a graphQL query. I could end up with a 500 queries being called one after the other.
Instead I want to batch them (or send them all at the same time) using aliases. Something like
[
first: User(id: "12") {
name
email
},
second: User(id: "34") {
name
email
},
....
....
oneHundred: User(id: "34") {
name
email
}
]
With the results being popped into an array. E.g.
this.users.pop(second)
I’ve done a fair bit of reading and searching. I found this that hints that it can be done
enter link description here
Any help out there?
The answer is in 3 parts.
Does the server recognise batch requests? Apollo server does by default
Set up the client in your app to handle batches
Create the queries on the fly.
Creating a Vue Apollo client:
import VueApollo from 'vue-apollo'
import Vue from 'vue';
import { ApolloClient } from 'apollo-client'
import { ApolloLink, split } from 'apollo-link'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { BatchHttpLink } from 'apollo-link-batch-http';
import { getMainDefinition } from 'apollo-utilities'
const httpLink = new HttpLink({ uri: HTTP_END_POINT });
const batchLink = new BatchHttpLink({ uri: HTTP_END_POINT });
const link = split(
// split based on operation type
({ query }) => {
const { kind, operation } = getMainDefinition(query)
return kind === 'OperationDefinition' && operation === 'subscription'
},
httpLink,
batchLink,
)
const client = new ApolloClient({
link: ApolloLink.from([link]),
cache: new InMemoryCache(),
connectToDevTools: true
})
Example of sending of a batch of queries inside a Vue component:
methods: {
fetchUsers() {
[<a list of user ids>].forEach(id => {
this.$apollo.query({
query: USER_QUERY,
variables: { id },
}).then(d => {
console.table(d.data.User)
this.users.push(d.data.User)
}).catch(e => console.log(e));
});
},
}
The actual query looks like:
import gql from "graphql-tag";
export const USER_QUERY = gql`
query User($id: String!) {
User(id: $id) {
firstName
lastName
}
}
Related
I am using Dart Alfred framework. And learning websockets.
Here is implamentation from example:
var users = <WebSocket>[];
app.get('/ws', (req, res) {
return WebSocketSession(
onOpen: (ws) {
users.add(ws);
users
.where((user) => user != ws)
.forEach((user) => user.send('A new user joined the chat.'));
},
onClose: (ws) {
users.remove(ws);
users.forEach((user) => user.send('A user has left.'));
},
onMessage: (ws, dynamic data) async {
users.forEach((user) => user.send(data));
},
);
});
https://github.com/rknell/alfred#websockets
I can't figure out how to return some additional data for every user to client.
For example (let's simplify) it's country from server. For example I have next map:
Map cuntries = {
'Mike': 'USA',
'Piter': 'Holland',
'Jow': 'Italy'
};
I did not worked with WebSocket before. Could anybody provide example how to do it?
Debugging update:
So, we went a bit further in debugging this and it seems like 'client:root' cannot access the connection at all by itself.
To debug the complete store, we added this line in the updater function after exporting the store variable from the relay/environment.
console.log(relayEnvStore.getSource().toJSON())
If I use .get() with the specific string client:root:__ItemList_items_connection, I can access the records I have been looking for but it's definitely not pretty.
const testStore = store.get('client:root:__ItemList_items_connection')
console.log(testStore.getLinkedRecords('edges'))
Original:
I'm using Relay Modern and trying to update the cache after the updateItem mutation is completed with the updater. The call to ConnectionHandler.getConnection('client:root', 'ItemList_items') returns undefined.
I'm not sure if it's because I'm trying to use 'client:root' as my parent record or if there's a problem with my code. Has anyone found themselves with a similar issue?
Here's the paginationContainer:
const ItemListPaginationContainer = createPaginationContainer(
ItemList,
{
node: graphql`
fragment ItemList_node on Query
#argumentDefinitions(count: { type: "Int", defaultValue: 3 }, cursor: { type: "String" }) {
items(first: $count, after: $cursor) #connection(key: "ItemList_items") {
edges {
cursor
node {
id
name
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
}
}
}
`
},
{
direction: 'forward',
getConnectionFromProps: props => props.node && props.node.items,
getVariables(props, { count, cursor }) {
return {
count,
cursor
}
},
query: graphql`
query ItemListQuery($count: Int!, $cursor: String) {
...ItemList_node #arguments(count: $count, cursor: $cursor)
}
`
}
)
Here's the mutation:
const mutation = graphql`
mutation UpdateItemMutation($id: ID!, $name: String) {
updateItem(id: $id, name: $name) {
id
name
}
}
`
Here's the updater:
updater: (store) => {
const root = store.getRoot()
const conn = ConnectionHandler.getConnection(
root, // parent record
'ItemList_items' // connection key
)
console.log(conn)
},
Turns out that I was setting my environment incorrectly. The store would reset itself every time I would make a query or a mutation, hence why I couldn't access any of the connections. I initially had the following:
export default server => {
return new Environment({
network: network(server),
store: new Store(new RecordSource())
})
}
All connections are accessible with this change:
const storeObject = new Store(new RecordSource())
export default server => {
return new Environment({
network: network(server),
store: storeObject
})
}
Quite new to React on Rails apps, especially the React portion. I'm trying to access data in a nested hash that is given from a SQL query in a Rails service. First off, is this even possible?
In Rails Console, lets say user1 has already been found by id, LedgersService.transactions(user1).first returns all data in this format:
{:transactable=>{:type=>"Deposit",
:id=>"28cba04f-5b9d-4c9c-afca-b09a6e0e8739",
:user_id=>"72700244-e6b0-4baf-a381-c22bfe56b022",
:transacted_at=>"2019-03-12 19:04:48.715678", :amount_cents=>15,
:notes=>"none", :processor=>nil, :details=>nil},
:ledgers=>[{:entry_type=>"credit", :amount_cents=>15,
:transacted_at=>"2019-03-12 19:04:48.715678",
:user_id=>"72700244-e6b0-4baf-a381-c22bfe56b022",
:transactable_type=>"Deposit",
:transactable_id=>"28cba04f-5b9d-4c9c-afca-b09a6e0e8739"}]}
I am attempting to do something similar in my React component to try to get the data, however, I'm not quite sure how to set LedgersService.transactions portion. This is how I currently have it:
class LedgersIndex extends React.Component {
constructor(props) {
super(props);
this.state = { ledgers_service: { transactions: [] }, paginator: { count: 0, page: 0, limit: 0 }, user: { id: this.props.match.params.user_id } };
My endpoint call:
componentDidMount() {
var user_id = this.state.user.id;
this.fetchData(user_id, 1);
}
fetchData = (user_id, page_number) => {
apiService.ledgersIndex(user_id, page_number)
.then(
paginated => {
this.setState({
ledgers_service: {
transactions: paginated.ledgers_service.transactions
},
paginator: {
limit: paginated.meta.limit,
count: paginated.meta.count,
page: paginated.meta.page -1
}
});
},
Further down in my render:
render() {
const { classes } = this.props;
const { ledgers_service, paginator } = this.state;
My fetch in apiService:
function locationsIndex(page_number) {
const requestOptions = {
method: 'GET',
headers: Object.assign({},
authorizationHeader(),
{ 'Content-Type': 'application/json' })
};
return fetch(`${process.env.API_SERVER}/api/v1/admin/locations?page=${page_number}`, requestOptions)
.then(handleResponse)
.then(paginated => {
return paginated;
});
}
When I console.log(ledgers_service.transactions(this.state.user.id)), I get the error that ledgers_service.transactions is not a function. console.log(paginator.count) however worked, is this because transactions is being set to an array?
What's the correct way to get that same endpoint in my React component that I got from my rails console?
Quite new to React on Rails apps, especially the React portion. I'm
trying to access data in a nested hash that is given from a SQL query
in a Rails service.
Yes, JS likes JSON so you should have a Rails action that responds with JSON. This is the correct way to exchange data between React and Rails:
# in your React app
fetch('/path/to/resource.json')
.then((returnedResource) => {
// do something with JSON
})
.catch(error => console.error('Error:', error));
# in your controller
respond_to do |format|
format.json { render json: LedgersService.transactions(user1).first }
end
From there, you can treat your returnedResource as a JSON object. In your case, this would be pagination
I have multiple user nodes (around 45 users) and I want to return the total users count as well as the User's details too in a single query. (Similar to How to design the following resolver for GraphQL server?)
My schema:
type User {
ID: Int
name: String
}
type Query {
users: [User]
}
And after running the resolver for users query, I want to pull the total count as well as the users details too like below:
{
"data": {
"users": {
"total": 45
"users": [
{
"ID": 1,
"name": "User A"
},
{
"ID": 2,
"name": "User B"
},
...
]
}
But I am confused how to use Promise.all in neo4j. I tried to look how the promise works in neo4j but I did not find any desired info.
So, could you please let me know how should I write my resolver for this case ? Any help would be appreciable !!
Using Promise.all is not different in neo4j. Promise.all is from javascript. To write resolver you can do following:
let countQuery = "MATCH(n:User) RETURN count(n) as count;";
let userQuery = "MATCH(u:User) RETURN u;";
return Promise.all([
dbSession().run(countQuery, params),
dbSession().run(userQuery, params)
]).then((data) => {
return {
total: data[0].records.map(record => {return record.get('count')}
users: data[1].records.map(record => {return record.get('u')}
}
})
In your schema type you can change it to following:
type User {
ID: Int
name: String
}
type PagedData {
total: Int,
users: [User]
}
type Query {
users: PagedData
}
Given that I have an example Model:
var model = new falcor.Model({
cache: {
userById: {
"1": {
name: "User",
email: "user#email.com"
}
},
users: {
current: null
}
}
});
This is a local model that I'm using for testing purposes, and I would like to implement it on a call to users.login so the user so that I can call:
model.call(['users', 'login'], ['user', 'password'])
I realized that if I do this:
var model = new falcor.Model({
cache: {
userById: {
"1": {
name: "User",
email: "user#email.com"
}
},
users: {
current: null,
login: function(user, password) {
console.log('this code is reached', user, password);
// what to return in order to mutate model?
}
},
}
});
When I do the call it gets there, but I can't figure out how to mutate the model as part of the response; on the server side we return the paths with values and invalidates, and it just works, but here I tried:
// trying returning as a jsonGraph response, don't work
login: function() {
return {
jsonGraph: {
users: {
current: {$type: "ref", value: ['userById', '1']}
}
},
paths: [['users', 'current']]
}
}
// trying returning as a path set mutation list, don't work
login: function() {
return [{path: ['users', 'current'], value: {$type: "ref", value: ['userById', '1']}}]
}
// trying force call to set on the model, don't work
login: function() {
this.set([
{path: ['users', 'current'], value: {$type: "ref", value: ['userById', '1']}}
])
}
// trying using ModelResponse, got an example on some external sources, don't work
login: funtion() {
return new ModelResponse((observer) => {
observer.onNext({
jsonGraph: {
users: {
current: {$type: "ref", value: ['userById', '1']}
}
},
paths: [['users', 'current']]
});
observer.onCompleted();
});
}
Now I don't know what else to try; I need a simple way to declare mutations after a call into a local model, if you know how to solve this, please let me know here.
Thanks.
The client model cache only supports JSONGraph, which b/c it is essentially just JSON with some conventions, doesn't support functions. So, when working with a falcor model cache and no dataSource/middle tier router, it is not possible to implement calls.
This can be kind of annoying when prototyping/testing, as a router is conceptually more difficult than a simple JSON cache object. I ran into this a while ago, so I wrote a dataSource module to support it: falcor-local-datasource. The dataSource is initialized with a graph object that does support function nodes, and as with your above examples, will mutate the graph based on the function's returned JSONGraphEnvelope or an array of PathValues.