Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gqty doesn't respect prevSelection.unions while composing cacheKey #1342

Open
Ty3uK opened this issue Dec 16, 2022 · 1 comment
Open

gqty doesn't respect prevSelection.unions while composing cacheKey #1342

Ty3uK opened this issue Dec 16, 2022 · 1 comment

Comments

@Ty3uK
Copy link

Ty3uK commented Dec 16, 2022

Hi!

I have scheme like this (using Federation):

# type from another subgraph
type Product @key(fields: "id") {
	id: String!
	name: String!
	slug: String!
}

# type from another subgraph
type Service @key(fields: "id") {
	id: String!
	name: String!
}

type BasketItemProduct {
	id: String!
	price: String!
	count: Int!
	product: Product
	services: [Service!]!
}

type BasketItemPresent {
	id: String!
	price: String!
	count: Int!
	product: Product
}

union BasketItem =
	| BasketItemProduct
	| BasketItemPresent

type Basket {
	items: [BasketItem!]!
}

I want to fetch query like this:

query {
	basket {
		items {
			...  on BasketItemProduct {
				price
				count
				product {
					name
					slug
				}
			}
			...  on BasketItemPresent {
				price
				count
				product {
					name
					slug
				}
			}
		}
	}
}

My code (simplified) looks like this:

function mapService(service: Service | null) {
	return castNotSkeleton({
		name: service,
	});
}

function mapProduct(product: Product | null) {
	return castNotSkeleton({
		name: product.name,
		slug: product.slug,
		services: product.services.map(mapService),
	});
}

function mapBasketItemProduct(itemProduct: BasketItemProduct | null) {
	if (!itemProduct) {
		return null;
	}
	
	return castNotSkeleton({
		id: itemProduct,
		price: itemProduct.price,
		count: itemProduct.count,
		product: mapProduct(itemProduct.product ?? null),
	});
}

function mapBasketItemPresent(itemPresent: BasketItemPresent | null) {
	if (! itemPresent) {
		return null;
	}

	return castNotSkeleton({
		id: itemPresent,
		price: itemPresent.price,
		count: itemPresent.count,
		product: mapProduct(itemPresent.product ?? null),
	});
}

export function api() {
	return resolved(() => {
		return query.basket.items.map((it) => ({
			product: mapBasketItemProduct(it.$on.BasketItemProduct ?? null),
			present: mapBasketItemProduct(it.$BasketItemPresent ?? null),
		}));
	});
}

and with this piece of code I've got query like this (simplified):

query {
	basket {
		items {
			...  on BasketItemProduct {
				price
				count
				product {
					name
					slug
				}
			}
			...  on BasketItemPresent {
				price
				count
			}
		}
	}
}

so second usage of mapproduct is ignored.

After some investigation I found that problem is in this piece of code:

let cacheKey = key + '';
if (args && argTypes) {
alias = getVariableAlias(key, args, argTypes);
cacheKey = alias;
}
if (prevSelection) {
cacheKey = prevSelection.pathString + '.' + cacheKey;
}
if (unions?.length) {
cacheKey += ';' + unions.join(';');
}
let selection = selectionCache.get(cacheKey);
if (selection == null) {

because cacheKey for Product.slug (for example) looks like this: basket.items.0.product.slug and at the second pass it returns entry for BasketItemProduct and not creating seperate one for BasketItemPresent

My ugly fix for testing looks like this:

if (prevSelection?.unions?.length > 0) {
  cacheKey += ";" + prevSelection.unions.join(";");
}
let selection = selectionCache.get(cacheKey);
if (selection == null || selection.prevSelection !== prevSelection) ...

I hope you can forward me to the right point for this issue! ❤️

@vicary
Copy link
Member

vicary commented May 4, 2024

Hey @Ty3uK, since the merge of v3 the cache is completely rewritten.

You may try installing gqty@canary, see if it works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants