SCIM2 Filter Parser
scim2-filter-parser (SFP) is a customizable Python library designed to parse and transpile SCIM 2.0 filter queries. It breaks down SCIM queries into tokens, constructs an Abstract Syntax Tree (AST), and can then convert this AST into other query languages, such as SQL WHERE clauses or Django Q objects. The library is currently at version 0.7.0 and is actively maintained.
Warnings
- breaking When using the raw SQL output (e.g., from the command-line tool or if you concatenate `sql_where_clause` directly without `query_parameters`), there is a significant risk of SQL injection. The library provides `params` separately for safe parameterized query execution.
- gotcha The `attribute_map` is highly specific to your database schema and must be carefully configured. Incorrect mappings will lead to invalid SQL queries or unexpected filtering behavior.
- gotcha By default, `SQLQuery` uses `%s` as the placeholder for query parameters, which is common in PostgreSQL. If your database (e.g., SQLite, MySQL with `?` or named parameters) requires a different placeholder, you must subclass `SQLQuery` and override the `placeholder` class variable.
- gotcha The library primarily demonstrates SQL output. If you intend to use it with Django models, you need to import and use `scim2_filter_parser.transpilers.django_q_object.get_query` to generate Django Q objects, which has a different API.
Install
-
pip install scim2-filter-parser
Imports
- SQLQuery
from scim2_filter_parser.queries import SQLQuery
- get_query
from scim2_filter_parser.transpilers.django_q_object import get_query
Quickstart
from scim2_filter_parser.queries import SQLQuery
# Define a mapping from SCIM attributes to your database column names.
# This is crucial for the parser to generate correct SQL.
attribute_map = {
'userName': 'users.username',
'emails.value': 'emails.email_address',
'emails.type': 'emails.type',
'name.familyName': 'users.last_name',
'name.givenName': 'users.first_name'
}
# Define necessary SQL JOINs if your SCIM attributes span multiple tables.
joins = [
'LEFT JOIN emails ON emails.user_id = users.id'
]
scim_filter = 'userName eq "bjensen" or emails[type eq "work" and value co "@example.com"]'
try:
# Instantiate the SQLQuery parser
query_builder = SQLQuery(
scim_filter=scim_filter,
attribute_map=attribute_map,
joins=joins
)
# Get the generated SQL WHERE clause and parameters
sql_where_clause = query_builder.sql
query_parameters = query_builder.params
print(f"Generated SQL WHERE clause: {sql_where_clause}")
print(f"Query parameters: {query_parameters}")
# Example of how you might use it (DO NOT run this directly without proper DB connection and sanitization):
# import sqlite3
# conn = sqlite3.connect(':memory:')
# cursor = conn.cursor()
# # For demonstration, imagine 'users' and 'emails' tables exist
# # cursor.execute(f"SELECT * FROM users {joins[0]} WHERE {sql_where_clause}", query_parameters)
# # results = cursor.fetchall()
# # print(f"Query results: {results}")
except Exception as e:
print(f"An error occurred: {e}")