GraphCms publishOrderMutation how to update OrderItem as well - next.js

I create a new order after the
payment with stripe, and I update the
stage to published
the brand new order with this code:
const order = {
email: session.customer_email,
total: session.amount_total,
stripeCheckoutId: session.id,
orderItems: {
create: line_items!.data.map((item) => ({
quantity: item.quantity,
total: item.amount_total,
product: {
connect: {
id: (item.price?.product as Stripe.Product).metadata.productId
}
}
}))
}
};
const result = await client
.mutation(CreateOrderMutationDocument, {
order
})
.toPromise();
const id = result.data.order.id;
const result2 = await client
.mutation(PublishOrderMutationDocument, {
id
})
.toPromise();
but how to update OrderItem as well
I've tried with
mutation publishOrderItemMutation($id: ID!) {
publishOrder(where: { order: $id }, to: PUBLISHED) {
id
}
}
but I've got
Error 0: GraphQLDocumentError: Field "order" is not defined by type
"OrderWhereUniqueInput".

Related

How do I access data in GraphQL if not by the id?

I'm using GraphQL with Meteor and Pup v2, and I have a problem accessing the users data via a special ID provided to every user on signup, this ID will be used in a link (mysite.com/user/specialId) so other users can view the searched users account. Problem is, I can't get the data with the special ID, I can't get any data back if I don't pass in the users _id provided by MongoDB. Below I have a bunch of the code used:
Attempt 1
I tried to use a custom on-the-go way just to be able to at least access the data to see if it works (and then implement it correctly later)
const GET_USER_DETAILS = gql`
query user($userId: String) {
user(userId: $userId) {
userId
username
_id
}
}
`;
Here I export so I can get the data:
export default compose(
graphql(GET_USER_DETAILS, {
options: ({ match }) => ({
fetchPolicy: 'no-cache',
variables: {
// existing specialId for testing purposes, to be replaced with match.params.userId
userId: "J4xZzvvhBDSEufnBn",
},
}),
}),
)(PublicProfileView);
This returns a 400 error Network error: Response not successful: Received status code 400 error and after multiple attempts, I could not fix it, so I tried a different approach...
Attempt 2
I tried to go deep into the files and change the GraphQL. Created a new query:
query userById($userId: String) {
userById(userId: $userId) {
...UserAttributes
}
}
(Mentioned fragment)
fragment UserAttributes on User {
_id
name {
...
}
username
emailAddress
oAuthProvider
roles {
...
}
settings {
...
}
userId
}
Tried to add new item in API:
type Query {
...
userById(userId: String): User
...
}
Resolver:
resolvers: {
Query: {
...
userById: (parent, args) => {
// Assuming args equals an object like { _id: '123' };
return UserQueries.userById(args);
},
},
},
query.js, attempt 1:
userById: (parent) => queryUsers.find({ userId: parent.userId }, { sort: { createdAt: 1 } }).fetch()
Attempt 2:
userById: (parent, args, context) => {
return queryUsers({
userId: parent.userId,
});
},
And finally
Attempt 3
I tried to modify the get query
const getQueryModified = (options) => {
// console.log(options.userId)
try {
return options.userId
? { 'userId': options.userId }
: { userId: options.userId };
} catch (exception) {
throw new Error(`[queryUsers.getQuery] ${exception.message}`);
}
};
Here is the original query I tried to modify:
const getQuery = (options) => {
try {
return options.search
? {
_id: { $ne: options.currentUser._id },
$or: [
{ 'profile.name.first': options.search },
{ 'profile.name.last': options.search },
{ 'emails.address': options.search },
// { 'userId': options.search },
{ 'services.facebook.first_name': options.search },
{ 'services.facebook.last_name': options.search },
{ 'services.facebook.email': options.search },
],
}
: { _id: options.currentUser._id };
} catch (exception) {
throw new Error(`[queryUsers.getQuery] ${exception.message}`);
}
};
Unfortunately this was also unsuccessful, the best I get from these when executing the below query is null...
userById(userId: "J4xZzvvhBDSEufnBn"){
username
}
All I want is to get the user data from their userId and not their _id, but I can't seem to figure out how to do it

How can I upload an image to firebase storage and add it to the database?

I'm new to Vuejs. I want to have a form using which you can add products. The product image goes to firebase storage but how do I associate that image with the exact product in the database?
I've already set up my form, and created two methods. saveProduct() to save the products to the database and onFilePicked() to listen for changes in the input field and target the image and upload that to storage.
import { fb, db } from '../firebaseinit'
export default {
name: 'addProduct',
data () {
return {
product_id: null,
name: null,
desc: null,
category: null,
brand: null,
image: null,
}
},
methods: {
saveProduct () {
db.collection('products').add({
product_id: this.product_id,
name: this.name,
desc: this.desc,
category: this.category,
brand: this.brand
})
.then(docRef => {
this.$router.push('/fsbo/produkten')
})
},
onFilePicked (event) {
let imageFile = event.target.files[0]
let storageRef = fb.storage().ref('products/' + imageFile.name)
storageRef.put(imageFile)
}
}
}
what about this, you can use the filename, your images are going to be served as somefireurl.com/{your_file_name} on your product collection you can have an image prop with the imageFile.name.
methods: {
saveProduct (image = null) {
let productRef = db.collection('products').doc(this.product_id)
const payload = {
product_id: this.product_id,
name: this.name,
desc: this.desc,
category: this.category,
brand: this.brand
}
if (image) payload['image'] = image
return productRef
.set(payload, {merge: true})
.then(docRef => {
this.$router.push('/fsbo/produkten')
})
},
onFilePicked (event) {
let imageFile = event.target.files[0]
let storageRef = fb.storage().ref('products/' + imageFile.name)
storageRef.put(imageFile)
return this.saveProduct(imageFile.name)
}
}
That should be enough to get you started, maybe you want to try a different combination, or maybe you dont want to call saveProduct the way I set it, it's up to your use case but the idea is the same. Hope this can help you
I fixed it myself. Here's my solution. I don't know if it's technically correct but it works for my use case.
methods: {
saveProduct () {
let imageFile
let imageFileName
let ext
let imageUrl
let key
let task
db.collection('products').add({
product_id: this.product_id,
name: this.name,
desc: this.desc,
category: this.category,
brand: this.brand
})
.then(docRef => {
key = docRef.id
this.$router.push('/fsbo/produkten')
return key
})
.then(key => {
if(this.image !== null) {
this.onFilePicked
imageFile = this.image
imageFileName = imageFile.name
ext = imageFileName.slice(imageFileName.lastIndexOf('.'))
}
let storageRef = fb.storage().ref('products/' + key + '.' + ext)
let uploadTask = storageRef.put(imageFile)
uploadTask.on('state_changed', (snapshot) => {}, (error) => {
// Handle unsuccessful uploads
}, () => {
uploadTask.snapshot.ref.getDownloadURL().then( (downloadURL) => {
db.collection('products').doc(key).update({ imageUrl: downloadURL})
});
});
})
},
onFilePicked (event) {
return this.image = event.target.files[0]
}
}

How to dynamically update an attribute in a dynamodb item?

I created an item in dynamodb using Node js, the item has multiple attributes such as brand, category, discount, validity, etc. I am using uuid to generate ids for each item. Now let's say I want to update the validity attribute of the item, in which case I am currently sending the entire json object with the value of validity modified to the new value.
This is definitely not optimal, please help me find an optimal solution.
const params = {
TableName: process.env.PRODUCT_TABLE,
Key: {
id: event.pathParameters.id,
},
ExpressionAttributeNames: {
'#discount': 'discount',
},
ExpressionAttributeValues: {
':brand': data.brand,
':category': data.category,
':discount': data.discount,
':denominations': data.denominations,
":validity": data.validity,
":redemption": data.redemption
},
UpdateExpression: 'SET #discount = :discount, denominations = :denominations, brand = :brand, category = :category, validity = :validity, redemption = :redemption',
ReturnValues: 'ALL_NEW',
};
I want to send just the attribute I want to update with the new value, if I want to change the validity from 6 months to 8 months, I should just send something like:
{
"validity": "8 months"
}
And it should update the validity attribute of the item.
Same should apply to any other attribute of the item.
'use strict';
const AWS = require('aws-sdk');
const dynamoDb = new AWS.DynamoDB.DocumentClient();
module.exports.update = (event, context, callback) => {
const data = JSON.parse(event.body);
let attr = {};
let nameobj = {};
let exp = 'SET #';
let arr = Object.keys(data);
let attrname = {};
arr.map((key) => {attr[`:${key}`]=data[key]});
arr.map((key) => {
exp += `${key} = :${key}, `
});
arr.map((key) => {nameobj[`#${key}`]=data[key]});
attrname = {
[Object.keys(nameobj)[0]] : nameobj[Object.keys(nameobj)[0]]
}
const params = {
TableName: process.env.PRODUCT_TABLE,
Key: {
id: event.pathParameters.id,
},
ExpressionAttributeNames: attrname,
ExpressionAttributeValues: attr,
UpdateExpression: exp,
ReturnValues: 'ALL_NEW',
};
// update the todo in the database
dynamoDb.update(params, (error, result) => {
// handle potential errors
if (error) {
console.error(error);
callback(null, {
statusCode: error.statusCode || 501,
headers: { 'Content-Type': 'text/plain' },
body: 'Couldn\'t update the card',
});
return;
}
// create a response
const response = {
statusCode: 200,
body: JSON.stringify(result.Attributes),
};
callback(null, response);
});
};
Contrary to others comments, this is very possible, use the UpdateItem action.
Language agnostic API docs
JavaScript specific API docs
If you want to dynamically create the query, try something like this:
const generateUpdateQuery = (fields) => {
let exp = {
UpdateExpression: 'set',
ExpressionAttributeNames: {},
ExpressionAttributeValues: {}
}
Object.entries(fields).forEach(([key, item]) => {
exp.UpdateExpression += ` #${key} = :${key},`;
exp.ExpressionAttributeNames[`#${key}`] = key;
exp.ExpressionAttributeValues[`:${key}`] = item
})
exp.UpdateExpression = exp.UpdateExpression.slice(0, -1);
return exp
}
let data = {
'field' : { 'subfield': 123 },
'other': '456'
}
let expression = generateUpdateQuery(data)
let params = {
// Key, Table, etc..
...expression
}
console.log(params)
Output:
{
UpdateExpression: 'set #field = :field, #other = :other',
ExpressionAttributeNames: {
'#field': 'field',
'#other': 'other'
},
ExpressionAttributeValues: {
':field': {
'subfield': 123
},
':other': '456'
}
}
Using Javascript SDK V3:
Import from the right package:
import { DynamoDBClient PutItemCommandInput, UpdateItemCommandInput, UpdateItemCommand } from '#aws-sdk/client-dynamodb';
Function to dynamically do partial updates to the item:
(the code below is typescript can be easily converted to Javascript, just remove the types!)
function updateItem(id: string, item: any) {
const dbClient = new DynamoDBClient({region: 'your-region-here });
let exp = 'set ';
let attNames: any = { };
let attVal: any = { };
for(const attribute in item) {
const valKey = `:${attribute}`;
attNames[`#${attribute}`] = attribute;
exp += `#${attribute} = ${valKey}, `;
const val = item[attribute];
attVal[valKey] = { [getDynamoType(val)]: val };
}
exp = exp.substring(0, exp.length - 2);
const params: UpdateItemCommandInput = {
TableName: 'your-table-name-here',
Key: { id: { S: id } },
UpdateExpression: exp,
ExpressionAttributeValues: attVal,
ExpressionAttributeNames: attNames,
ReturnValues: 'ALL_NEW',
};
try {
console.debug('writing to db: ', params);
const command = new UpdateItemCommand(params);
const res = await dbClient.send(command);
console.debug('db res: ', res);
return true;
} catch (err) {
console.error('error writing to dynamoDB: ', err);
return false;
}
}
And to use it (we can do partial updates as well):
updateItem('some-unique-id', { name: 'some-attributes' });
What i did is create a helper class.
Here is a simple function : Add all the attribute and values that goes into, if the value is null or undefined it won't be in the expression.
I recommande to create a helper class with typescript and add more functions and other stuff like generator of expressionAttributeValues , expressionAttributeNames ... , Hope this help.
function updateExpression(attributes, values) {
const expression = attributes.reduce((res, attribute, index) => {
if (values[index]) {
res += ` #${attribute}=:${attribute},`;
}
return res;
}, "SET ");
return expression.slice(0, expression.length - 1)
}
console.log(
updateExpression(["id", "age", "power"], ["e8a8da9a-fab0-55ba-bae3-6392e1ebf624", 28, undefined])
);
You can use code and generate the params object based on the object you provide. It's just a JavaScript object, you walk through the items so that the update expression only contains the fields you have provided.
This is not really a DynamoDB question in that this is more a general JS coding question.
You can use UpdateItem; to familiarize yourself with DynamoDb queries I would suggest you DynamoDb NoSQL workbench:
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html
It can generate snippets for you based on your queries.
DynamoDb NoSQL workbench screenshot query

How do i convert a single json record retrieved from firebase into an array

I am trying to take a single record from firebase to use in vuejs but I cant find out how to convert it to an array, if thats even what i should be doing.
my mutation
GET_CASE(state, caseId) {
state.caseId = caseId;
},
My action
getCase ({ commit, context }, data) {
return axios.get('http' + data + '.json')
.then(res => {
const convertcase = []
convertcase.push({ data: res.data })
//result below of what is returned from the res.data
console.log(convertcase)
// commit('GET_CASE', convertcase)
})
.catch(e => context.error(e));
},
I now get the following returned to {{ myCase }}
[ { "data": { case_name: "Broken laptop", case_status: "live", case_summary: "This is some summary content", contact: "", createdBy: "Paul", createdDate: "2018-06-21T15:20:22.932Z", assessor: "Gould", updates: "" } } ]
when all i want to display is Broken Laptop
Thanks
Example let obj = {a: 1, b: 'a'); let arr = Object.values(obj) // arr = [1, 'a']
async getCase ({ commit, context }, url) {
try {
let { data } = await axios.get(`http${url}.json`)
commit('myMutation', Object.values(data))
} catch (error) {
context.error(error)
}
}
But as I'm reading your post again, I think you don't want array from object. You want array with one object. So, maybe this is what you want:
async getCase ({ commit, context }, url) {
try {
let { data } = await axios.get(`http${url}.json`)
commit('myMutation', [data])
} catch (error) {
context.error(error)
}
}
Put this inside / after your .then
Object.keys(data).forEach(function(k, i) {
console.log(k, i);
});
With a response from Axios, you can get your data as:
res.data.case_name
res.data.case_number
....
Just build JavaScript object holding these properties and pass this object to your mutation. I think it is better than using an array.
const obj = {};
Object.assign(obj, res.data);
commit('GET_CASE', obj)
And in your mutation you do as follows:
mutations: {
GET_CASE (state, payload) {
for (var k in payload) {
if (payload.hasOwnProperty(k)) {
state[k] = payload[k]
}
}
}
}
Alternatively you can code your store as follows:
state: {
case: {},
...
},
getters: {
getCase: state => {
return state.case
},
....
},
mutations: {
GET_CASE (state, payload) {
state.case = payload
}
}
and you call the value of a case field form a component as follows:
const case = this.$store.getters.getCase
..... = case.case_name

Akryum: Vuex#1 for Meteor example app, addTrackers?

I don't really understand any of this from https://github.com/Akryum/meteor-vuex-example/tree/master/imports/vuex/modules: from init(data) all the way to if data in getters at the bottom references to vue instance data or state of vuex.
subModule.addTrackers({
selectedThread() {
let sub;
return {
init(data) {
data.selectedThread = null;
data.posts = [];
},
watch(state) {
// Dynamic subscription
if(sub) {
sub.stop();
}
if(state.selectedThreadId) {
sub = Meteor.subscribe('posts', state.selectedThreadId);
console.log('subscribed posts to thread ', state.selectedThreadId);
}
return {
id: state.selectedThreadId
}
},
update(data, {id}) {
data.selectedThread = Object.freeze(Threads.findOne({
_id: id
}));
data.posts = Object.freeze(Posts.find({
thread_id: id
}, {
sort: {created: -1}
}).fetch());
console.log('posts', data.posts);
},
getters: {
getSelectedThread: data => data.selectedThread,
getPosts: data => data.posts
}
}
}
})

Resources