Browse Source

feat(core): Language fallback when querying Product/Collection by slug

Closes #538
Michael Bromley 5 years ago
parent
commit
0a12f8e894

+ 16 - 0
packages/core/e2e/collection.e2e-spec.ts

@@ -359,6 +359,22 @@ describe('Collection resolver', () => {
             expect(result.collection.id).toBe(computersCollection.id);
         });
 
+        // https://github.com/vendure-ecommerce/vendure/issues/538
+        it('falls back to default language slug', async () => {
+            const result = await adminClient.query<GetCollection.Query, GetCollection.Variables>(
+                GET_COLLECTION,
+                {
+                    slug: computersCollection.slug,
+                },
+                { languageCode: LanguageCode.de },
+            );
+            if (!result.collection) {
+                fail(`did not return the collection`);
+                return;
+            }
+            expect(result.collection.id).toBe(computersCollection.id);
+        });
+
         it(
             'throws if neither id nor slug provided',
             assertThrowsWithMessage(async () => {

+ 15 - 0
packages/core/e2e/product.e2e-spec.ts

@@ -252,6 +252,21 @@ describe('Product resolver', () => {
             expect(product.slug).toBe('curvy-monitor');
         });
 
+        // https://github.com/vendure-ecommerce/vendure/issues/538
+        it('falls back to default language slug', async () => {
+            const { product } = await adminClient.query<GetProductSimple.Query, GetProductSimple.Variables>(
+                GET_PRODUCT_SIMPLE,
+                { slug: 'curvy-monitor' },
+                { languageCode: LanguageCode.de },
+            );
+
+            if (!product) {
+                fail('Product not found');
+                return;
+            }
+            expect(product.slug).toBe('curvy-monitor');
+        });
+
         it(
             'throws if neither id nor slug provided',
             assertThrowsWithMessage(async () => {

+ 8 - 7
packages/core/src/service/services/collection.service.ts

@@ -138,18 +138,19 @@ export class CollectionService implements OnModuleInit {
     }
 
     async findOneBySlug(ctx: RequestContext, slug: string): Promise<Translated<Collection> | undefined> {
-        const translation = await this.connection.getRepository(ctx, CollectionTranslation).findOne({
+        const translations = await this.connection.getRepository(ctx, CollectionTranslation).find({
             relations: ['base'],
-            where: {
-                languageCode: ctx.languageCode,
-                slug,
-            },
+            where: { slug },
         });
 
-        if (!translation) {
+        if (!translations?.length) {
             return;
         }
-        return this.findOne(ctx, translation.base.id);
+        const bestMatch =
+            translations.find(t => t.languageCode === ctx.languageCode) ??
+            translations.find(t => t.languageCode === ctx.channel.defaultLanguageCode) ??
+            translations[0];
+        return this.findOne(ctx, bestMatch.base.id);
     }
 
     getAvailableFilters(ctx: RequestContext): ConfigurableOperationDefinition[] {

+ 8 - 7
packages/core/src/service/services/product.service.ts

@@ -133,17 +133,18 @@ export class ProductService {
     }
 
     async findOneBySlug(ctx: RequestContext, slug: string): Promise<Translated<Product> | undefined> {
-        const translation = await this.connection.getRepository(ctx, ProductTranslation).findOne({
+        const translations = await this.connection.getRepository(ctx, ProductTranslation).find({
             relations: ['base'],
-            where: {
-                languageCode: ctx.languageCode,
-                slug,
-            },
+            where: { slug },
         });
-        if (!translation) {
+        if (!translations?.length) {
             return;
         }
-        return this.findOne(ctx, translation.base.id);
+        const bestMatch =
+            translations.find(t => t.languageCode === ctx.languageCode) ??
+            translations.find(t => t.languageCode === ctx.channel.defaultLanguageCode) ??
+            translations[0];
+        return this.findOne(ctx, bestMatch.base.id);
     }
 
     async create(ctx: RequestContext, input: CreateProductInput): Promise<Translated<Product>> {