Shopify bulk query results parsing - shopify

I am working on a shopify integration, and I am trying to perform some bulk queries which return data in jsonl format.
I read carefully the documentation, and I understood which is the principle behind this format, but there is one thing I don't understand: the following is a portion of my jsonl file representing the first item in the result
{"id":"gid:\/\/shopify\/Product\/6755349070004","options":[{"id":"gid:\/\/shopify\/ProductOption\/8677003133108","name":"Città","position":1}],"title":"Product title","productType":"Concerto Live"}
{"id":"gid:\/\/shopify\/ProductVariant\/40163436363956","price":"100.00","title":"MIlano","__parentId":"gid:\/\/shopify\/Product\/6755349070004"}
{"id":"gid:\/\/shopify\/ProductVariant\/40163436396724","price":"100.00","title":"Roma","__parentId":"gid:\/\/shopify\/Product\/6755349070004"}
{"id":"gid:\/\/shopify\/ProductVariant\/40163436429492","price":"100.00","title":"Firenze","__parentId":"gid:\/\/shopify\/Product\/6755349070004"}
{"id":"gid:\/\/shopify\/Collection\/272323707060","description":"Product variant description","title":"CONCERTI","__parentId":"gid:\/\/shopify\/Product\/6755349070004"}
{"id":"gid:\/\/shopify\/Collection\/272323739828","description":"Product variant description","title":"LIVE","__parentId":"gid:\/\/shopify\/Product\/6755349070004"}
{"id":"gid:\/\/shopify\/Collection\/273036607668","description":"Product variant description","title":"Product variant description","__parentId":"gid:\/\/shopify\/Product\/6755349070004"}
and it's obtained by the following query
mutation {
bulkOperationRunQuery(
query: """
{
items: products{
pageInfo {
hasNextPage
}
edges {
cursor
node {
id
variants(first: 10) {
edges {
node {
id
price
title
}
}
}
options(first: 5) {
id
name
position
}
title
collections(first: 8) {
edges {
node {
id
metafields(first: 5) {
edges {
node {
id
key
namespace
value
}
}
}
description
title
}
}
}
productType
images(first: 2) {
edges {
node {
src
}
}
}
}
}
}
}
"""
) {
bulkOperation {
id
status
}
userErrors {
field
message
}
}
}
So The first line it the "main" product object, the lines 2,3 and 4 are the variants, then we have the collections and then the image: the problem is that, besides the parent's id, there is no way to know which parent's property a child line refers to. If I want to build back a json from this, how can I know for example that the second line is an item of the array in products.variants?

You can use either:
the id format (gid://shopify/Product/6755349070004 is a product)
the __typename property that exists on all GraphQL objects

Related

Find all items with empty many to many relationship in vapor fluent

Given the example from the vapor docs:
// Example of a pivot model.
final class PlanetTag: Model {
static let schema = "planet+tag"
#ID(key: .id)
var id: UUID?
#Parent(key: "planet_id")
var planet: Planet
#Parent(key: "tag_id")
var tag: Tag
init() { }
init(id: UUID? = nil, planet: Planet, tag: Tag) throws {
self.id = id
self.$planet.id = try planet.requireID()
self.$tag.id = try tag.requireID()
}
}
final class Planet: Model {
// Example of a siblings relation.
#Siblings(through: PlanetTag.self, from: \.$planet, to: \.$tag)
public var tags: [Tag]
}
final class Tag: Model {
// Example of a siblings relation.
#Siblings(through: PlanetTag.self, from: \.$tag, to: \.$planet)
public var planets: [Planet]
}
How can I query with fluent all planets which do not have a tag?
Planet.query(on: req.db).filter(?).all()
EDIT: Solution but with async/await
let pivots = try await PlanetTag.query(on: req.db).unique().all()
let planetsWithTags = pivots.map { $0.$planet.id }
let planetsWithoutTags = Planet.query(on: req.db).filter(\.$id !~ planetsWithTags)
return try await planetsWithoutTags.paginate(for: req).map(\.detail)
I haven't checked this out but, intuitively, this should work if you want to make use of the Sibling relationship:
Planet.query(on:req.db).with(\.$tags).all().map { allPlanets in
let planetWithoutTags = allPlanets.filter { $0.tags.isEmpty }
// continue processing
}
This is a bit wasteful, since you are fetching (potentially) lots of records that you don't want. A better approach is to get the planets that do have tags and then exclude those:
PlanetTag.query(on:req.db).unique().all(\.$planet).flatMap { planetTags in
return Planet.query(on:req.db).filter(\.$id !~ planetTags.map { $0.$planet.$id }).all().flatMap { planetsWithoutTags in
// continue processing
}
}

GraphQl Variable Question - hardcode works

I am wondering why my 2nd postman request does not work when utilizing variables for graphql api POST request.
The 1st request below works on Postman.
Variables with graphql issue.
query {getById(id: "2"){
id
name
icon
elements {
id name link
elements {
id name link
elements {
id name link
elements {
id name link
}
}
}
}
} }
query {getById($id: String ){
id ($id: id)
name
icon
elements {
id name link
elements {
id name link
elements {
id name link
elements {
id name link
}
}
}
}
}
}
} }
variable
{
"id": "2"
}
Your second postman request is not working because you're not having the node called "2" in the graphQL definition.
A simple breakdown of your request:
query {getById(id: "2"){
Above identifies the item with id 2 from the service.
All below that method are just nodes that you want to retrieve.
Also I think you can just use below:
query {getById($id: String ){
id
name
icon
elements {
id name link
}
}

QML ListModel and custom function property

I want to write tuned version of TableView (TableView.qml in Qt package).
I have ColumnDescriptor.qml with column definition:
Item {
property string title
property var formatDelegate: null
.... (other property definition)
function format(val) {
if (formatDelegate != null)
return formatDelegate(val);
else
return val;
}
}
The above code defines set of properties and fuction format(val), that calls for format value if formatDelefate was set.
In the main table I use list to store predefined columns definition (temporaly) and ListModel to store final columns definition ( the latter is more useful than list in remaining implementation)
list example:
property list<ColumnDescriptor> colDefines: [
ColumnDescriptor {
title: qsTr("col1")
},
ColumnDescriptor {
title: qsTr("col2")
formatDelegate: function(val) { return "!" + val}
}
]
Filling ListModel (id: columnModel):
Component.onCompleted: {
for(var i = 0; i < colDefines.length; ++i)
{
var col = colDefines[i];
...(some calculation)
columnModel.append(col);
}
}
All looks fine, but when I try to call format from model item, Qt sends me the following error
Property 'format' of object QQmlDMListAccessorData(0x8e3bf78) is not a function
Example of calling format:
Repeater {
model: columnModel
Text {
text: model.format([SOME USEFUL DATA])
}
}
On the other hand, if I call format directly from list it works well.
So my question here is how to fill model in a way that the format or other function will work correctly when being called from model?
For QtQuick2 this should work
formatDelegate = [function(val) { return "!" + val}]
formatDelegate[0]("some text")
but you could also use an overriding technique:
Item {
function formatDelegate(val) {
return val;
}
function format(val) {
return formatDelegate(val);
}
}
ColumnDescriptor {
function formatDelegate(val) {
return "!" + val
}
}
This way Item.format() should call "return val" as default and "!"+val for ColumnDescriptor given that ColumnDescriptor is derived from Item.
Try this
Repeater {
model: columnModel
Text {
text: columnModel[index].format([SOME USEFUL DATA])
}
}

CoolStorage can't set One-To-One relationship

The issue is that I can't understand how to make a OneToOne relation between two objects the way for the first object to have a link to the second and for the second to have a link to the first. Here's the code:
[MapTo("Model")]
public class Model : CSObject<Model, int>
{
[OneToOne(LocalKey = "ModelID", ForeignKey = "ModelID")]
public Product Product { get { return (Product)GetField ("Product"); } set { SetField ("Product", value); } }
}
[MapTo("Product")]
public class Product : CSObject<Product, int>
{
[OneToOne(LocalKey = "ProductID", ForeignKey = "ProductID")]
public Model Model { get { return (Model)GetField ("Model"); } set { SetField ("Model", value); } }
}
The thing is that when I create a product and a model and set the model's property "Product" to the created one and save it, the product's "Model" property doesn't get set and remains NULL. I've already tried making all the local and foreign keys for both Product's and Model's properties the same (e.g. "ModelID") but it didn't solve the problem. What is the right way of doing this?
I guess making one of them [OneToMany] will do the trick but will return a collection while I need a single object to be returned by a property.
Update
Here comes a simple solution one would call a crutch:
[OneToMany]
public CSList<Product> _ProductList { get { return (CSList<Product>)GetField ("_ProductList"); } set { SetField ("_ProductList", value); } }
[NotMapped]
public Product Product {
get {
CSList<Product> list = this._ProductList;
if (list.Count > 0)
return list [0];
return null;
}
set {
if (value != null) {
CSList<Product> list = this._ProductList;
list.RemoveAll ();
list.Add (value);
}
}
}
You can make both relations [ManyToOne]. That will work in your scenario.

Getting NHibernate to store unique object only once

I have got four tables in NHibernate
Job
{
DBID { int, primary key }
Name { string }
Media { fk_media (int) }
PublishInfo { fk_publishinfo (int) }
}
Media
{
DBID { int, primary key }
TransmissionID { string }
Series { string }
Title { string }
Description { string }
}
PublishInfo
{
DBID { int, primary key }
Destination { string }
AudioTrack_1 { fk_audiolanguage }
AudioTrack_2 { fk_audiolanguage }
AudioTrack_3 { fk_audiolanguage }
AudioTrack_4 { fk_audiolanguage }
}
AudioLanguage
{
Code { string, primary key }
Description { string }
}
What I want to achive with NHibernate is that it only stores unique records. So if a Media is used multiple times they all point to the same media entry. Same goes for PublishInfo.
A second issue I ran into is that when using the same audiolanguage for audiotrack_3 and 4 for instance it gives a error that is was already used in the session.
Any tips how I would do this properly?
This is a partial anwser to my own question. The reason it wasn't working correctly for the languages when using same lanuage on multiple tracks is because they got send back and forth between a client and server application. The way I solved this is by receiving it back to the server I lookup the proper objects stored in a list on the server and replace them.
I do not think this is the proper solution but it works.