Skip to content

Commit

Permalink
feat(street-service): add low level request optimization for multi la…
Browse files Browse the repository at this point in the history
…nguage search
  • Loading branch information
derrabauke committed Jul 17, 2024
1 parent 5cf1415 commit f1a120b
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 38 deletions.
51 changes: 51 additions & 0 deletions addon/services/languages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import Service, { inject as service } from "@ember/service";
import { languageOptions } from "ember-ebau-gwr/models/options";

export default class LanguagesService extends Service {
@service config;

languages = {
AG: ["de"],
AR: ["de"],
AI: ["de"],
BL: ["de"],
BS: ["de"],
BE: ["de", "fr"],
FR: ["de", "fr"],
GE: ["de", "fr"],
GL: ["de"],
GR: ["de", "rm", "it"],
JU: ["fr"],
LU: ["de"],
NE: ["fr"],
NW: ["de"],
OW: ["de"],
SH: ["de"],
SZ: ["de"],
SO: ["de"],
SG: ["de"],
TI: ["it"],
TG: ["de"],
UR: ["de"],
VD: ["fr"],
VS: ["de", "fr"],
ZG: ["de"],
ZH: ["de"],
};

get availableLanguages() {
return this.config.cantonAbbreviation
? this.languages[this.config.cantonAbbreviation]
: ["de", "rm", "fr", "it"];
}

codeToLanguage(code) {
return Object.entries(languageOptions).find(
([, value]) => value === code,
)[0];
}

languageToCode(languageAbbreviation) {
return languageOptions[languageAbbreviation];
}
}
110 changes: 72 additions & 38 deletions addon/services/street.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import { languageOptions } from "ember-ebau-gwr/models/options";
import { inject as service } from "@ember/service";
import { task } from "ember-concurrency";
import Street, { StreetList } from "ember-ebau-gwr/models/street";

import GWRService from "./gwr";

export default class StreetService extends GWRService {
@service languages;

cacheKey = "ESID";
cacheClass = Street;
cachedLanguageOverride;
cachedLanguageOverrides;

constructor(...args) {
super(...args);

this.resetCachedLanguages();
}

async get(ESID) {
if (!ESID) {
Expand All @@ -18,54 +27,79 @@ export default class StreetService extends GWRService {
return this.cache(street);
}

get language() {
return languageOptions[this.intl.primaryLocale?.split("-")?.[0]];
get primaryLanguage() {
return this.intl.primaryLocale?.split("-")?.[0];
}

async search(query = {}) {
if (this.cachedLanguageOverride) {
query.language = this.cachedLanguageOverride;
}
get language() {
return this.languages.languageToCode(this.primaryLanguage);
}

const searchResult = await super.search(query, query.EGID, {
@task
*_search(query) {
return yield super.search(query, query.EGID, {
xmlMethod: "getStreet",
urlPath: "streets",
listModel: StreetList,
listKey: "street",
searchKey: "streetWithoutStreetGeometryType",
});
}

if (!searchResult) {
let results = [];

for (const [lang, code] of Object.entries(languageOptions)) {
query.language = code;

results.push({
lang: [lang, code],
result: super.search(query, query.EGID, {
xmlMethod: "getStreet",
urlPath: "streets",
listModel: StreetList,
listKey: "street",
searchKey: "streetWithoutStreetGeometryType",
}),
});
}

results = await Promise.allSettled(
results.map(async ({ lang, result }) => {
return { lang, result: await result };
resetCachedLanguages() {
this.cachedLanguageOverrides = new Set([]);
}

async searchMultiple(query, useCachedLanguagesOnly) {
let results = [];

for (const lang of useCachedLanguagesOnly
? this.cachedLanguageOverrides
: this.languages.availableLanguages) {
const code = this.languages.languageToCode(lang);
query.language = code;

results.push({
lang: [lang, code],
result: this._search.perform(query, query.EGID, {
xmlMethod: "getStreet",
urlPath: "streets",
listModel: StreetList,
listKey: "street",
searchKey: "streetWithoutStreetGeometryType",
}),
);
return results
.filter(({ value }) => value.result?.length)
.reduce((previous, { value: { lang, result } }) => {
this.cachedLanguageOverride = lang[1];
return previous.concat(result);
}, []);
});
}

return searchResult;
results = await Promise.allSettled(
results.map(async ({ lang, result }) => {
return { lang, result: await result };
}),
);
return results
.filter(({ value }) => value.result?.length)
.reduce((previous, { value: { lang, result } }) => {
this.cachedLanguageOverrides.add(lang[0]);
return previous.concat(result);
}, []);
}

async search(query = {}) {
const lastQueryString =
this._search.lastPerformed?.args[0]?.description?.descriptionLong.replaceAll(
"*",
"",
) || "";
const currentQueryString =
query.description?.descriptionLong?.replaceAll("*", "") || "";

// In order to avoid unnecessary requests while typing (and thereby "refining"
// the search), we continue searching only with the languages for which we
// previously received results.
if (lastQueryString && currentQueryString.includes(lastQueryString)) {
return this.searchMultiple(query, true);
}
this.resetCachedLanguages();
return this.searchMultiple(query);
}
}
37 changes: 37 additions & 0 deletions tests/unit/services/languages-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { setupTest } from "dummy/tests/helpers";
import { module, test } from "qunit";

module("Unit | Service | languages", function (hooks) {
setupTest(hooks);

test("available languages for a given canton", function (assert) {
const configService = this.owner.lookup("service:config");
const languagesService = this.owner.lookup("service:languages");

configService.cantonAbbreviation = "GR";

assert.deepEqual(languagesService.availableLanguages, ["de", "rm", "it"]);

configService.cantonAbbreviation = "BE";

assert.deepEqual(languagesService.availableLanguages, ["de", "fr"]);
});

test("transforms language abbrevation to gwr API language code", function (assert) {
const service = this.owner.lookup("service:languages");

assert.strictEqual(service.languageToCode("de"), 9901);
assert.strictEqual(service.languageToCode("rm"), 9902);
assert.strictEqual(service.languageToCode("fr"), 9903);
assert.strictEqual(service.languageToCode("it"), 9904);
});

test("transforms gwr API language code to language abbrevation", function (assert) {
const service = this.owner.lookup("service:languages");

assert.strictEqual(service.codeToLanguage(9901), "de");
assert.strictEqual(service.codeToLanguage(9902), "rm");
assert.strictEqual(service.codeToLanguage(9903), "fr");
assert.strictEqual(service.codeToLanguage(9904), "it");
});
});

0 comments on commit f1a120b

Please sign in to comment.