Model.match()#
#Model.match(multiple: bool = False, dynamic: bool = True) -> Context
Matches objects to one or more subqueries.
Similar to a Python match
or a SQL CASE
statement.
Must be used in a rule or query context.
Parameters#
Name | Type | Description |
---|---|---|
multiple | bool | Whether or not the context matches multiple queries. If True , objects match all subqueries that filter them. If False , objects match only the first. |
dynamic | bool | Whether or not the context is dynamic. Dynamic queries support Python control flow as macros. See Context for more information. |
Returns#
A Context
object.
Example#
Model.match()
is a
context manager
and should be called in a with
statement.
It must be called from within a rule or query context:
#import relationalai as rai
model = rai.Model("students")
Student = model.Type("Student")
with model.rule():
Student.add(name="Fred", grade=87)
Student.add(name="Johnny", grade=65)
Student.add(name="Mary", grade=98)
with model.rule():
student = Student()
with model.match():
# Match students to subqueries based on their grade.
with student.grade >= 90:
student.set(letter_grade="A")
with student.grade >= 80:
student.set(letter_grade="B")
with student.grade >= 70:
student.set(letter_grade="C")
# Default case when no other conditions are met.
with model.case():
student.set(letter_grade="F")
# Which students got a B?
with model.query() as select:
student = Student(letter_grade="B")
response = select(student.name, student.grade, student.letter_grade)
print(response.results)
# Output:
# name grade letter_grade
# 0 Fred 87 B
You can think of consecutive with
statements inside of a Model.match()
context as branches of an if
-else
statement.
In the example above, the letter_grade
property of student
objects is set based on their grade
property.
Only the first matching with
statement is applied to each object.
To match multiple subqueries, set the multiple
parameter to True
:
#with model.rule():
student = Student()
with model.match(multiple=True):
with student.grade >= 90:
student.set(letter_grade="A")
with student.grade >= 80:
student.set(letter_grade="B")
with student.grade >= 70:
student.set(letter_grade="C")
with model.case():
student.set(letter_grade="F")
# Which students got a B?
with model.query() as select:
student = Student(letter_grade="B")
response = select(student.name, student.grade, student.letter_grade)
print(response.results)
# Output:
# name grade letter_grade
# 0 Fred 87 B
# 1 Mary 98 B
Mary has .letter_grade
set to "B"
.
She also has .letter_grade
set to "A"
and "C"
because her grade meets the conditions
in the first three of the four with
statements.
Set dynamic
to True
to use Python control flow inside of the .match()
context.
This allows you to leverage Python as a macro language to generate subqueries dynamically:
#with model.rule():
student = Student()
with model.match(dynamic=True):
for grade, letter in [(90, "A"), (80, "B"), (70, "C")]:
with student.grade >= grade:
student.set(letter_grade=letter)
with model.case():
student.set(letter_grade="F")
.match().__enter__()
returns an optional ContextSelect
object
that may be used to group objects matched by the context for further manipulation.
For instance, the following example calculates student letter grades in a query,
not a rule, and filters students who got a B:
## Which students got a B?
# This time, we're calculating the letter grade in a query, not a rule.
with model.query() as select:
student = Student()
with model.match(dynamic=True) as matched:
for grade, letter in [(90, "A"), (80, "B"), (70, "C")]:
with student.grade >= grade:
matched.add(student, letter_grade=letter)
with model.case():
matched.add(student, letter_grade="F")
# Filter students who got a B.
matched.letter_grade == "B"
response = select(students.name, students.grade, students.letter_grade)
print(response.results)
# Output:
# name grade v
# 0 Fred 87 B
You can only use with
statements directly under a Model.match()
block:
## INCORRECT
with model.rule():
with model.match():
student = Student() # Raises an error
with student.grade >= 90:
student.set(letter_grade="A")
# ...
# CORRECT
with model.rule():
student = Student()
with model.match():
with student.grade >= 90:
student.set(letter_grade="A")
# ...
# - OR -
with model.rule():
with model.match():
with model.case():
student = Student() # OK because it's nested under a `with` statement
student.grade >= 90
student.set(letter_grade="A")
# ...