Skip to main content

A query string parsing library for REST server queries

Project description

rest-filter

rest-filter aims to ba a light weight fast parser written in pure Python, meant for use in REST API servers. It was inspired by the OData standard, but this query is a bit simpler and less feature rich.

Goals

  • An easily extendable querying syntax
  • Be able to query any data source by writing a simple translator
  • Usable in any Python REST framework

Installation

pip install rest-filter

Example usage

Here is an example of the most basic usage

from rest_filter.encoder.common import encoder
from rest_filter.translator import get_mongo_translator

# The raw input expression
expression = r"((age gt 20) and (age ge 10))"

# Generate the encoded expression
encoded_expression = encoder.encode_expression(expression)
print(encoded_expression)

# Translate into a mongo query
mongo_query = get_mongo_translator().translate(encoded_expression)
print(mongo_query)

The resulting encoded expression looks like this:

And(operands=[
    GraterThan(field=Field(name='age'), value=20.0), 
    GraterEqualsTo(field=Field(name='age'), value=10.0)
])

And the resulting mongo query looks like this:

{
    '$and': [
        {'age': {'$gt': 20.0}}, 
        {'age': {'$ge': 10.0}}
    ]
}

This uses the default pre built expression encoding elements & the pre build translation elements. you can add additional elements like this:

import re

from rest_filter.encoder.common import encoder, And
from rest_filter.encoder import BinaryOperation
from rest_filter.translator import get_mongo_translator


mongo_translator = get_mongo_translator()
encoder.register_binary_logical_operator('&&')(And)


@encoder.register_ratio('contains')
class Contains(BinaryOperation):
    pass


@mongo_translator.register_binary_operation_translator(Contains)
def translate_equals(operation: Contains):
    return {
        operation.field.name: f'/{re.escape(operation.value)}/'
    }


# The raw input expression
expression = r"((age gt 20) && (name contains 'a string with special **^^ chars'))"

# Generate the encoded expression
encoded_expression = encoder.encode_expression(expression)
print(encoded_expression)

# Translate into a mongo query
mongo_query = get_mongo_translator().translate(encoded_expression)
print(mongo_query)

If you want you can forgo the pre loaded encoder & translator objects and create ones of your one with completely custom elements:

from rest_filter.encoder import Encoder
from rest_filter.encoder import BooleanOperation, BinaryOperation

from rest_filter.translator import get_mongo_translator, Translator

encoder = Encoder()


# Register encoders
@encoder.register_binary_logical_operator('and')
class And(BooleanOperation):
    pass


@encoder.register_ratio('eq')
class Equals(BinaryOperation):
    pass

@encoder.register_type(r'-?\d+')
def number(text: str):
    return int(text)

mongo_translator = get_mongo_translator()

# Register translators
@mongo_translator.register_boolean_operation_translator(And)
def translate_and(operation: And, translator: Translator):
    return {
        '$and': [
            translator.translate(operand) for operand in operation.operands
        ]
    }


@mongo_translator.register_binary_operation_translator(Equals)
def translate_equals(operation: Equals):
    return {
        operation.field.name: {
            '$eq': operation.value
        }
    }

expression = "((age eq 3) and (height eq 18))"

# Generate the encoded expression
encoded_expression = encoder.encode_expression(expression)
print(encoded_expression)

# Translate into a mongo query
mongo_query = mongo_translator.translate(encoded_expression)
print(mongo_query)

Limitations

  • Expressions can only be parentheses complete (for now). For example, these expressions are not allowed:
    • age gt 10 and name eq 'eric' and city eq 'tlv'
    • (age gt 10 and name eq 'eric' and city eq 'tlv')
    • (age gt 10) and (name eq 'eric') and (city eq 'tlv')
      But this expression is valid:
    • (((age gt 10) and (name eq 'eric')) and (city eq 'tlv'))
  • You cannot register new value types (for now), you must use the prebuilt boolean, string or number values

Encoder Translator design

This utility is separated into two parts: Encoder & Translator

Encoder

The encoder is responsible for parsing the input string into a structured expression object, that can be easily read & parsed by code

The encoder can encodes grammar elements that are registered to it. each registered grammar is a ratio between a field & a value, or a logical operation between two logical values or expressions

Translator

The translator translates the generic expression format given from the encoder into a target language.
There is a basic mongo translator built into this package (more yet to come), but you can easily write a translator of your own.

Contributors

  • Sagiv Oulu

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rest-filter-1.0.2.tar.gz (9.2 kB view hashes)

Uploaded Source

Built Distribution

rest_filter-1.0.2-py3-none-any.whl (10.6 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page