zeroSteiner / rule-engine

A lightweight, optionally typed expression language with a custom grammar for matching arbitrary Python objects.
https://zerosteiner.github.io/rule-engine/
BSD 3-Clause "New" or "Revised" License
445 stars 54 forks source link

Does it support running rules on complex objects? #30

Closed durja closed 2 years ago

durja commented 2 years ago

Does it support running rules on complex objects? Like running rules on address.country == 'USA"?

{ "name": "test_user", "email_address": "test@gmail.com", "address": { "address_1": "high st", "address_2": "unit-4", "state": "AZ", "country": "USA" } }

Can you give an example as i see complex types are supported

zeroSteiner commented 2 years ago

Your best bet is going to be in the Getting Started page. https://zerosteiner.github.io/rule-engine/getting_started.html

What your showing should work with the default getitem resolver. You can experiment with it using the debug repl https://zerosteiner.github.io/rule-engine/debug_repl.html

I'm enjoying the holidays now and won't be able to provide a more detailed example until I'm back at my computer next week. I don't see any issue with the example you provided yourself. All the data types I see are fully supported.

zeroSteiner commented 2 years ago

Here's a larger example using the debug repl.

PYTHONPATH=$(pwd)/lib python -m rule_engine.debug_repl --edit-console
edit the 'context' and 'thing' objects as necessary
>>> thing = { "name": "test_user", "email_address": "test@gmail.com", "address": { "address_1": "high st", "address_2": "unit-4", "state": "AZ", "country": "USA" } }
>>> exit()
exiting the edit console...
rule > address.country == 'USA'
result: 
True
rule > email_address =~ '@gmail\.com$'
result: 
False
rule > email_address =~~ '@gmail\.com$'
result: 
True
rule > 'state' in address
result: 
True
rule > address['state'].as_lower == 'az'
result: 
True
rule > 

You can access MAPPING keys using the dot syntax like mapping.key, and that's mostly kept for backwards compatibility purposes. There could be name collisions with attributes though which is why I recommend you use the other syntax like mapping['key']. The default context should work just fine for this since it uses the getitem resolver.

durja commented 2 years ago

Thank you for this example. It's very helpful. In the below example, is it possible to match all users whose friends association == 'school'

`

python -m rule_engine.debug_repl --edit-console edit the 'context' and 'thing' objects as necessary thing = { "user_id": "abc123", "address": { "address_1": "123 high st", "address_2": "unit 101", "city": "jersey city", "state": "nj", "country": "usa" }, "friends": [ { "user_id": "def123", "association": "school", }, { "user_id": "ghi123", "association": "college", }, { "user_id": "jkl789", "association": "school", } ] }... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... exit() exiting the edit console... rule > address.country == 'usa' result: True rule > friends[0].association == 'school' result: True rule > friends.association == 'school' 🤔 Is there a way to do something like this and get a filtered list of friends? `

zeroSteiner commented 2 years ago

Yeah you should be able to use array comprehension (like Python's own list comprehension) to do that. https://zerosteiner.github.io/rule-engine/syntax.html#array-comprehension

Something like: [ friend for friend in friends if friend.association == 'school']

The resulting expression will be a list so you can check the length on it and do stuff like that.

durja commented 2 years ago

In my specific case, I am trying to create a generic function that can filter a list without knowing the type of objects it has. Thanks for answering my questions.

zeroSteiner commented 2 years ago

Cool so it sounds like you're all set so I'll close this out. If you have any other questions just post them here or in a new issue if you'd like.