AppSync GraphQL query with nested objects - amazon-dynamodb

I'm starting a new project using AWS Amplify, and have some trouble to correctly define my schema for my use case with nested objects
I have the following schema
type Company
#model
{
id: ID!
name: String!
teams: [Team] #connection (name: "CompanyTeams", sortField: "name")
}
type Team
#model
{
id: ID!
name: String!
users: [User] #connection (name: "TeamUsers", sortField: "createdAt")
company: Building #connection (name: "CompanyTeams", sortField: "name")
teamCompanyId: ID!
}
type User
#model
{
id: ID!
createdAt: String
name: String!
email: String!
team: Unit #connection (name: "TeamUsers")
}
I would like to be able to query a list of teams based on a list of companies and a user name.
For example, get all teams in companies A/B/C with user name starts with "David".
Is my current schema fine for that?
I can easily retrieve a list of teams based on the company with this kind of query
query listTeams {
listTeams(filter: {
teamCompanyId: {
eq:"A"
}
}) {
items {
name
}
}
}
But not sure how to include search on the user model. Should I override the filter and add a new custom resolver including the new filters?
Also is using filters the best solution? I believe with DynamoDB filter is only applied after we got results from the query or scan. And due to the limitation of 1mb, it might introduce a lot of reads to retrieve some results?
Happy to get any insights as I'm relatively new with AppSync / GraphQL and DynamoDB.
Thanks.

Related

Can i get amplify datastore to return related items in a query?

I'm trying to get the related/child items with a datastore query. I have no problems getting them with the graphql API, but it returns a bunch of deleted items which i am unable to filter server side (and keep pagination working nicely).
I'm using react/next/javascript.
``
I have the following models in my schema:
type TestResultData #model #auth(rules: [{allow: public}, {allow: owner, operations: [create, read, update]}, {allow: groups, groups: ["admin"], operations: [read, create, update, delete]}]) {
id: ID!
name: String
value: String
unit: String
testresultsID: ID! #index(name: "byTestResults")
TestResultAnalyses: [TestResultAnalysis] #hasMany(indexName: "byTestResultData", fields: ["id"])
tests: [Test] #manyToMany(relationName: "TestTestResultData")
}
and
type TestResults #model #auth(rules: [{allow: public}, {allow: owner, operations: [create, read, update]}, {allow: groups, groups: ["admin"], operations: [read, create, update, delete]}]) {
id: ID!
CustomerID: ID! #index(name: "byCustomer")
lab: String
fasting: Boolean
dateReported: AWSDateTime
dateCollected: AWSDateTime
dateTested: AWSDateTime
type: [TestType]
note: String
UploadedFiles: [UploadedFiles] #hasMany(indexName: "byTestResults", fields: ["id"])
TestResultData: [TestResultData] #hasMany(indexName: "byTestResults", fields: ["id"])
}
and I would like to query my TestResults model and have it return the nested TestResultData. However, datastore does not seem to return the related items. (if i do the query using the graphql api it works perfectly, except it contains all my deleted items, which i cannot filter)
this command gets me the TestResults without child items
const data = await DataStore.query(TestResults);
I've also tried "querying relations" as per:
https://docs.amplify.aws/lib/datastore/relational/q/platform/js/#updated-schema
but it doesn't work. I've also upgraded to the latest version of amplify.

How to use custom object types in Hasura actions?

I want to create an action with the following input:
input PurchaseInput {
user: UserInfo!
}
UserInfo is defined as an object:
type UserInfo {
accessToken: String!
userId: Int!
}
However Hasura doens't like this and returns a 400 on saving the action.
Is it possible to define custom input types in Hasura? I feel limited by String, Int, Float, Boolean etc.
You can absolutely create custom types like in your example
type UserInfo {
accessToken: String!
userId: Int!
}
So the error is of some other origin ( action response.... ).
Hasura only has a limitation of nested object types, for example, you can not do type definition like this in action :
type User {
userId: Int!
}
type UserInfo {
accessToken: String!
user: User!
}

Using hotchocolate's filters with schema first approach

I'm using a schema interceptor to configure my schema. It's a multi-tenant application, so I build the schema according to the tenant's configuration. I'm mapping that configuration to SDL language (schema-first approach) and then I add it to the schema builder (schemaBuilder.AddDocumentFromString(...)).
As said on the documentation (here), "Schema-first does currently not support filtering!". But that is the only approach I can use right now, so I'm trying to find a workaround.
What I've tried:
Manually create the input filter types and add the filtering to the server (something like this):
...
schemaBuilder.AddDocumentFromString(#"
type Query {
persons(where: PersonFilterInput): [Person]
}
input PersonFilterInput {
and: [PersonFilterInput!]
or: [PersonFilterInput!]
name: StringOperationFilterInput
}
input StringOperationFilterInput {
and: [StringOperationFilterInput!]
or: [StringOperationFilterInput!]
eq: String
neq: String
contains: String
ncontains: String
in: [String]
nin: [String]
startsWith: String
nstartsWith: String
endsWith: String
nendsWith: String
}
}
type Person {
name: String
}");
...
//add resolvers
...
And on the server configuration:
services
.AddGraphQLServer()
.TryAddSchemaInterceptor<TenantSchemaInterceptor>()
.AddFiltering();
However, this is not enough because the filters aren't being applied.
Query:
{
persons (where: { name: {eq: "Joao" }}){
name
}
}
Results:
{
"data": {
"persons": [
{
"name": "Joao"
},
{
"name": "Liliana"
}
]
}
}
Is there anything I can do to workaround this problem?
Thank you people
Filter support for schema-first is coming with version 12. You then do not even have to specify everything since we will provide schema building directives.
type Query {
persons: [Person] #filtering
}
type Person {
name: String
}
you also will be able to control which filter operations can be provided. We have the first preview coming up this week.

AppSync #connection not making two-way connection

I'm using graphql through AWS AppSync. Given my models below I would expect when I successfully createClassroom with createClassroomInput that the teacherClassrooms would have a new Classroom associated to it and that the newly created Classroom would have a teacher associated to it.
The outcome, however, is that Classroom is created and the User is correctly associated with the new Classroom but the Classroom is not associated to the existing User.
type User #model {
id: ID!
userType: String!
teacherClassrooms: [Classroom] #connection(name: "TeacherClassrooms")
}
type Classroom #model {
id: ID!
teacher: User #connection(name: "TeacherClassrooms")
linkCode: String!
name: String!
}
export type CreateClassroomInput = {
id?: string | null,
linkCode: string,
name: string,
classroomTeacherId?: string | null,
};
So, if I query for listClassrooms, each classroom comes back with its associated User. But if I query for a User they do not have any classrooms in their teacherClassrooms array.
Do I need to updateUser when I create a new Classroom? My intuition, and my understanding of the docs, lead me to believe that AppSync would handle both updates when #connection is specified on a model property.
Or is this just a way of indicating to the backend that "for each Id in this property array assume it's of type X and when queried go fetch by Id against the corresponding table"?
Check your list query. I had the same issue and then realised that generated list query was missing relation attributes after I updated schema with name connection. In your case something like this
listUsers {
items {
id
teacherClassrooms {
items {
linkCode
id name
}
}
}
}
inside your listUsers query

Error: Resolver associated with data sources

I'm having the serverless error:
Resolver associated with data sources when building from serverless.yml config file:
# serverless.yml
...
mappingTemplates:
- dataSource: Wallet
type: Query
field: walletFromId
request: "_dynamo-get-wallet.txt"
response: "_generic-result-response.txt"
- dataSource: Wallet
type: Query
field: walletsFromUser
request: "_dynamo-get-wallets-from-user.txt"
response: "_generic-result-response.txt"
- dataSource: Wallet
type: Mutation
field: registerWallet
request: "_dynamo-put-wallet.txt"
response: "_generic-result-response.txt"
dataSources:
- type: AMAZON_DYNAMODB
name: Wallet
description: 'Wallet DataSource'
config:
tableName: "${self:custom.stage}-Wallet"
serviceRoleArn: "arn:aws:iam::${self:custom.accountId}:role/${self:custom.appSync.serviceRole}"
...
I also have a schema.graphql:
type Query {
# query the wallet with given id and get the output with detail info
walletFromId(walletId: String!): Wallet!
# query wallets with given user id and get list of cards
walletsFromUser(userId: String!): [Wallet!]!
}
type Mutation {
# Add a wallet to an existing user
registerWallet(userId: String!, number: String!, cvx: String!, expirationDate: String!): Wallet!
}
type Wallet {
walletId: String!
userId: String!
number: String!
cvx: String!
expirationDate: String!
}
type Subscription {
addWallet: Wallet
#aws_subscribe(mutations: ["registerWallet"])
}
schema {
query: Query
mutation: Mutation
subscription: Subscription
}
I could not find a single clue as to what this error mean, and there isn't anything else I can get from the build logs.
This error usually means you are trying to delete a data source that is currently being used by a resolver. If you can identify the resolver pointing to the data source and delete it then you should no longer see the error message.

Resources