The @feedmepos/custom-attributes
package provides a set of tools to manage and filter custom attributes for entities such as restaurants. The main features include:
-
Filter Builder:
FmCustomAttributeFilter
A vue component that enables users to build complex filter queries based on custom attributes. -
Rule Validation Function:
validateRule
A function that evaluates MongoDB-style queries against custom attribute data to determine if they match the specified rules.
The mongoQuery
function is used to evaluate a set of rules against custom attribute data. It takes two parameters: the data to be evaluated and the rule to be applied. The function returns a boolean indicating whether the data matches the rule.
pnpm install
pnpm dev
- Create a new release and tag on GitHub (
custom-attributes-v*
Eg. custom-attributes-v0.0.0-alpha) - The package will be published to npm and github registry by @feedmepos/custom-attributes-action
- Create a new release and tag on GitHub (custom_attributes_dart@semantic-version eg. custom_attributes_dart@0.0.0-alpha)
pnpm install @feedmepos/custom-attributes
import '@feedmepos/custom-attributes/style.css';
import { FmCustomAttributeFilter } from '@feedmepos/custom-attributes';
<FmCustomAttributeFilter
:attributes="[
{ key: 'name', type: 'string', entity: 'restaurant' },
{ key: 'region', type: 'string', entity: 'restaurant' },
{ key: 'staffCount', type: 'number', entity: 'restaurant' },
{ key: 'memberCount', type: 'number', entity: 'restaurant' },
]"
:model-value="filter"
@update:model-value="(v) => (filter = v)"
/>
/**
* filter = { "logic": "AND", "rules": [ { "logic": "AND", "rules": [ { "property": "name", "operator": "$eq", "value": "123" } ] }, { "logic": "AND", "rules": [ { "property": "region", "operator": "$eq", "value": "123" } ] }, { "logic": "AND", "rules": [ { "property": "name", "operator": "$eq", "value": "123123" }, { "property": "staffCount", "operator": "$eq", "value": 123 } ] } ] }
*
* values: FdoCustomAttribute = {
* name: '123',
* region: '123',
* staffCount: 123,
* memberCount: 123123
* }
*/
const testResult = validateRule(values, filter);
const result = restaurants.filter((r) => validateRule(r.customAttribute, filter));
This package provides utilities to convert between FDO rules and MongoDB queries, and to validate data against MongoDB-style queries.
The following MongoDB operators are supported:
-
$eq
,$ne
,$gt
,$gte
,$lt
,$lte
,$in
,$nin
,$regex
-
$between
(for FDO compatibility, mapped to$gte
and$lte
)
String fields
Supported: $eq
, $ne
, $in
,$nin
, $regex
, $gt
, $gte
, $lt
, $lte
Number fields
Supported: $eq
, $ne
, $gt
, $gte
, $lt
, $lte
, $in
, $nin
Boolean fields
Supported: $eq
, $ne
, $in
, $nin
Date fields
Supported: $eq
, $ne
, $gt
, $gte
, $lt
, $lte
, $in
, $nin
Array fields
Supported:$in
, $nin
Converts an FDO rule object to a MongoDB query object.
import { FdoRuleToMongoQueryBuilder } from 'feedmepos/custom-attributes';
const fdoRule = {
property: 'age',
operator: '$gt',
value: 18,
type: 'number'
};
const mongoQuery = FdoRuleToMongoQueryBuilder.build(fdoRule);
// mongoQuery: { age: { $gt: 18 } }
Converts a MongoDB query object back to an FDO rule object.
import { MongoQueryBuilderToFdoRule } from '@feedmepos/custom-attributes';
const mongoQuery = { age: { $gt: 18 } };
const fdoRule = MongoQueryBuilderToFdoRule.build(mongoQuery);
// fdoRule: { property: 'age', operator: '$gt', value: 18, type: 'number'}
Validates a data object against a MongoDB-style query.
import { validateMongoQuery, MongoQuery } from 'feedmepos/custom-attributes';
const user: User = {
name: 'John',
age: 25,
active: true,
tags: ['user', 'admin'],
createdAt: new Date('2024-01-01'),
profile: { email: 'john@example.com', score: 85 }
};
const query: MongoQuery<User> = {
age: { $gt: 18 },
active: { $eq: true },
tags: { $in: ['admin'] },
profile: { score: { $gte: 80 } }
};
const isValid = validateMongoQuery(user, query); // true
import { MongoQuery, validateMongoQuery } from '@feedmepos/custom-attributes';
interface Profile {
email: string;
score: number;
}
interface User {
name: string;
age: number;
active: boolean;
tags: string[];
createdAt: string | Date;
profile: Profile;
}
const query: MongoQuery<User> = {
name: { $eq: 'Alice' },
age: { $gte: 18 },
profile: { score: { $gt: 80 } },
tags: { $in: ['admin'] },
createdAt: { $gte: '2024-01-01' }
};
validateMongoQuery(user, query);
// OR
validateMongoQuery(user, {
name: { $eq: 'Alice' },
age: { $gte: 18 },
profile: { score: { $gt: 80 } },
tags: { $in: ['admin'] },
createdAt: { $gte: '2024-01-01' }
});
TypeScript will show errors for:
- Invalid keys (e.g.,
'profile.score'
instead ofprofile: { score: ... }
) - Invalid operators (e.g.,
{ age: { $regex: 'foo' } }
) - Wrong value types (e.g.,
{ age: { $eq: 'Alice' } }
)
// example of invalid query
const invalidQuery: MongoQuery<User> = {
name: { $eq: 123, $regex: 456 }, // $eq expects string, $regex expects string
age: { $regex: 'foo', $gt: 'twenty' }, // $regex not allowed for number, $gt expects number
active: { $gte: true }, // $gte not allowed for boolean
tags: { $eq: 'admin', $nin: 'user' }, // $eq not allowed for array, $nin expects string[]
createdAt: { $regex: 2024, $gt: false }, // $regex expects string, $gt expects string or Date
profile: {
score: { $regex: 'foo' }, // $regex not allowed for number
notAProfileField: { $eq: 1 } // 'notAProfileField' does not exist in Profile
},
notAUserField: { $eq: 1 }, // 'notAUserField' does not exist in User
$and: [
{ name: { $eq: 'Alice' } },
{ 'profile.email': { $eq: 'foo@bar.com' } } // dot notation not allowed
]
};
- Always use object notation for nested fields (not dot notation).
-
Annotate your query as
MongoQuery<YourType>
for best type safety. -
If you use inline objects, use the generic on
validateMongoQuery
to enforce type checking.