Query logic
Combine conditions with AND/OR logic. Conditions on different attributes are combined with AND, conditions on the same attribute with OR. For any other combination, use addGroup with an explicit groupType. Build complex boolean expressions for advanced filtering with faceted search patterns.
Syntax
list.catalog.query.addGroup({
groupKey?: string,
groupType?: 'and' | 'or',
queries: Array<Condition | Group>
})Parameters
groupKeystringOptional- Names the group. Adding a group with an existing groupKey extends it; setGroup() replaces it; removeGroup(groupKey) removes it. The keyed group is found at any nesting depth (a top-level match first) and changed where it is. Removing a group that leaves its wrapper group empty removes the wrapper too (and every wrapper above it that becomes empty). addGroup() always adds a group without a key as a new group; setGroup() without a key replaces the first keyless group.
groupType'and' | 'or'Optional- Logic within the group. Set it explicitly: a group without groupType is stored as 'or', whether it is new or replaces an existing group with setGroup() (addGroup() without groupType extending a keyed group keeps that group's groupType), while a nested group inside queries without groupType is evaluated as 'and'.
queriesArray<Condition | Group>Required- Conditions or nested groups in this group
Return type
addGroup(), setGroup() and addCondition() return the updated query (DcuplGlobalQueryOptions). Use current() to inspect it, clear() to reset:
// Shape of the returned query, e.g. after addCondition() on category and brand
type DcuplGlobalQueryOptions<T> = {
modelKey: string;
groupKey: 'root';
groupType: 'and'; // top-level groups are ANDed
queries: Array<DcuplQuery | DcuplQueryGroup>; // here: [{ groupKey: 'category', groupType: 'or', queries: [...] },
// { groupKey: 'brand', groupType: 'or', queries: [...] }]
};Usage notes
- Default: addCondition() puts each condition into a group named after its attribute, so different attributes use AND and the same attribute uses OR
- Use addGroup with groupType: 'or' for OR across different attributes
- Use addGroup with groupType: 'and' for ranges on one attribute
- Different groups are ANDed together at the top level
- Use setCondition() for single-select dropdowns (replaces the conditions on that attribute)
- Use addCondition() for multi-select checkboxes (accumulates, OR within the attribute)
- removeCondition() removes one condition (pass the full condition); removeGroup(groupKey) removes a whole group
- clear() removes all conditions
Related methods
catalog.query.addGroup()— Add or extend a group of conditionscatalog.query.setGroup()— Replace a group by its groupKeycatalog.query.current()— Get current query structurecatalog.query.isEmpty()— Check if any conditions existcatalog.query.clear()— Remove all conditionscatalog.query.removeCondition()— Remove specific condition
Examples
Default AND logic
Multiple conditions on different attributes use AND by default.
const productList = dcupl.lists.create({ modelKey: 'Product' });
// These conditions are ANDed automatically
productList.catalog.query.addCondition({
attribute: 'category',
operator: 'eq',
value: 'Electronics',
});
productList.catalog.query.addCondition({
attribute: 'inStock',
operator: 'isTruthy',
value: true,
});
// Result: Electronics AND in stock
const results = productList.catalog.query.items();OR logic with same attribute
Multiple values for same attribute create OR logic by default.
const productList = dcupl.lists.create({ modelKey: 'Product' });
// Same attribute = OR logic
productList.catalog.query.addCondition({
attribute: 'category',
operator: 'eq',
value: 'Electronics',
});
productList.catalog.query.addCondition({
attribute: 'category',
operator: 'eq',
value: 'Computers',
});
// Result: Electronics OR Computers
const results = productList.catalog.query.items();Explicit OR group
Use addGroup with groupType: "or" for OR logic across different attributes.
const productList = dcupl.lists.create({ modelKey: 'Product' });
// Conditions on different attributes are combined with AND,
// so put them in one group with groupType 'or'
productList.catalog.query.addGroup({
groupKey: 'special',
groupType: 'or',
queries: [
{ attribute: 'featured', operator: 'eq', value: true },
{ attribute: 'onSale', operator: 'eq', value: true },
],
});
// Result: featured OR on sale
const specialProducts = productList.catalog.query.items();Multiple OR groups (AND between groups)
Combine multiple OR groups with AND logic between them.
const productList = dcupl.lists.create({ modelKey: 'Product' });
// Category group (OR): Electronics OR Computers
productList.catalog.query.addGroup({
groupKey: 'category-group',
groupType: 'or',
queries: [
{ attribute: 'category', operator: 'eq', value: 'Electronics' },
{ attribute: 'category', operator: 'eq', value: 'Computers' },
],
});
// Brand group (OR): Apple OR Samsung
productList.catalog.query.addGroup({
groupKey: 'brand-group',
groupType: 'or',
queries: [
{ attribute: 'brand', operator: 'eq', value: 'Apple' },
{ attribute: 'brand', operator: 'eq', value: 'Samsung' },
],
});
// Result: (Electronics OR Computers) AND (Apple OR Samsung)
const results = productList.catalog.query.items();Faceted search pattern
Build a typical e-commerce filter with multiple facets.
const productList = dcupl.lists.create({ modelKey: 'Product' });
function applyFacetedFilters(filters: {
categories?: string[];
brands?: string[];
priceMin?: number;
priceMax?: number;
}) {
const query = productList.catalog.query;
query.clear();
// Categories (OR within group). Key the group by its attribute:
// fn.facets({ attribute: 'category' }) leaves the group with that key out when counting
if (filters.categories?.length) {
query.addGroup({
groupKey: 'category',
groupType: 'or',
queries: filters.categories.map((cat) => ({
attribute: 'category',
operator: 'eq' as const,
value: cat,
})),
});
}
// Brands: the 'in' operator matches any of the listed values
if (filters.brands?.length) {
query.addCondition({ attribute: 'brand', operator: 'in', value: filters.brands });
}
// Price range (AND within group)
const price = [];
if (filters.priceMin !== undefined) {
price.push({ attribute: 'price', operator: 'gte' as const, value: filters.priceMin });
}
if (filters.priceMax !== undefined) {
price.push({ attribute: 'price', operator: 'lte' as const, value: filters.priceMax });
}
if (price.length) {
query.addGroup({ groupKey: 'price', groupType: 'and', queries: price });
}
// Result: (cat1 OR cat2) AND (brand1 OR brand2) AND (price range)
return query.items();
}Replace vs. add
Control whether a new condition replaces or adds to the existing ones on the same attribute.
const productList = dcupl.lists.create({ modelKey: 'Product' });
// addCondition adds: Electronics
productList.catalog.query.addCondition({
attribute: 'category',
operator: 'eq',
value: 'Electronics',
});
// setCondition replaces the conditions on 'category'
productList.catalog.query.setCondition({
attribute: 'category',
operator: 'eq',
value: 'Books',
});
// Now only Books products match
// (addCondition here would give Electronics OR Books)
const results = productList.catalog.query.items();Remove specific condition
Remove a specific condition while keeping others.
const productList = dcupl.lists.create({ modelKey: 'Product' });
// Add multiple category filters
productList.catalog.query.addCondition({
attribute: 'category',
operator: 'eq',
value: 'Electronics',
});
productList.catalog.query.addCondition({
attribute: 'category',
operator: 'eq',
value: 'Books',
});
// Remove just the Electronics filter (pass the full condition)
productList.catalog.query.removeCondition({
attribute: 'category',
operator: 'eq',
value: 'Electronics',
});
// Now only Books products match
const results = productList.catalog.query.items();
// Remove all conditions on 'category'
productList.catalog.query.removeGroup('category');Query state inspection
Check current query state and reset.
const productList = dcupl.lists.create({ modelKey: 'Product' });
productList.catalog.query.addCondition({
attribute: 'category',
operator: 'eq',
value: 'Electronics',
});
// Check current query state
const currentQuery = productList.catalog.query.current();
console.log('Current query:', currentQuery);
// Check if query has any conditions
const isEmpty = productList.catalog.query.isEmpty();
console.log('Is empty:', isEmpty); // false
// Check for a specific group (addCondition groups are keyed by attribute)
const hasCategory = productList.catalog.query.has({ groupKey: 'category' });
// Clear all conditions
productList.catalog.query.clear();
// Now returns all products
const allProducts = productList.catalog.query.items();Conditional UI based on query state
Use isEmpty() and has() to drive UI decisions.
const productList = dcupl.lists.create({ modelKey: 'Product' });
// Check if query has any conditions
if (productList.catalog.query.isEmpty()) {
// Show all products view
showAllProductsMessage();
}
// Check if a specific filter is active
if (productList.catalog.query.has({ groupKey: 'category' })) {
// Show reset button for category filter
showCategoryResetButton();
}
// Combine with faceted search
function updateFilterUI() {
const query = productList.catalog.query;
// Show "clear all" only when filters are active
clearAllButton.hidden = query.isEmpty();
// Show individual reset buttons per filter
categoryReset.hidden = !query.has({ groupKey: 'category' });
brandReset.hidden = !query.has({ groupKey: 'brand' });
priceReset.hidden = !query.has({ groupKey: 'price' });
}// Faceted search: (category1 OR category2) AND (brand1)
const list = dcupl.lists.create({ modelKey: 'Article' });
// Conditions on the same attribute are combined with OR
list.catalog.query.addCondition([
{ attribute: 'category', operator: 'eq', value: 'Running' },
{ attribute: 'category', operator: 'eq', value: 'Training' },
]);
// Conditions on different attributes are combined with AND
list.catalog.query.addCondition({
attribute: 'brand',
operator: 'eq',
value: 'Nike',
});
const results = list.catalog.query.items();[]