AppSync #connection not making two-way connection - amazon-dynamodb

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

Related

How can I use the Prisma adapter for Next-Auth without email and emailVerified values

I am using next-auth with a custom provider and the Prisma adapter and I only want to store the values: id, name, country, avatar, and gender. However, I am getting this error:
[next-auth][error][adapter_error_createUser]
https://next-auth.js.org/errors#adapter_error_createuser
Invalid `p.user.create()` invocation in
.\node_modules\#next-auth\prisma-adapter\dist\index.js:6:38
3 exports.PrismaAdapter = void 0;
4 function PrismaAdapter(p) {
5 return {
→ 6 createUser: (data) => p.user.create({
data: {
name: [redacted],
wcaId: [redacted],
country: [redacted],
avatar: [redacted],
gender: [redacted],
email: undefined,
emailVerified: null
~~~~~~~~~~~~~
}
})
Unknown arg `emailVerified` in data.emailVerified for type UserCreateInput. Available args:
...
The profile object in my custom provider looks like this:
profile(profile) {
return {
id: profile.me.id,
name: profile.me.name,
country: profile.me.country_iso2,
avatar: profile.me.avatar.url,
gender: profile.me.gender,
};
},
Everything in my Prisma schema follows the example in https://next-auth.js.org/adapters/prisma#setup except the User model which is like so:
model User {
id String #id #default(cuid())
name String
country String #db.Char(2)
avatar String
gender String #db.Char(1)
accounts Account[]
sessions Session[]
// Temporary workaround:
email String? #unique
emailVerified DateTime? #map("email_verified")
}
In the error, the adapter appears to have added email and emailVerified to the data object so the temporary workaround I am using is adding email and emailVerified columns to my Prisma model as shown above. However, this is not ideal, and I would like to know how I can remove these unnecessary columns from my database as their values are always undefined and null.

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!
}

AppSync GraphQL query with nested objects

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.

Query List of Maps in DynamoDB

I am trying to filter list of maps from a dynamodb table which is of the following format.
{
id: "Number",
users: {
{ userEmail: abc#gmail.com, age:"23" },
{ userEmail: de#gmail.com, age:"41" }
}
}
I need to get the data of the user with userEmail as "abc#gmail.com". Currently I am doing it using the following dynamodb query. Is there any another efficient way to solve this issue ?
var params = {
TableName: 'users',
Key:{
'id': id
}
};
var docClient = new AWS.DynamoDB.DocumentClient();
docClient.get(params, function (err, data) {
if (!err) {
const users = data.Item.users;
const user = users.filter(function (user) {
return user.email == userEmail;
});
// filtered has the required user in it
});
The only way you can get a single item in dynamo by id if you have a table with a partition key. So you need to have a table that looks like:
Email (string) - partition key
Id (some-type) - user id
...other relevant user data
Unfortunately, since a nested field cannot be a partition key you will have to maintain a separate table here and won't be able to use an index in DynamoDB (neither LSI, nor GSI).
It's a common pattern in NoSQL to duplicate data, so there is nothing unusual in it. If you were using Java, you could use transactions library, to ensure that both tables are in sync.
If you are not going to use Java you could read DynamoDB stream of the original database (where emails are nested fields) and update the new table (where emails are partition keys) when an original table is updated.

Bookshelf.js accessing multiple tables that are related

I'm dealing with three tables.
Right now I can get the feed of a user (activities table) and activityTypes object (id,type from activitytypes table), but I also need to get related_user (users table) object of a given activity, so I'll know the details of the related_user if the column isn't empty.
users
id
email
username
password_hash
activitytypes
id
type
activities
id
user_id (foreign key from users, owner of the activity)
status
activitytype_id (foreign key from activitytypes)
related_user (foreign key from users.
Shows relation with the user_id, if there's any.
if activitytype_id is 2 or 3, this will be shown as "followed, "commented", etc.)
My models
var activityType = db.Model.extend({
tableName: 'activitytypes',
hasTimestamps: false
});
var activity = db.Model.extend({
tableName: 'activities',
hasTimestamps: true,
activityTypes: function() {
return this.belongsTo(activityType);
}
});
var user = db.Model.extend({
tableName: 'users',
hasTimestamps: true,
feed: function() {
return this.hasMany(activity);
}
});
This is my existing query, how can I add related_user object to it?
user.where({id : 43}).fetchAll({withRelated : ['feed.activityTypes']}).then(function(data) {
data = data.toJSON();
res.send(data);
});
I solved it.
I added a new method to activity, like below.
userRelated : function() {
return this.belongsTo(user,'related_user');
}
And here's the updated query. I don't know whether it's the right way or not in terms of optimization, but it works.
user.where({
id: 43
}).fetchAll({
withRelated: ['feed.userRelated', 'feed.activityTypes']
}).then(function(data) {
data = data.toJSON();
res.send(data);
});
Right now feed, userRelated and activityTypes return without a problem, everything is in data in JSON format.

Resources