mirror of
https://github.com/IT4Change/Ocelot-Social.git
synced 2025-12-13 07:45:56 +00:00
pages are counted correctly
This commit is contained in:
parent
40c35599f6
commit
7562af227e
@ -19,7 +19,8 @@ const cypherTemplate = (setup) => `
|
||||
const simpleWhereClause =
|
||||
'WHERE score >= 0.0 AND NOT (resource.deleted = true OR resource.disabled = true)'
|
||||
|
||||
const postWhereClause = `WHERE score >= 0.0 AND NOT (
|
||||
const postWhereClause = `WHERE score >= 0.0
|
||||
AND NOT (
|
||||
author.deleted = true OR author.disabled = true
|
||||
OR resource.deleted = true OR resource.disabled = true
|
||||
OR (:User {id: $userId})-[:MUTED]->(author)
|
||||
@ -66,26 +67,22 @@ const searchHashtagsSetup = {
|
||||
resultKeyName: 'hashtags',
|
||||
}
|
||||
|
||||
const countSetup = {
|
||||
returnClause: 'toString(size(collect(resource)))',
|
||||
limit: '',
|
||||
}
|
||||
|
||||
const countUsersSetup = {
|
||||
...searchUsersSetup,
|
||||
...{
|
||||
returnClause: 'toString(size(collect(resource)))',
|
||||
limit: '',
|
||||
},
|
||||
...countSetup,
|
||||
}
|
||||
const countPostsSetup = {
|
||||
...searchPostsSetup,
|
||||
...{
|
||||
returnClause: 'toString(size(collect(resource)))',
|
||||
limit: '',
|
||||
},
|
||||
...countSetup,
|
||||
}
|
||||
const countHashtagsSetup = {
|
||||
...searchHashtagsSetup,
|
||||
...{
|
||||
returnClause: 'toString(size(collect(resource)))',
|
||||
limit: '',
|
||||
},
|
||||
...countSetup,
|
||||
}
|
||||
|
||||
const searchResultPromise = async (session, setup, params) => {
|
||||
@ -94,23 +91,20 @@ const searchResultPromise = async (session, setup, params) => {
|
||||
})
|
||||
}
|
||||
|
||||
const getSearchResults = async (context, setup, params) => {
|
||||
const session = context.driver.session()
|
||||
try {
|
||||
const results = await searchResultPromise(session, setup, params)
|
||||
log(results)
|
||||
return results.records.map((r) => r.get('result'))
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
const searchResultCallback = (result) => {
|
||||
return result.records.map((r) => r.get('result'))
|
||||
}
|
||||
|
||||
const countSearchResults = async (context, setup, params) => {
|
||||
const countResultCallback = (result) => {
|
||||
return result.records[0].get('result')
|
||||
}
|
||||
|
||||
const getSearchResults = async (context, setup, params, resultCallback = searchResultCallback) => {
|
||||
const session = context.driver.session()
|
||||
try {
|
||||
const results = await searchResultPromise(session, setup, params)
|
||||
log(results)
|
||||
return results.records[0].get('result')
|
||||
return resultCallback(results)
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
@ -127,15 +121,19 @@ export default {
|
||||
Query: {
|
||||
searchPosts: async (_parent, args, context, _resolveInfo) => {
|
||||
const { query, postsOffset, firstPosts } = args
|
||||
// const { id: userId } = context.user
|
||||
const userId = '73'
|
||||
const { id: userId } = context.user
|
||||
|
||||
return {
|
||||
postCount: countSearchResults(context, countPostsSetup, {
|
||||
query: queryString(query),
|
||||
skip: 0,
|
||||
userId,
|
||||
}),
|
||||
postCount: getSearchResults(
|
||||
context,
|
||||
countPostsSetup,
|
||||
{
|
||||
query: queryString(query),
|
||||
skip: 0,
|
||||
userId,
|
||||
},
|
||||
countResultCallback,
|
||||
),
|
||||
posts: getSearchResults(context, searchPostsSetup, {
|
||||
query: queryString(query),
|
||||
skip: postsOffset,
|
||||
@ -147,10 +145,15 @@ export default {
|
||||
searchUsers: async (_parent, args, context, _resolveInfo) => {
|
||||
const { query, usersOffset, firstUsers } = args
|
||||
return {
|
||||
userCount: countSearchResults(context, countUsersSetup, {
|
||||
query: queryString(query),
|
||||
skip: 0,
|
||||
}),
|
||||
userCount: getSearchResults(
|
||||
context,
|
||||
countUsersSetup,
|
||||
{
|
||||
query: queryString(query),
|
||||
skip: 0,
|
||||
},
|
||||
countResultCallback,
|
||||
),
|
||||
users: getSearchResults(context, searchUsersSetup, {
|
||||
query: queryString(query),
|
||||
skip: usersOffset,
|
||||
@ -161,10 +164,15 @@ export default {
|
||||
searchHashtags: async (_parent, args, context, _resolveInfo) => {
|
||||
const { query, hashtagsOffset, firstHashtags } = args
|
||||
return {
|
||||
hashtagCount: countSearchResults(context, countHashtagsSetup, {
|
||||
query: queryString(query),
|
||||
skip: 0,
|
||||
}),
|
||||
hashtagCount: getSearchResults(
|
||||
context,
|
||||
countHashtagsSetup,
|
||||
{
|
||||
query: queryString(query),
|
||||
skip: 0,
|
||||
},
|
||||
countResultCallback,
|
||||
),
|
||||
hashtags: getSearchResults(context, searchHashtagsSetup, {
|
||||
query: queryString(query),
|
||||
skip: hashtagsOffset,
|
||||
@ -187,83 +195,24 @@ export default {
|
||||
userId,
|
||||
} */
|
||||
|
||||
const postCypher = `
|
||||
CALL db.index.fulltext.queryNodes('post_fulltext_search', $query)
|
||||
YIELD node as resource, score
|
||||
MATCH (resource)<-[:WROTE]-(author:User)
|
||||
WHERE score >= 0.0
|
||||
AND NOT (
|
||||
author.deleted = true OR author.disabled = true
|
||||
OR resource.deleted = true OR resource.disabled = true
|
||||
OR (:User {id: $userId})-[:MUTED]->(author)
|
||||
)
|
||||
WITH resource, author,
|
||||
[(resource)<-[:COMMENTS]-(comment:Comment) | comment] as comments,
|
||||
[(resource)<-[:SHOUTED]-(user:User) | user] as shouter
|
||||
RETURN resource {
|
||||
.*,
|
||||
__typename: labels(resource)[0],
|
||||
author: properties(author),
|
||||
commentsCount: toString(size(comments)),
|
||||
shoutedCount: toString(size(shouter))
|
||||
}
|
||||
LIMIT $limit
|
||||
`
|
||||
|
||||
const userCypher = `
|
||||
CALL db.index.fulltext.queryNodes('user_fulltext_search', $query)
|
||||
YIELD node as resource, score
|
||||
MATCH (resource)
|
||||
WHERE score >= 0.0
|
||||
AND NOT (resource.deleted = true OR resource.disabled = true)
|
||||
RETURN resource {.*, __typename: labels(resource)[0]}
|
||||
LIMIT $limit
|
||||
`
|
||||
const tagCypher = `
|
||||
CALL db.index.fulltext.queryNodes('tag_fulltext_search', $query)
|
||||
YIELD node as resource, score
|
||||
MATCH (resource)
|
||||
WHERE score >= 0.0
|
||||
AND NOT (resource.deleted = true OR resource.disabled = true)
|
||||
RETURN resource {.*, __typename: labels(resource)[0]}
|
||||
LIMIT $limit
|
||||
`
|
||||
|
||||
const myQuery = queryString(query)
|
||||
|
||||
const session = context.driver.session()
|
||||
const searchResultPromise = session.readTransaction(async (transaction) => {
|
||||
const postTransactionResponse = transaction.run(postCypher, {
|
||||
query: myQuery,
|
||||
return [
|
||||
...(await getSearchResults(context, searchPostsSetup, {
|
||||
query: queryString(query),
|
||||
skip: 0,
|
||||
limit,
|
||||
userId,
|
||||
})
|
||||
const userTransactionResponse = transaction.run(userCypher, {
|
||||
query: myQuery,
|
||||
})),
|
||||
...(await getSearchResults(context, searchUsersSetup, {
|
||||
query: queryString(query),
|
||||
skip: 0,
|
||||
limit,
|
||||
})
|
||||
const tagTransactionResponse = transaction.run(tagCypher, {
|
||||
query: myQuery,
|
||||
})),
|
||||
...(await getSearchResults(context, searchHashtagsSetup, {
|
||||
query: queryString(query),
|
||||
skip: 0,
|
||||
limit,
|
||||
})
|
||||
return Promise.all([
|
||||
postTransactionResponse,
|
||||
userTransactionResponse,
|
||||
tagTransactionResponse,
|
||||
])
|
||||
})
|
||||
|
||||
try {
|
||||
const [postResults, userResults, tagResults] = await searchResultPromise
|
||||
log(postResults)
|
||||
log(userResults)
|
||||
log(tagResults)
|
||||
return [...postResults.records, ...userResults.records, ...tagResults.records].map((r) =>
|
||||
r.get('resource'),
|
||||
)
|
||||
} finally {
|
||||
session.close()
|
||||
}
|
||||
})),
|
||||
]
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -24,12 +24,12 @@ beforeAll(async () => {
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDatabase()
|
||||
// await cleanDatabase()
|
||||
})
|
||||
|
||||
const searchQuery = gql`
|
||||
query($query: String!) {
|
||||
findResources(query: $query, limit: 5) {
|
||||
searchResults(query: $query, limit: 5) {
|
||||
__typename
|
||||
... on Post {
|
||||
id
|
||||
@ -65,7 +65,7 @@ describe('resolvers/searches', () => {
|
||||
variables = { query: 'John' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: [
|
||||
searchResults: [
|
||||
{
|
||||
id: 'a-user',
|
||||
name: 'John Doe',
|
||||
@ -95,7 +95,7 @@ describe('resolvers/searches', () => {
|
||||
variables = { query: 'beitrag' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: [
|
||||
searchResults: [
|
||||
{
|
||||
__typename: 'Post',
|
||||
id: 'a-post',
|
||||
@ -114,7 +114,7 @@ describe('resolvers/searches', () => {
|
||||
variables = { query: 'BEITRAG' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: [
|
||||
searchResults: [
|
||||
{
|
||||
__typename: 'Post',
|
||||
id: 'a-post',
|
||||
@ -132,7 +132,7 @@ describe('resolvers/searches', () => {
|
||||
it('returns empty search results', async () => {
|
||||
await expect(
|
||||
query({ query: searchQuery, variables: { query: 'Unfug' } }),
|
||||
).resolves.toMatchObject({ data: { findResources: [] } })
|
||||
).resolves.toMatchObject({ data: { searchResults: [] } })
|
||||
})
|
||||
})
|
||||
|
||||
@ -189,7 +189,7 @@ und hinter tausend Stäben keine Welt.`,
|
||||
variables = { query: 'beitrag' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: expect.arrayContaining([
|
||||
searchResults: expect.arrayContaining([
|
||||
{
|
||||
__typename: 'Post',
|
||||
id: 'a-post',
|
||||
@ -216,7 +216,7 @@ und hinter tausend Stäben keine Welt.`,
|
||||
variables = { query: 'tee-ei' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: [
|
||||
searchResults: [
|
||||
{
|
||||
__typename: 'Post',
|
||||
id: 'g-post',
|
||||
@ -235,7 +235,7 @@ und hinter tausend Stäben keine Welt.`,
|
||||
variables = { query: '„teeei“' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: [
|
||||
searchResults: [
|
||||
{
|
||||
__typename: 'Post',
|
||||
id: 'g-post',
|
||||
@ -256,7 +256,7 @@ und hinter tausend Stäben keine Welt.`,
|
||||
variables = { query: '(a - b)²' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: [
|
||||
searchResults: [
|
||||
{
|
||||
__typename: 'Post',
|
||||
id: 'c-post',
|
||||
@ -277,7 +277,7 @@ und hinter tausend Stäben keine Welt.`,
|
||||
variables = { query: '(a-b)²' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: [
|
||||
searchResults: [
|
||||
{
|
||||
__typename: 'Post',
|
||||
id: 'c-post',
|
||||
@ -298,7 +298,7 @@ und hinter tausend Stäben keine Welt.`,
|
||||
variables = { query: '+ b² 2.' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: [
|
||||
searchResults: [
|
||||
{
|
||||
__typename: 'Post',
|
||||
id: 'c-post',
|
||||
@ -321,7 +321,7 @@ und hinter tausend Stäben keine Welt.`,
|
||||
variables = { query: 'der panther' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: [
|
||||
searchResults: [
|
||||
{
|
||||
__typename: 'Post',
|
||||
id: 'd-post',
|
||||
@ -349,7 +349,7 @@ und hinter tausend Stäben keine Welt.`,
|
||||
variables = { query: 'Vorü Subs' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: expect.arrayContaining([
|
||||
searchResults: expect.arrayContaining([
|
||||
{
|
||||
__typename: 'Post',
|
||||
id: 'd-post',
|
||||
@ -395,7 +395,7 @@ und hinter tausend Stäben keine Welt.`,
|
||||
variables = { query: '-maria-' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: expect.arrayContaining([
|
||||
searchResults: expect.arrayContaining([
|
||||
{
|
||||
__typename: 'User',
|
||||
id: 'c-user',
|
||||
@ -440,7 +440,7 @@ und hinter tausend Stäben keine Welt.`,
|
||||
variables = { query: 'beitrag' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: expect.not.arrayContaining([
|
||||
searchResults: expect.not.arrayContaining([
|
||||
{
|
||||
__typename: 'Post',
|
||||
id: 'muted-post',
|
||||
@ -465,7 +465,7 @@ und hinter tausend Stäben keine Welt.`,
|
||||
variables = { query: 'myha' }
|
||||
await expect(query({ query: searchQuery, variables })).resolves.toMatchObject({
|
||||
data: {
|
||||
findResources: [
|
||||
searchResults: [
|
||||
{
|
||||
__typename: 'Tag',
|
||||
id: 'myHashtag',
|
||||
|
||||
@ -11,7 +11,7 @@ import { user } from '~/components/UserTeaser/UserTeaser.story.js'
|
||||
|
||||
helpers.init()
|
||||
|
||||
const postMock = fields => {
|
||||
const postMock = (fields) => {
|
||||
return {
|
||||
...post,
|
||||
id: faker.random.uuid(),
|
||||
@ -24,7 +24,7 @@ const postMock = fields => {
|
||||
}
|
||||
}
|
||||
|
||||
const userMock = fields => {
|
||||
const userMock = (fields) => {
|
||||
return {
|
||||
...user,
|
||||
id: faker.random.uuid(),
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<post-teaser :post="resource" />
|
||||
</masonry-grid-item>
|
||||
</masonry-grid>
|
||||
{{postPage}}
|
||||
{{ postPage }}
|
||||
<pagination-buttons
|
||||
:hasNext="hasMorePosts"
|
||||
:hasPrevious="hasPreviousPosts"
|
||||
@ -73,7 +73,6 @@ export default {
|
||||
PostTeaser,
|
||||
PaginationButtons,
|
||||
UserTeaser,
|
||||
searchHashtags,
|
||||
HcHashtag,
|
||||
},
|
||||
props: {
|
||||
@ -101,10 +100,6 @@ export default {
|
||||
postsOffset: 0,
|
||||
usersOffset: 0,
|
||||
hashtagsOffset: 0,
|
||||
hasMorePosts: false,
|
||||
hasMoreUsers: false,
|
||||
hasMoreHashtags: false,
|
||||
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@ -125,17 +120,17 @@ export default {
|
||||
{
|
||||
type: 'Post',
|
||||
title: `${this.postCount} ${this.$t('search.heading.Post')}`,
|
||||
disabled: this.postCount == 0,
|
||||
disabled: this.postCount === 0,
|
||||
},
|
||||
{
|
||||
type: 'User',
|
||||
title: `${this.userCount} ${this.$t('search.heading.User')}`,
|
||||
disabled: this.userCount == 0,
|
||||
disabled: this.userCount === 0,
|
||||
},
|
||||
{
|
||||
{
|
||||
type: 'Hashtag',
|
||||
title: `${this.hashtagCount} ${this.$t('search.heading.Tag')}`,
|
||||
disabled: this.hashtagCount == 0,
|
||||
disabled: this.hashtagCount === 0,
|
||||
},
|
||||
]
|
||||
},
|
||||
@ -148,33 +143,42 @@ export default {
|
||||
hasPreviousHashtags() {
|
||||
return this.hashtagsOffset > 0
|
||||
},
|
||||
hasMorePosts() {
|
||||
return (this.postPage + 1) * this.pageSize <= this.postCount
|
||||
},
|
||||
hasMoreUsers() {
|
||||
return (this.userPage + 1) * this.pageSize <= this.userCount
|
||||
},
|
||||
hasMoreHashtags() {
|
||||
return (this.hashtagPage + 1) * this.pageSize <= this.hashtagCount
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
switchTab(tab) {
|
||||
this.activeTab = tab
|
||||
},
|
||||
previousPosts() {
|
||||
this.postsOffset = this.postPage * this.pageSize
|
||||
this.postPage--
|
||||
this.postsOffset = this.postPage * this.pageSize
|
||||
},
|
||||
nextPosts() {
|
||||
this.postsOffset += this.pageSize
|
||||
this.postPage++
|
||||
},
|
||||
previousUsers() {
|
||||
this.usersOffset = Math.max(this.usersOffset - this.pageSize, 0)
|
||||
this.userPage--
|
||||
this.usersOffset = this.userPage * this.pageSize
|
||||
},
|
||||
nextUsers() {
|
||||
this.usersOffset += this.pageSize
|
||||
this.userPage++
|
||||
},
|
||||
previousHashtags() {
|
||||
this.usersOffset = Math.max(this.usersOffset - this.pageSize, 0)
|
||||
this.hashtagPage--
|
||||
this.hashtagsOffset = this.hashtagPage * this.pageSize
|
||||
},
|
||||
nextHashtags() {
|
||||
this.usersOffset += this.pageSize
|
||||
this.hashtagsOffset += this.pageSize
|
||||
this.hashtagPage++
|
||||
},
|
||||
},
|
||||
@ -197,7 +201,6 @@ export default {
|
||||
update({ searchPosts }) {
|
||||
this.posts = searchPosts.posts
|
||||
this.postCount = searchPosts.postCount
|
||||
this.hasMorePosts = this.postCount >= (this.pageSize * this.postPage)
|
||||
if (searchPosts.posts.length) this.activeTab = 'Post'
|
||||
},
|
||||
fetchPolicy: 'cache-and-network',
|
||||
@ -220,33 +223,36 @@ export default {
|
||||
update({ searchUsers }) {
|
||||
this.users = searchUsers.users
|
||||
this.userCount = searchUsers.userCount
|
||||
this.hasMoreUsers = this.users.length >= this.pageSize
|
||||
if (!searchPosts.posts.length && searchUsers.users.length) this.activeTab = 'User'
|
||||
},
|
||||
fetchPolicy: 'cache-and-network',
|
||||
},
|
||||
searchHashtags: {
|
||||
query() {
|
||||
return searchHashtags
|
||||
},
|
||||
variables() {
|
||||
const { firstHashtags, hashtagsOffset, search } = this
|
||||
return {
|
||||
query: search,
|
||||
firstHashtags,
|
||||
hashtagsOffset,
|
||||
}
|
||||
},
|
||||
skip() {
|
||||
return !this.search
|
||||
},
|
||||
update({ searchHashtags }) {
|
||||
this.hashtags = searchHashtags.hashtags
|
||||
this.hashtagCount = searchHashtags.hashtagCount
|
||||
this.hasMoreHashtags = this.hashtags.length >= this.pageSize
|
||||
if (!searchPosts.posts.length && !searchUsers.users.length && searchHashtags.hashtags.length) this.activeTab = 'Hashtag'
|
||||
},
|
||||
fetchPolicy: 'cache-and-network',
|
||||
query() {
|
||||
return searchHashtags
|
||||
},
|
||||
variables() {
|
||||
const { firstHashtags, hashtagsOffset, search } = this
|
||||
return {
|
||||
query: search,
|
||||
firstHashtags,
|
||||
hashtagsOffset,
|
||||
}
|
||||
},
|
||||
skip() {
|
||||
return !this.search
|
||||
},
|
||||
update({ searchHashtags }) {
|
||||
this.hashtags = searchHashtags.hashtags
|
||||
this.hashtagCount = searchHashtags.hashtagCount
|
||||
if (
|
||||
!searchPosts.posts.length &&
|
||||
!searchUsers.users.length &&
|
||||
searchHashtags.hashtags.length
|
||||
)
|
||||
this.activeTab = 'Hashtag'
|
||||
},
|
||||
fetchPolicy: 'cache-and-network',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -7,8 +7,7 @@ export const searchQuery = gql`
|
||||
${tagsCategoriesAndPinnedFragment}
|
||||
|
||||
query($query: String!) {
|
||||
searchResults(query: $query, limit: 5)
|
||||
{
|
||||
searchResults(query: $query, limit: 5) {
|
||||
__typename
|
||||
... on Post {
|
||||
...post
|
||||
@ -38,16 +37,16 @@ export const searchPosts = gql`
|
||||
searchPosts(query: $query, firstPosts: $firstPosts, postsOffset: $postsOffset) {
|
||||
postCount
|
||||
posts {
|
||||
__typename
|
||||
...post
|
||||
...tagsCategoriesAndPinned
|
||||
commentsCount
|
||||
shoutedCount
|
||||
author {
|
||||
...user
|
||||
__typename
|
||||
...post
|
||||
...tagsCategoriesAndPinned
|
||||
commentsCount
|
||||
shoutedCount
|
||||
author {
|
||||
...user
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
@ -58,21 +57,20 @@ export const searchUsers = gql`
|
||||
searchUsers(query: $query, firstUsers: $firstUsers, usersOffset: $usersOffset) {
|
||||
userCount
|
||||
users {
|
||||
__typename
|
||||
...user
|
||||
__typename
|
||||
...user
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export const searchHashtags = gql`
|
||||
|
||||
query($query: String!, $firstHashtags: Int, $hashtagsOffset: Int) {
|
||||
searchHashtags(query: $query, firstHashtags: $firstHashtags, hashtagsOffset: $hashtagsOffset) {
|
||||
hashtagCount
|
||||
hashtags {
|
||||
__typename
|
||||
id
|
||||
__typename
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user