Properly typing a multiline string in ruby with sorbet - ruby

I'm adopting Sorbet into a project and I can't understand how should I type the following constant:
RETRIEVE_FILE_URL_QUERY = <<~QUERY.freeze
query($input: ID!) {
node(id: $input) {
... on BulkOperation {
url
partialDataUrl
}
}
}
QUERY
The fastest way should be
RETRIEVE_FILE_URL_QUERY = T.let(<<~QUERY.freeze
query($input: ID!) {
node(id: $input) {
... on BulkOperation {
url
partialDataUrl
}
}
}
QUERY, String)
this is also the quick fix I got from vscode
But this raise the error
escape sequence meets end of file (2001)
As expected, since the heredoc name can't be no more found.
So I tried
RETRIEVE_FILE_URL_QUERY = T.let(<<~QUERY.freeze
query($input: ID!) {
node(id: $input) {
... on BulkOperation {
url
partialDataUrl
}
}
}
QUERY
, String)
But this raised another error:
T.untyped
unexpected token "," (2001)
With this, I got no clue how should I handle it.
I know that I could use the concatenation operator (+) but I would like to not split this string.
I'm still new to ruby so I want to ask you if there is a way to handle this.

Your "fastest" way violates the syntax. The terminating token must be on a line by itself.
When you do this:
QUERY, String)
You've put in something other than the terminator token QUERY, so it is assumed the string keeps going.
Remember that Ruby has multiple quoting systems, and is largely indifferent to multiple lines, as in:
RETRIEVE_FILE_URL_QUERY = "
query($input: ID!) {
node(id: $input) {
... on BulkOperation {
url
partialDataUrl
}
}
}
".freeze
Where you could also use # frozen_string_literal: true to do the freezing for you automatically.

Related

Conditional field in GraphQL Where query

Using Apollo client I am trying to run a query that will return students with any status if the status field is empty. If there is a status filter it should be applied:
const statusWhere = inputs.status ? { equals: $inputs.status }: {};
query GetStudents($course: ID, $status: String, $statusWhere: status_bool_exp) {
studentCourses (where :{
status: {$statusWhere},
course: {
id: {
equals: $course
}
},
# other fields, etc
This is giving error:
GraphQLError: Syntax Error: Expected Name, found "$".
Could you provide any hints?
After a bunch of trial and error I was able to figure it out myself. Posting it here because it could be useful for someone else.
Using the regular JS string interpolation variables works here.
So you need to define the condition as a string literal:
const statusWhere = inputs.status ? 'equals: "'+ inputs.status +'"' : '';
Then the whole gpl string looks like this:
gql`
query GetStudents($course: ID) {
studentCourses (where :{
status: {
${statusWhere}
},
course: {
id: {
equals: $course
}
},
})
# fields etc`
In this case you do not need to pass your string variable as a query param.

Strapi GraphQL search by multiple attributes

I've got a very simple Nuxt app with Strapi GraphQL backend that I'm trying to use and learn more about GraphQL in the process.
One of my last features is to implement a search feature where a user enters a search query, and Strapi/GraphQL performs that search based on attributes such as image name and tag names that are associated with that image. I've been reading the Strapi documentation and there's a segment about performing a search.
So in my schema.graphql, I've added this line:
type Query {
...other generated queries
searchImages(searchQuery: String): [Image
}
Then in the /api/image/config/schema.graphql.js file, I've added this:
module.exports = {
query: `
searchImages(searchQuery: String): [Image]
`,
resolver: {
Query: {
searchImages: {
resolverOf: 'Image.find',
async resolver(_, { searchQuery }) {
if (searchQuery) {
const params = {
name_contains: searchQuery,
// tags_contains: searchQuery,
// location_contains: searchQuery,
}
const searchResults = await strapi.services.image.search(params);
console.log('searchResults: ', searchResults);
return searchResults;
}
}
}
},
},
};
At this point I'm just trying to return results in the GraphQL playground, however when I run something simple in the Playground like:
query($searchQuery: String!) {
searchImages(searchQuery:$searchQuery) {
id
name
}
}
I get the error: "TypeError: Cannot read property 'split' of undefined".
Any ideas what might be going on here?
UPDATE:
For now, I'm using deep filtering instead of the search like so:
query($searchQuery: String) {
images(
where: {
tags: { title_contains: $searchQuery }
name_contains: $searchQuery
}
) {
id
name
slug
src {
url
formats
}
}
}
This is not ideal because it's not an OR/WHERE operator, meaning it's not searching by tag title or image name. It seems to only hit the first where. Ideally I would like to use Strapi's search service.
I actually ran into this problem not to recently and took a different solution.
the where condition can be combined with using either _and or _or. as seen below.
_or
articles(where: {
_or: [
{ content_contains: $dataContains },
{ description_contains: $dataContains }
]})
_and
(where: {
_and: [
{slug_contains: $categoriesContains}
]})
Additionally, these operators can be combined given that where in this instance is an object.
For your solution I would presume you want an or condition in your where filter predicate like below
images(where: {
_or: [
{ title_contains: $searchQuery },
{ name_contains: $searchQuery }
]})
Lastly, you can perform a query that filters by a predicate by creating an event schema and adding the #search directive as seen here

Is there a way to pass a parameter into a GraphQL query to specify the GraphQL type it should be run on?

I'm new to GraphQL and would like to be able to use a variable for a GraphQL name in a query.
I've attempted to use the standard $ syntax but with no luck.
Working query:
query Tryptych($section: SectionsEnum = home) {
enGB: entries(section: [$section], site: "enGB") {
... on Home {
tryptych {
...tryptychFields
}
}
}
}
What I'd like to be able to do:
query Tryptych($section: SectionsEnum = home, $interface: SomeType = Home) {
enGB: entries(section: [$section], site: "enGB") {
... on $interface {
tryptych {
...tryptychFields
}
}
}
}
Fragment for reference:
fragment tryptychFields on TryptychTryptych {
__typename
theme
tagline
firstImageTitle
firstImageContent
firstImageAsset {
url
}
firstImageLink
secondImageTitle
secondImageContent
secondImageAsset {
url
}
secondImageLink
thirdImageTitle
thirdImageContent
thirdImageAsset {
url
}
thirdImageLink
}
In the code snippet for what I'd like to achieve I get the error message:
Expected Name, found $
Thanks for the help.
A variable can only have one type, that type must be an input type (i.e. a scalar, enum or input object type), and it can only be used where an input type would be expected (i.e. a field or directive argument). In other words, the syntax you're suggesting is not supported.
If you have multiple types that may be returned by the same field, you may use any number of fragments to specify the selection set by type. The actual selection set will be determined at runtime when the type of the field is evaluated. For example, if the animal field returns a union of Cat, Dog and Bird types:
query {
animal {
... on Cat {
meows
}
... on Dog {
barks
}
... on Bird {
chirps
}
}
}
You may also use the #skip and #include directives to control which fields are selected:
query ($inAHouse: Boolean!, $withAMouse: Boolean!) {
greenEggs #skip(if: $inAHouse)
ham #include(if: $withAMouse)
}
And you may include multiple operations in a single document, and then specify an operationName with your request to tell the server which operation to run:
query OperationA {
foo
}
query OperationB {
bar
}

how to match queries with apollo's refetchQuery

My fundimental question is do the variables for queries need to be exact for refetchQueries to work. Or can you give it a subset of variables and it will match similar queries.
Consider the following ....
<Query<NotesQuery, NotesQueryVariables>
query={notesQuery}
variables={{
input: {
notebookId: notebookContext.id,
first: 20
}
}}
>
</Query>
and the following mutation:
client
.mutate<NoteCreateOrUpdateMutation, NoteCreateOrUpdateMutationVariables>({
mutation: noteCreateOrUpdateMutation,
variables: {
input: {
noteId: note ? note.id : undefined,
subjectIds: noteSubjects,
notebookId: notebookContext.id,
authorId: userContext.id,
content: noteContent,
context: noteCaption,
}
},
refetchQueries: [
{
query: notesQuery,
variables: { input: { notebookId: notebookContext.id } } as NotesQueryVariables
}
]
})
when I do that mutation it is NOT refetching the note query with the pagination
If I add the first: 20 parameter -- it works.
I would like it to clear all noteQueries that match with the given parameters. Is that possible?
I believe you'll be wanting to add #connection directives to your gql definitions of notesQuery and measurementsQuery. You didn't post those, so unfortunately I can't show you exactly what that would look like for your use case.
Anyway, the #connection directive will allow Apollo to match on notebookId for example, while ignoring the value of first.
Unfortunately, you've bundled all your input into the object input, and I don't know how you would select just notebookId with the filter. Assuming that your gql definition looks something like this for notesQuery:
const notesQuery = gql`
query notes($input: InputType!) {
notes(input: $input) #connection(key: "notes", filter: ["input['notebookId']"]) {
id
...
}
}
`;
^^^ Unfortunately, that won't work because of the way that apollo-utilities/lib/storeUtils.js -> getStoreKeyName() function works. It'll just ignore the above attempt to get better resolution than an arg name, i.e. can't go beyond input. Any string in the filter array that doesn't match an arg name is silently ignored.
Looks like you'll have to modify your schema.
More info at: https://www.apollographql.com/docs/react/features/pagination.html#connection-directive

I get a GraphQL error when running this query using the apollo server. Anyone one knows what is the problem with it?

I am trying to fetch some data from the GitHub GraphQL but I get a GaphQLError. I have tried the same query on the developer section of github and it works. Anyone know what is the problem with it?
issueQuery = gql`
query search(first: 10, type: ISSUE, query: "repo:angular/angular is:issue state:open") {
issueCount
edges {
node {
... on Issue {
createdAt
title
body
url
comments(first: 10) {
nodes {
body
}
}
}
}
}
}
`;
Error Stack Trace:
"GraphQLError: Syntax Error: Expected $, found Name "first"
at syntaxError (http://localhost:4200/vendor.js:70270:10)
at expect (http://localhost:4200/vendor.js:75154:67)
at parseVariable (http://localhost:4200/vendor.js:73984:3)
at parseVariableDefinition (http://localhost:4200/vendor.js:73970:15)
at many (http://localhost:4200/vendor.js:75222:16)
at parseVariableDefinitions (http://localhost:4200/vendor.js:73959:82)
at parseOperationDefinition (http://localhost:4200/vendor.js:73926:26)
at parseExecutableDefinition (http://localhost:4200/vendor.js:73881:16)
at parseDefinition (http://localhost:4200/vendor.js:73845:16)
at many (http://localhost:4200/vendor.js:75222:16)"
New Error Stack Trace when adding $ before the parameters:
"GraphQLError: Syntax Error: Expected Name, found Int "10"
at syntaxError (http://localhost:4200/vendor.js:70270:10)
at expect (http://localhost:4200/vendor.js:75154:67)
at parseName (http://localhost:4200/vendor.js:73809:15)
at parseNamedType (http://localhost:4200/vendor.js:74385:11)
at parseTypeReference (http://localhost:4200/vendor.js:74364:12)
at parseVariableDefinition (http://localhost:4200/vendor.js:73971:83)
at many (http://localhost:4200/vendor.js:75222:16)
at parseVariableDefinitions (http://localhost:4200/vendor.js:73959:82)
at parseOperationDefinition (http://localhost:4200/vendor.js:73926:26)
at parseExecutableDefinition (http://localhost:4200/vendor.js:73881:16)"
Don't confuse the operation with the actual field being queried. The syntax should look like this:
operationType [operationName] [variableDefinitions] {
selectionSet
}
where operationType is one of query, mutation or subscription, operationName is an arbitrary name for your operation used in debugging, variableDefinitions are type definitions for any variables you reference inside the operation, and selectionSet is one or more fields you're actually querying.
In this case, search is a field we're querying, so it should not be proceeded by the query keyword. This works fine, provided you're authenticated:
query OptionalName {
search(first: 10, type: ISSUE, query: "repo:angular/angular is:issue state:open") {
issueCount
edges {
# more fields
}
}
}
If the operation type is query, you can omit the query keyword altogether. This is called "query shorthand":
{
search(first: 10, type: ISSUE, query: "repo:angular/angular is:issue state:open") {
issueCount
edges {
# more fields
}
}
}
If you use variables, define them inside parentheses beside your operation. Variable names are arbitrary, but by convention we use the input field names they will be used in:
query OptionalName ($first: Int, type: SearchType!, $query: String! ) {
search(first: $first, type: $type, query: $query) {
issueCount
edges {
# more fields
}
}
}

Resources