u
This commit is contained in:
@@ -16,6 +16,9 @@ import articleIndexAutomat from './articleIndexAutomat';
|
|||||||
import categoryAutomat from './categoryAutomat';
|
import categoryAutomat from './categoryAutomat';
|
||||||
import { parseFilter } from '../components/article/searchFormat';
|
import { parseFilter } from '../components/article/searchFormat';
|
||||||
|
|
||||||
|
// #region Types & Initial State
|
||||||
|
// MARK: typedefs, initial state, and FlexSearch instance variables
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} ArticleSearchResult
|
* @typedef {Object} ArticleSearchResult
|
||||||
* @property {Record<string,object>} categoryFacets Facet counts per category id.
|
* @property {Record<string,object>} categoryFacets Facet counts per category id.
|
||||||
@@ -67,7 +70,12 @@ const { Document, Charset } = FlexSearch;
|
|||||||
let flexDocument = null;
|
let flexDocument = null;
|
||||||
let lastIndexedArticles = null;
|
let lastIndexedArticles = null;
|
||||||
let articleByInternalId = new Map();
|
let articleByInternalId = new Map();
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Helpers
|
||||||
|
|
||||||
|
// #region getOrCreateFlexIndex
|
||||||
|
// MARK: constructs or retrieves FlexSearch document index
|
||||||
/**
|
/**
|
||||||
* Lazily constructs and maintains the FlexSearch Document index for the given articles array.
|
* Lazily constructs and maintains the FlexSearch Document index for the given articles array.
|
||||||
*
|
*
|
||||||
@@ -120,7 +128,10 @@ function getOrCreateFlexIndex(articles) {
|
|||||||
articleByInternalId = byId;
|
articleByInternalId = byId;
|
||||||
return { doc, byId };
|
return { doc, byId };
|
||||||
}
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region queryFlexSearch
|
||||||
|
// MARK: queries FlexSearch document index
|
||||||
/**
|
/**
|
||||||
* Searches the FlexSearch index with the query string.
|
* Searches the FlexSearch index with the query string.
|
||||||
*
|
*
|
||||||
@@ -158,7 +169,10 @@ function queryFlexSearch(query, articles) {
|
|||||||
}
|
}
|
||||||
return matchesList;
|
return matchesList;
|
||||||
}
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region getArticleRelevanceScore
|
||||||
|
// MARK: calculates search relevance score for an article
|
||||||
/**
|
/**
|
||||||
* Calculates a search relevance score for an article record against a query.
|
* Calculates a search relevance score for an article record against a query.
|
||||||
*
|
*
|
||||||
@@ -200,7 +214,10 @@ export function getArticleRelevanceScore(article, query) {
|
|||||||
|
|
||||||
return 10;
|
return 10;
|
||||||
}
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region sortArticlesByRelevance
|
||||||
|
// MARK: sorts articles by relevance score, name, and sku
|
||||||
/**
|
/**
|
||||||
* Sorts articles by relevance to the query, breaking ties alphabetically by name and SKU.
|
* Sorts articles by relevance to the query, breaking ties alphabetically by name and SKU.
|
||||||
*
|
*
|
||||||
@@ -225,7 +242,10 @@ export function sortArticlesByRelevance(articles, query) {
|
|||||||
return String(a.sku ?? '').localeCompare(String(b.sku ?? ''), 'de');
|
return String(a.sku ?? '').localeCompare(String(b.sku ?? ''), 'de');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region searchArticlesIndex
|
||||||
|
// MARK: calls articleIndexAutomat.actions.ensureLoaded
|
||||||
/**
|
/**
|
||||||
* Synchronously searches the article index using the search automat token matching and relevance order.
|
* Synchronously searches the article index using the search automat token matching and relevance order.
|
||||||
*
|
*
|
||||||
@@ -308,7 +328,10 @@ export function searchArticlesIndex(query, options = {}) {
|
|||||||
|
|
||||||
return recordset;
|
return recordset;
|
||||||
}
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region isRootCategory
|
||||||
|
// MARK: checks if category id or name represents the root category
|
||||||
/**
|
/**
|
||||||
* Determines whether a category ID or name represents the root category.
|
* Determines whether a category ID or name represents the root category.
|
||||||
*
|
*
|
||||||
@@ -326,7 +349,10 @@ function isRootCategory(id, rootCategoryId, metaName) {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region getCategoryAndDescendantIds
|
||||||
|
// MARK: recursively collects category id and descendant category ids
|
||||||
/**
|
/**
|
||||||
* Recursively collects categoryId and all its descendant category IDs.
|
* Recursively collects categoryId and all its descendant category IDs.
|
||||||
*
|
*
|
||||||
@@ -404,7 +430,10 @@ export function getCategoryAndDescendantIds(selectedCategories, categoriesMap, f
|
|||||||
|
|
||||||
return allIds;
|
return allIds;
|
||||||
}
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region matchesCategory
|
||||||
|
// MARK: checks whether article matches expanded category ids
|
||||||
/**
|
/**
|
||||||
* Checks whether an article belongs to at least one of the target categories.
|
* Checks whether an article belongs to at least one of the target categories.
|
||||||
*
|
*
|
||||||
@@ -418,7 +447,10 @@ function matchesCategory(row, expandedCategoryIds) {
|
|||||||
const rowCats = String(row.categories).split(',').map((s) => s.trim());
|
const rowCats = String(row.categories).split(',').map((s) => s.trim());
|
||||||
return rowCats.some((catId) => expandedCategoryIds.has(String(catId)));
|
return rowCats.some((catId) => expandedCategoryIds.has(String(catId)));
|
||||||
}
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region buildCategoryFacets
|
||||||
|
// MARK: computes category facet counts from matched articles
|
||||||
/**
|
/**
|
||||||
* Computes facet counts for each category represented in matched articles.
|
* Computes facet counts for each category represented in matched articles.
|
||||||
*
|
*
|
||||||
@@ -463,8 +495,14 @@ function buildCategoryFacets(matchedArticles) {
|
|||||||
|
|
||||||
return facets;
|
return facets;
|
||||||
}
|
}
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Actions
|
||||||
const actions = {
|
const actions = {
|
||||||
|
// #region runSearch
|
||||||
|
// MARK: runs in-memory search and derivation synchronously
|
||||||
/**
|
/**
|
||||||
* Executes in-memory search and derivation synchronously.
|
* Executes in-memory search and derivation synchronously.
|
||||||
*
|
*
|
||||||
@@ -537,7 +575,10 @@ const actions = {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region search
|
||||||
|
// MARK: calls articleIndexAutomat.actions.ensureLoaded
|
||||||
/**
|
/**
|
||||||
* Runs a client-side search over the article index with pagination.
|
* Runs a client-side search over the article index with pagination.
|
||||||
*
|
*
|
||||||
@@ -562,7 +603,10 @@ const actions = {
|
|||||||
|
|
||||||
return actions.runSearch(params);
|
return actions.runSearch(params);
|
||||||
},
|
},
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region setPageSize
|
||||||
|
// MARK: updates page size and re-derives result set
|
||||||
/**
|
/**
|
||||||
* Updates the page size and re-derives the result set.
|
* Updates the page size and re-derives the result set.
|
||||||
*
|
*
|
||||||
@@ -572,7 +616,10 @@ const actions = {
|
|||||||
setPageSize(pageSize) {
|
setPageSize(pageSize) {
|
||||||
return actions.runSearch({ pageSize });
|
return actions.runSearch({ pageSize });
|
||||||
},
|
},
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region setPage
|
||||||
|
// MARK: sets 1-based page number and re-derives result set
|
||||||
/**
|
/**
|
||||||
* Sets page number (1-based) and re-derives the result set.
|
* Sets page number (1-based) and re-derives the result set.
|
||||||
*
|
*
|
||||||
@@ -584,7 +631,10 @@ const actions = {
|
|||||||
const offset = Math.max(0, (page - 1) * safeSize);
|
const offset = Math.max(0, (page - 1) * safeSize);
|
||||||
return actions.runSearch({ offset });
|
return actions.runSearch({ offset });
|
||||||
},
|
},
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region setOffset
|
||||||
|
// MARK: sets 0-based offset and re-derives result set
|
||||||
/**
|
/**
|
||||||
* Sets 0-based offset and re-derives the result set.
|
* Sets 0-based offset and re-derives the result set.
|
||||||
*
|
*
|
||||||
@@ -594,7 +644,10 @@ const actions = {
|
|||||||
setOffset(offset) {
|
setOffset(offset) {
|
||||||
return actions.runSearch({ offset });
|
return actions.runSearch({ offset });
|
||||||
},
|
},
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region reset
|
||||||
|
// MARK: resets search state and clears FlexSearch index
|
||||||
/** Reset the search state and clear FlexSearch index. */
|
/** Reset the search state and clear FlexSearch index. */
|
||||||
reset() {
|
reset() {
|
||||||
flexDocument = null;
|
flexDocument = null;
|
||||||
@@ -602,7 +655,12 @@ const actions = {
|
|||||||
articleByInternalId = new Map();
|
articleByInternalId = new Map();
|
||||||
articleSearchAutomat.setState(initialState);
|
articleSearchAutomat.setState(initialState);
|
||||||
},
|
},
|
||||||
|
// #endregion
|
||||||
};
|
};
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Automat Instance & Subscriptions
|
||||||
|
// MARK: initializes Automat instance and subscribes to articleIndexAutomat & categoryAutomat
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Article search and pagination state for the `/artikel` overview page.
|
* Article search and pagination state for the `/artikel` overview page.
|
||||||
@@ -625,6 +683,10 @@ categoryAutomat.subscribe((catState) => {
|
|||||||
actions.runSearch();
|
actions.runSearch();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// #endregion
|
||||||
|
|
||||||
|
// #region Selectors & Exports
|
||||||
|
// MARK: selectSearchResult selector and default export
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the latest search result.
|
* Selects the latest search result.
|
||||||
@@ -637,3 +699,4 @@ export function selectSearchResult(state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default articleSearchAutomat;
|
export default articleSearchAutomat;
|
||||||
|
// #endregion
|
||||||
|
|||||||
Reference in New Issue
Block a user