apollo-client: How to insert a fragment in a gql template? - javascript

I have this fragment:
// product-info.js
module.exports = gql`fragment productInfo on Product {
id
name
model
color
quantity
}`
And I have this query:
// get-products.js
const productInfo = require('./fragments/product-info')
module.exports = gql`query getProducts {
quote #client {
items { ...productInfo }
}
}`
This is not working because ...productInfo is a simple literal here.
Even string interpolation is not working ${...productInfo}.

You should include the string after the query, I don't know if it will work with gql tag, depends on your bundler settings:
module.exports = gql`query getProducts {
quote #client {
items { ...productInfo }
}
}
fragment productInfo on Product {
id
name
model
color
quantity
}`
Other options is include with string formatter:
const productInfo = require('./fragments/product-info')
module.exports = gql`query getProducts {
quote #client {
items { ...productInfo }
}
}
${productInfo}`

Related

error There was an error in your GraphQL query: Variable "$slug" of required type "String!" was not provided

The title above is the error message, and below is the code.
I ran into this while following a tutorial on Gatsby. I wonder if anybody knows what happened and can give me some idea on what happened. I have little idea on what is going on . sorry......
import React from 'react'
import { graphql } from 'gatsby'
import Layout from '../components/layout'
import { parseImageUrl } from '#conradlin/notabase/src/utils'
export default ({ data }) => {
const { posts: { title, tags, publish_date, html, url, slug, desc, color, cover_image } } = data
return (
<Layout>
<div id = "main">
<div>{tags && tags.join(', ')}</div>
<h1>{title}</h1>
<div dangerouslySetInnerHTML={{ __html: html }} />
</div>
</Layout>
)
}
export const query = graphql`
query($slug: String!) {
posts(slug: { eq: $slug }) {
html
title
tags
publish_date{
startDate(formatString: "YYYY-MMM-DD", fromNow: false)
}
url
desc
color
cover_image
}
}
The tutorial is here for reference
https://conradlin.com/blog/posts/host-gatsbyjs-blog-with-notion-cms-and-netlify-for-free
This should be the query code
const path = require(`path`)
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const blogPost = await graphql(`
query {
allPosts(filter: {status: {eq: "published"}, content_type: {eq: "article"}}) {
nodes {
slug
url
}
}
}
`).then(result => {
if (result.errors) {
Promise.reject(result.errors);
}
result.data.allPosts.nodes.forEach(({ slug, url }) => {
createPage({
path: `blog/posts/${url}`,
component: path.resolve(`./src/templates/blogPost.js`),
context: {
// Data passed to context is available
// in page queries as GraphQL variables.
slug: slug,
},
});
});
});
const newsPost = await graphql(`
query {
allPosts(filter: {status: {eq: "published"}, content_type: {eq: "newsletter"}}) {
nodes {
slug
url
}
}
}
`).then(result => {
if (result.errors) {
Promise.reject(result.errors);
}
result.data.allPosts.nodes.forEach(({ slug, url }) => {
createPage({
path: `subscribe/posts/${url}`,
component: path.resolve(`./src/templates/blogPost.js`),
context: {
// Data passed to context is available
// in page queries as GraphQL variables.
slug: slug,
},
});
});
});
return Promise.all([blogPost, newsPost]);
};
If you look at:
result.data.allPosts.nodes.forEach(({ slug, url }) => {
createPage({
path: `subscribe/posts/${url}`,
component: path.resolve(`./src/templates/blogPost.js`),
context: {
// Data passed to context is available
// in page queries as GraphQL variables.
slug: slug,
},
});
This snippet refers to the gatsby-node.js, where you create pages dynamically based on a GraphQL query for allPosts. In this case, you are creating each post that will have the following URL:
path: `subscribe/posts/${url}`,
However, to filter the data for each particular post, you need to pass to the template (set with component: path.resolve('./src/templates/blogPost.js')) you need to pass an identifier field, typically the id, the slug or some other unique value. That flow of data is done due to the context, where you tell what parameter is passed to the component template, the slug in this case:
context: {
// Data passed to context is available
// in page queries as GraphQL variables.
slug: slug,
},
Thereby, in you template you can do:
export const query = graphql`
query($slug: String!) {
posts(slug: { eq: $slug }) {
html
title
tags
publish_date{
startDate(formatString: "YYYY-MMM-DD", fromNow: false)
}
url
desc
color
cover_image
}
}
Notice the ($slug: String!) the exclamation mark (!) means that the field is non-nullable for the GraphQL query, or in other words, that is required. Your code is breaking because somewhere in your GraphQL query (in your gatsby-node.js) you are passing an empty/null value to that template and the query breaks.
Debug what's happening in that query or remove the non-nullable parameter by:
query($slug: String)
However, that will bypass the code-breaking but the issue will persist since you are providing an empty value.

How I can make my belongsToMany relation in adonis.js

I'm trying to make a relationship between two tables.
My relationship is belongsToMany between user => user_bet_match => matchs.
A user can have many user_bet_match and matchs can have many user_bet_match.
My database migration is :
Matchs table :
this.create('matchs', (table) => {
table.increments()
table.integer('round_id').unsigned()
table.integer('league_id').unsigned()
table.integer('hometeam_id').unsigned()
table.integer('awayteam_id').unsigned()
table.string('final_score_hometeam_goal')
table.string('final_score_awayteam_goal')
table.string('halftime_score_hometeam_goal')
table.string('halftime_score_awayteam_goal')
table.date('event_date')
table.integer('event_timestamp')
table.boolean('betailable').defaultTo(false)
table.boolean('is_finish').defaultTo(false)
table.timestamps()
})
User table:
this.create('users', (table) => {
table.increments()
table.string('username', 80).notNullable().unique()
table.string('email', 254).notNullable().unique()
table.string('password', 60).notNullable()
table.timestamps()
})
user_bet_match table :
this.create('user_bet_match', (table) => {
table.increments()
table.integer('user_id').unsigned()
table.integer('match_id').unsigned()
table.string('choice').notNullable()
table.timestamps()
})
My user model:
class User extends Model {
static boot () {
super.boot()
this.addHook('beforeSave', async (userInstance) => {
if (userInstance.dirty.password) {
userInstance.password = await Hash.make(userInstance.password)
}
})
}
tokens () {
return this.hasMany('App/Models/Token')
}
match () {
return this.belongsToMany('App/Models/Match').pivotTable('user_bet_match')
}
My user bet match module:
'use strict'
/** #type {typeof import('#adonisjs/lucid/src/Lucid/Model')} */
const Model = use('Model')
const Database = use('Database')
class UserBetMatch extends Model {
user () {
return this.hasOne('App/Models/User')
}
matchs () {
return this.hasOne('App/Models/Match')
}
}
module.exports = UserBetMatch
And my matchs module:
'use strict'
/** #type {typeof import('#adonisjs/lucid/src/Lucid/Model')} */
const Model = use('Model')
class Match extends Model {
userbetmatchs () {
return this.hasMany('App/Models/UserBetMatch')
}
}
module.exports = Match
And when I make :
let k = user.match().fetch()
With this relation :
match () {
return this.belongsToMany('App/Models/Match').pivotTable('user_bet_match')
}
It's returning me sqlMessage: "Table 'bo7jjjccwliucibms5pf.matches' doesn't exist"
But I never mention of a table "matches"..
I don't know why..
I noticed that you changed the name of the tables in the migration (by default with adonis cli : matches; user_bet_matches)
Try to use this in your models:
static get table () {
return 'matchs' // Your table name
}
^ https://adonisjs.com/docs/4.0/lucid#_table
Lucid does not take into account the migrations.
It's therefore necessary to specify the name of the table if it is not the default one (with adonis cli).
Don't hesitate to tell me if it's not fair.

How change query value (where : { }) with Apollo GraphQL

with graphQL we can fetch data with "where"
query{
activities(where: {date: "2020-08-01"}){
date
collect
}
}
How change the date value to params ?
I try this :
let date = "2020-01-08"
const { loading, error, data } = useQuery(GET_ACTIVITY, {
variables: {
input: {
where: { date: date }
}
}
});
First the schema definition from your back-end must be something like this:
type Activity {
date: String
collect: String
...
}
type Query {
activities(date: String): [Activity]
...
}
then in the front-end create the query using the gql function from #apollo/client:
import { gql, useQuery } from '#apollo/client';
...
const GET_ACTIVITY = gql`
query Activities($date: String!) {
activities(date: $date){
date
collect
}
}
`;
And finally call it like this:
let date = "2020-01-08";
const { loading, error, data } = useQuery(GET_ACTIVITY, {
variables: {
date
}
});
More about queries: https://www.apollographql.com/docs/react/data/queries

How to implement pagination with GraphQL DataLoader?

I have the following GraphQL query:
{
events {
name
images {
uri
}
}
}
Currently, I am not able (don't know how) to handle pagination in that images field, because it is fetched using DataLoader.
The eventImagesLoader (DataLoader) implementation is the following:
import DataLoader from 'dataloader';
import { getRepository } from 'typeorm';
import { EventImage } from '../entities/event-image';
export const eventImagesLoader = () =>
new DataLoader<string, EventImage[]>(async (eventIds) => {
const images = await getRepository(EventImage)
.createQueryBuilder('image')
.where('image.eventId IN (:...ids)', { ids: eventIds })
.getMany();
const imagesMap = new Map<string, EventImage[]>();
images.forEach((image) =>
imagesMap.has(image.eventId)
? imagesMap.get(image.eventId)!.push(image)
: imagesMap.set(image.eventId, [image])
);
return eventIds.map((eventId) => imagesMap.get(eventId) || []);
});
The problem that I am facing is to handle the pagination in this scenario, because if you see in the above excerpt of code, I am querying to the database in this way:
const images = await getRepository(EventImage)
.createQueryBuilder('image')
.where('image.eventId IN (:...ids)', { ids: eventIds })
.getMany();
Which translates in a SQL like that:
SELECT * FROM `event_image` AS image WHERE image.id IN ("id:1", "id:2", "id:n");
And I use DataLoader in this case to batch all database queries into one (the above one).
So with that, how am I able to handle pagination?
I would like to do something like that:
{
events {
name
images(page: Int) {
uri
}
}
}

Import Constants in Vuex Store

The Vuex store of my Vue.js application is growing and getting a little bit messy with a lot of constants in it. I would like to split these constants in separate files and import them into my Vuex store store.js. I'm new to JavaScript so I would like to know:
How to store these constants in separate files? What would be the syntax in these files?
How to import these constants in store.js? What would be the exact syntax to do so?
Here is the current content of my store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
graphqlUrl: 'https://localhost/listof/api/v1/graphql',
errorObject: {
flag: false,
message: ''
},
// Data types queries
queryGetAllDataTypes: `query getAllDataTypes {
allSysDataTypes(orderBy: NAME_ASC) {
nodes {
id
name
}
}
}`,
// Data for linked list & attributes drodpdown in attribute form
// Response labels must be formatted according to Treeselect requirements
queryGetLinkedLists: `query getAllLists {
allSysLists(orderBy: NAME_ASC) {
nodes {
id:nodeId
label:name
attributes:sysAttributesByListId {
children:nodes {
id
label:name
}
}
}
}
}`,
// Data for linked list & attributes drodpdown in value form
// Response labels must be formatted according to Treeselect requirements
queryGetLinkedListValues: `query getAllValues {
all<GraphQlListName> {
nodes {
id
label:<graphQlAttributeName>
}
}
}`,
// Lists queries and mutations
queryGetAllLists: `query getAllLists{
allSysLists(orderBy: NAME_ASC) {
nodes {
id
name
description
}
}
}`,
queryGetList: `query getList($id: Int!) {
sysListById(id: $id) {
id
name
description
tableName
sysAttributesByListId {
nodes {
id
name
description
flagMandatory
flagUnique
dataTypeId
sysDataTypeByDataTypeId { name }
linkedAttributeId
sysAttributeByLinkedAttributeId {
name
columnName
listId
sysListByListId {
name
tableName
}
}
columnName
}
}
}
}`,
mutationCreateList: `mutation createList($sysList: SysListInput!) {
createSysList(input: {sysList: $sysList}) {
sysList {
id
}
}
}`,
mutationUpdateList: `mutation updateList($id: Int!, $sysListPatch: SysListPatch!) {
updateSysListById(input: {id: $id, sysListPatch: $sysListPatch }) {
sysList {
id
}
}
}`,
mutationDeleteList: `mutation deleteList($id: Int!) {
deleteSysListById(input: {id: $id}){
sysList {
id
}
}
}`,
// Attributes queries and mutations
queryGetAttribute: `query getAttribute($id: Int!) {
sysAttributeById(id: $id) {
id
name
description
flagMandatory
flagUnique
dataTypeId
sysDataTypeByDataTypeId { name }
linkedAttributeId
sysAttributeByLinkedAttributeId {
name
listId
sysListByListId { name }
}
defaultValue
}
}`,
mutationCreateAttribute: `mutation createAttribute($sysAttribute: SysAttributeInput!) {
createSysAttribute(input: {sysAttribute: $sysAttribute}) {
sysAttribute {
id
}
}
}`,
mutationUpdateAttribute: `mutation updateAttribute($id: Int!, $sysAttributePatch: SysAttributePatch!) {
updateSysAttributeById(input: {id: $id, sysAttributePatch: $sysAttributePatch }) {
sysAttribute {
id
}
}
}`,
mutationDeleteAttribute: `mutation deleteAttribute($id: Int!) {
deleteSysAttributeById(input: {id: $id}){
sysAttribute {
id
}
}
}`,
// Generic query used as template to fetch all values from a list
queryGetAllValues: `query getAllValues {
all<GraphQlListName> {
nodes {
id
createdDate
updatedDate
<graphQlAttributeName>
}
}
}`,
// Generic query used as template to fetch one value from a list
queryGetValue: `query getValue($id: Int!) {
<graphQlListName>ById(id: $id) {
id
createdDate
updatedDate
<graphQlAttributeName>
}
}`,
// Generic mutation used as template to create a new value in a list
mutationCreateValue: `mutation createValue($<graphQlListName>: <GraphQlListName>Input!) {
create<GraphQlListName>(input: {<graphQlListName>: $<graphQlListName>}) {
<graphQlListName> {
id
}
}
}`,
// Generic mutation used as template to update a value in a list
mutationUpdateValue: `mutation updateValue($id: Int!, $<graphQlListName>Patch: <GraphQlListName>Patch!) {
update<GraphQlListName>ById(input: {id: $id, <graphQlListName>Patch: $<graphQlListName>Patch }) {
<graphQlListName> {
id
}
}
}`,
// Generic mutation used as template to delete a value in a list
mutationDeleteValue: `mutation deleteValue($id: Int!) {
delete<GraphQlListName>ById(input: {id: $id}){
<graphQlListName> {
id
}
}
}`,
}
});
The simplest option is to create a new file for constants (constants.js) and define and export them there, e.g.:
export const cat = 'black'
export const dog = 'brown'
export const mouse = 'grey'
Then either import them all into the current namespace in store.js:
import * as constants from './constants'
Or import them selectively when needed:
import { cat, dog } from './constants'
VueX stores are immutable by default and can only be mutated via mutations. Vuex has created modules for this. I simply create a module and put all my constants in there without mutations.
From the vux documentation:
https://vuex.vuejs.org/guide/modules.html below:
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> `moduleA`'s state
store.state.b // -> `moduleB`'s state
Using nuxt.js you can simply add constants.js to the store folder with:
export const state = () => ({
example: {}
});

Categories

Resources