Is smart query custom variable name possible? - vue.js

I'm using Vue alongside with Apollo in order to query a GraphQL endpoint in my project. Everything's fine but I want to start programming generic components to ease and fasten the development.
The thing is, in most views, I use the Smart Query system.
For instance, I use :
apollo: {
group: {
query: GROUP_QUERY,
variables () { return { id: this.groupId } },
skip () { return this.groupId === undefined },
result ({ data }) {
this.form.name = data.group.name
}
}
}
With the GROUP_QUERY that is :
const GROUP_QUERY = gql`
query groupQuery ($id: ID) {
group (id: $id) {
id
name
usersCount
userIds {
id
username
}
}
}
`
So my group variable in my apollo smart query has the same name as the query itself group (id: $id). It is this mechanism that is quite annoying for what I try to achieve. Is there a way to avoid that default mechanism ?
I'd like for instance to be able to give a generic name such as record, and it would be records for queries that potentially return multiple records.
With that, I would be able to make generic components or mixins that operate either on record or records.
Or have I to rename all my queries to record and records which would be annoying later on in case of troubleshooting with error messages ?
Or maybe there's another way to achieve that and I didn't think about it ?
Thanks in advance.

You can, in fact, rename the variable of Apollo smart queries using the update option, as seen here in the Vue Apollo documentation. Your example would look like:
apollo: {
record: {
query: GROUP_QUERY,
variables () { return { id: this.groupId } },
update: (data) => data.group,
skip () { return this.groupId === undefined },
result ({ data }) {
this.form.name = data.group.name
}
}
}
You should notice that the Apollo object will create a record variable in your component, and the update statement shows where to get the group for the record.

By doing so :
const GROUP_QUERY = gql`
query groupQuery ($id: ID) {
record: group (id: $id) {
id
name
usersCount
userIds {
id
username
}
}
}
`
If the GROUP_QUERY is used at several places, the result will be accessible under the record name, because it is defined as an alias over group.
See documentation for Aliases.

Related

Retrieve config value from sales channel in plugin settings

How can I retrieve values from the plugin config for a specific sales channel? I need to validate an API-Token, but can only retrieve the value stored for all sales channels and don't know how my custom admin component could even know about its current sales channel.
Currently, I am retrieving values via the following code, which follows the example plugin from Shopware, but they too only retrieve the global value.
Component.register('my-component', {
computed: {
getMyKey() {
return this.pluginConfig['MyPlugin.config.myKey'];
},
pluginConfig() {
let $parent = this.$parent;
while ($parent.actualConfigData === undefined) {
$parent = $parent.$parent;
}
return $parent.actualConfigData.null;
}
}
}
You may want to inject systemConfigApiService and use it to retrieve the config values. getValues takes a second argument for the sales channel id.
Component.register('my-component', {
inject: ['systemConfigApiService'],
methods: {
getConfig(salesChannelId) {
const values = this.systemConfigApiService
.getValues('MyPlugin.config', salesChannelId);
return values.myKey;
},
},
}

Calling function in VueApollo after API response

I am using Vue and Apollo and I am making a querie that looks just like the box below.
After I get the API response, I would like to call a method from my methods object. However Vue, doesn't give me acess to it within apollo object.
I would like to know how can I call one of my methods, but only after I am sure I got that response, without having to manually trigger it with a button or something else.
apollo: {
materials: {
query: gql`
query allMaterials($tenantId: ID, $name: String) {
tenantMaterials(tenantId: $tenantId, name: $name) {
edges {
node {
name
materialType {
name
id
}
brand
vendor
size
unit
inventory
createdAt
updatedAt
isActive
updatedBy
id
}
}
totalCount
}
}
`,
variables() {
return {
name: null
};
},
fetchPolicy: "cache-and-network",
update: response => {
return response.tenantMaterials.edges;
//I want to call a function/method after this response
},
skip: false
},
}
Use update(data) or result(result, key)
update(data) {return ...} to customize the value that is set in the
vue property, for example if the field names don't match.
result(ApolloQueryResult, key) is a hook called when a result is
received (see documentation for ApolloQueryResult (opens new window)).
key is the query key in the apollo option.
https://apollo.vuejs.org/api/smart-query.html

Loopback 4 - How to find the highest value in column (Like SELECT MAX(column) from Table)?

I want to find the highest value in a specific column of a specific table. It should be very simple.
this is the documentation of LB4 https://loopback.io/doc/en/lb2/Where-filter But I didn't find it there.
We did this through a custom repository method where we execute a select max() query and have a custom controller method (i.e. /next-id) that calls it.
Repository method:
async nextId(): Promise<any> {
return this.dataSource
.execute('select MAX(id)+5 as nextId from route_lookup')
.then(data => {
if (data[0].NEXTID === null) {
data[0].NEXTID = 1005;
}
return data[0].NEXTID;
});
}
Controller method:
#get('/route-lookups/next-id')
#response(200, {
description: 'Next avaialble id for route lookup',
content: {
'application/json': {
schema: {
type: 'number',
},
},
},
})
async nextId(): Promise<number> {
return await this.routeLookupRepository.nextId();
}
Within the Loopback Filter Documentation they do mention a way to achieve this, even though it's not as obvious.
/weapons?filter[where][effectiveRange][gt]=900&filter[limit]=3
Essentially you can do the following:
Identify the column of interest.
Use the gt operator to set a min number
Add order if you wanted to ensure the sorting order is as expected.
Limit the results to 1.
Here is a code example:
Employees.find({
where: {
age: {
gt: 1
}
},
order: 'age ASC',
limit: 1
})
Please let me know if this is what you were going for or if you need some more support.

How to sort result set using computed fields (type-graphql)

I'm using type-graphql and typeorm. Is there a way to sort the result based on a computed field. Specifically, I want to return a list of Clients and sort the list based on a computed field: "sortName". Sort name is simply a string of the clent's "firstName lastName" or "lastName FirstName". The decision on how to generate the sortName is based on a flag in the Company table (that way the user can control how they want to view their clients). I just don't know how to do the sort prior to sending back to the front-end app. I know I can create a view and do it in sql - but I'd like to know if it's possible to do in code.
import {Arg, Ctx, Field, FieldResolver, ID, InputType, ObjectType, Query, Resolver, Root,} from 'type-graphql'
import {Client} from '../entities/Client'
import {ClientNameSort, Company} from '../entities/Company'
import {MyContext} from '../types/MyContext'
#InputType()
export class ClientsOptions {
#Field(() => ID)
companyId!: string
}
#ObjectType()
#Resolver(Client)
export class ClientResolver {
#FieldResolver(() => String)
async sortName(#Root() client: Client, #Ctx() { companyLoader }: MyContext) {
const company:Company = await companyLoader.load(client.companyId)
if (!company) {
throw new Error(`Missing rec for Company Id ${client.companyId}`)
}
if (company.clientNameSort === ClientNameSort.FIRST_NAME) {
return `${client.firstName} ${client.lastName} ${client.id}`
} else {
return `${client.lastName} ${client.firstName} ${client.id}`
}
}
#Query(() => [Client])
async clients(#Arg('options') options: ClientsOptions) {
const clientList = await Client.find({ where: { companyId: options.companyId } })
return clientList;
}
}
I believe you have to do the sorting on the "clients" method. Therefore i am not sure the field resolver is going to help you. You better separate that into a utility function and reuse it in both methods.
To to the sorting on the clients method:
if you use mongodb, maybe you can do an aggregated query that will create this virtual field and order by it
if you use another DB , you will have to look if they have this kind of feature
If you don't want to do sorting through DB, you can get the array of clients and do a sort
clients.sort((a,b) => sortByCompanyName(company.CLIENT_NAME_SORT, a, b))
getFullIdentificator(order, client) {
if (order === ClientNameSort.FIRST_NAME) {
return `${client.firstName} ${client.lastName} ${client.id}`
} else {
return `${client.lastName} ${client.firstName} ${client.id}`
}
}
sortByCompanyName(order, prev, next) {
return getFullIdentificator(order, prev) > getFullIdentificator(order, next) ? 1 : -1
}

Graphql query only not null objects

im trying to perform a query like this:
{
people{
pet{
name
}
}
}
result:
{
"people": {
"pet": null
}
},
{
"people": {
"pet": {
name: "steve"
}
}
}
What i want is to get only people that contains a pet, is there any way to achieve this not coding on my resolver ?
Actually, it is possible with the filter: { pet: {ne: null} } filtering:
query allPeople(filter: { people: { pet: {ne: null} } }) {
people {
pet
}
}
This is not possible the way you describe. GraphQL will call resolve functions to fetch the data. If you don't want certain data in your response, you have to filter it somewhere on the server. The only thing you have control over is the query, the schema and the resolve functions.
There is no way to express your requirement purely in the query. If you put it in the schema, you would no longer be able to query for people without pets. So the only way to do it is to write it in your resolve function. You could for example add a boolean argument called hasPet to your people field, and do this in the resolver:
people(root, { hasPet }){
// get allPeople
if (typeof hasPet === 'undefined'){
return allPeople
}
return allPeople.filter((person) => person.hasPet() === hasPet)
}
The unfortunate thing is that this will require you to 'look ahead' and figure out if a person has a pet in the first place, but if you cache backend or DB requests with something like DataLoader, this isn't actually costly, because you would have to fetch the pet anyway. This way you just fetch it a bit earlier.
If you're fetching your people from a database, it would of course make sense to already filter them there, and not in the resolve function.