relationalai.dsl.Producer
class Producer
Instances of the Producer
class act as variables in a rule or query context.
When the context is evaluated, all possible values for the variable are produced.
Instead of constructing Producer
instances directly, they are returned as the result of various operations.
The Producer
class is the base class for different kinds of producers, including:
Instance
, returned when you call aType
.InstanceProperty
, returned when you access a property of an object.Expression
, returned as the result of an operation on a producer, such as a mathematical or Boolean expression, or an aggregation.
Example
Section titled “Example”The key idea behind the Producer
class is that it is used to represent a variable
in a rule or query context:
import relationalai as rai
# Create a model named 'people' with Person and Adult types.model = rai.Model("people")Person = model.Type("Person")Adult = model.Type("Adult")
# Add some people to the model.with model.rule(): # Type.add() returns an Instance, which is a producer. alice = Person.add(name="Alice", age=8) bob = Person.add(name="Bob", age=36) # Instance producers have a .set() method for setting properties and # additional types on objects. bob.set(parent_of=alice)
# Create a rule that sets the Adult type on each person whose age is at least 18.with model.rule(): # Calling a type returns an Instance producer. person = Person() # person produces Person objects. # person.age returns an InstanceProperty, which is also a producer. # Comparing the age to 18 returns an Expression, yet another producer. person.age >= 18 # Filter to people who are 18 or older. person.set(Adult) # Set the adult type on the people who pass the filter.
You can think of the rule as executing once for each Person
object in the model.
Each line in the rule describes a step in a pipeline that the objects produced by person
pass through:
person
Produces aPerson
object.person.age >= 18
only lets through objects with an age of 18 or more.person.set(Adult)
sets theAdult
type on the objects that pass through.
The object for Alice never reaches the last step because her age is less than 18.
But the object for Bob does reach the last step, and the Adult
type is set on it.
Multiple producers may be mixed in the same rule or query:
# Get pairs of people where the first person is younger than the second.with model.query() as select: person1, person2 = Person(), Person() person1.age < person2.age response = select(person1.name, person2.name)
print(response.results)# Output:# name1 name2# 0 Alice Bob
Both person1
and person2
produce Person
objects.
The query is evaluated for each pair of possible values for person1
and person2
, of which there are four:
- Alice and Alice
- Alice and Bob
- Bob and Alice
- Bob and Bob
Only the pair (Alice, Bob) passes through the comparison and into select()
since Alice is 8 and Bob is 36.
Producers can be used as context managers.
This is especially useful for Expression
producers, which can be used to create a subcontext that applies to a subset of objects:
Minor = model.Type("Minor")
with model.rule(): person = Person() # If the person's age is less than 18, set the Minor type. with person.age < 18: person.set(Minor) # If the person's age is at least 18, set the Adult type. with person.age >= 18 person.set(Adult)
Thinking of the rule as a pipeline, the with
statement creates a subcontext
whose contents only apply to objects for which the Expression
is true,
but doesn’t block objects from passing through to the rest of the rule.
For example, the Alice object passes through the first with
statement and gets the Minor
type set on it since she is 8.
Her object still passes through to the second with
statement, but the Adult
type is not set on her because the expression is false.
Bob, on the other hand, passes through the first with
statement without setting the Minor
type, but the Adult
type is set on him in the second with
statement.
Methods
Section titled “Methods”The following methods support mathematical operations on producers:
Name | Description | Returns |
---|---|---|
__add__() | Supports the + operator between producers and other values. | Expression |
__sub__() | Supports the - operator between producers and other values. | Expression |
__mul__() | Supports the * operator between producers and other values. | Expression |
__truediv__() | Supports the / operator between producers and other values. | Expression |
__floordiv__() | Supports the // operator between producers and other values. | Expression |
__pow__() | Supports the ** operator between producers and other values. | Expression |
__mod__() | Supports the % operator between producers and other values. | Expression |
The following methods support comparison operations on producers:
Name | Description | Returns |
---|---|---|
__eq__() | Supports == comparison between producers and other values. | Expression |
__ne__() | Supports != comparison between producers and other values. | Expression |
__ge__() | Supports >= comparison between producers and other values. | Expression |
__gt__() | Supports > comparison between producers and other values. | Expression |
__le__() | Supports <= comparison between producers and other values. | Expression |
__lt__() | Supports < comparison between producers and other values. | Expression |
Instances of Producer
support arbitrary attribute access
and can be used as a context manager
in a with
statement:
Name | Description | Returns |
---|---|---|
__getattribute__() | Get a property of an object. | InstanceProperty |
__enter__() | Enter the producer’s context. | None |
__exit__() | Exit the producer’s context. | None |
.__add__()
Section titled “.__add__()”Producer.__add__(other: Any) -> Expression
Returns an Expression
that produces the sum of the Producer
values and other
.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | A numeric value or another Producer object. |
Returns
Section titled “Returns”An Expression
object.
Example
Section titled “Example”You may sum a Producer
with a number literal:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() # `person.age` returns an `InstanceProperty` object, # which is also a `Producer` object. age_after_next_birthday = person.age + 1 response = select(person.name, age_after_next_birthday)
print(response.results)# Output:# v# name v# 0 Fred 40# 1 Wilma 37
You may also sum two Producer
objects:
with model.rule(): fred = Person(name="Fred") fred.set(cash=100.0, savings=200.0)
with model.rule(): wilma = Person(name="Wilma") wilma.set(cash=90.0, savings=310.0)
with model.query() as select: person = Person() # `person.cash` and `person.savings` return `InstanceProperty` # objects, which are also `Producer` objects. total_assets = person.cash + person.savings response = select(person.name, total_assets)
print(response.results)# Output:# name v# 0 Fred 300.0# 1 Wilma 400.0
.__enter__()
Section titled “.__enter__()”Producer.__enter__() -> None
Producer
objects can be used as context managers
in a with
statement
to apply restrictions in a rule or query conditionally.
In a with
statement, Python calls the context manager’s .__enter__()
method before executing the with
block.
After the with
block executes,
the with
statement automatically executes the Producer.__exit__()
method.
Returns
Section titled “Returns”None
.
Example
Section titled “Example”You may use Producer
objects in a with
statement to set a property or Type conditionally:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")Adult = model.Type("Adult")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36) Person.add(name="Pebbles", age=6)
# People who 18 years old or older are adults.with model.rule(): person = Person() with person.age >= 18: person.set(Adult)
with model.query() as select: adult = Adult() response = select(adult.name, adult.age)
print(response.results)# Output:# name age# 0 Fred 39# 1 Wilma 36
The with person.age >= 18
block temporarily restricts person.age
to values greater than or equal to 18.
After Python executes the with
block, the Producer.__exit__()
method is called to remove the restriction.
This allows you to write multiple conditional with
statements
in the same rule or query:
Child = model.Type("Child")
with model.rule(): person = Person() with person.age >= 18: person.set(Adult) with person.age < 18: person.set(Child)
with model.query() as select: child = Child() response = select(child.name, child.age)
print(response.results)# Output:# name age# 0 Pebbles 6
.__eq__()
Section titled “.__eq__()”Producer.__eq__(other: Any) -> Expression
Returns an Expression
that restricts Producer
to values equal to other
.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | A numeric value or another Producer object. |
Returns
Section titled “Returns”An Expression
object.
Example
Section titled “Example”The Producer.__eq__()
method is called when you use the ==
operator with a Producer
object:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() # Restrict `person.age` to values that are equal to 36. # `person.age` returns an `InstanceProperty` object, # which is also a `Producer` object. person.age == 36 response = select(person.name, person.age)
print(response.results)# Output:# name age# 0 Wilma 36
You may use ==
with two Producer
objects:
with model.query() as select: person1, person2 = Person(), Person() person1.age == person2.age response = select(person1.name, person2.name)
print(response.results)# Output:# name name2# 0 Fred Fred# 1 Wilma Wilma
.__exit__()
Section titled “.__exit__()”Producer.__exit__() -> None
Producer
objects can be used as context managers
in a with
statement
to apply restrictions in a rule or query conditionally.
In a with
statement, Python calls the context manager’s .__enter__()
method before executing the with
block.
After the with
block executes, the with
statement automatically executes the .__exit__()
method.
See Producer.__enter__()
for more information.
Returns
Section titled “Returns”None
.__floordiv__()
Section titled “.__floordiv__()”Producer.__floordiv__(other: Any) -> Expression
Returns an Expression
that produces the quotient of the Producer
values and other
, rounded towards negative infinity.
The type of the result is the same as the type of the producer’s values.
.__floordiv__()
is called when the //
operator is used.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | The denominator of the floor division operation. |
Returns
Section titled “Returns”An Expression
object.
Example
Section titled “Example”import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39, account_balance=-123.45) Person.add(name="Wilma", age=36, account_balance=123.45)
with model.query() as select: person = Person() half_age = person.age // 2 response = select(person.name, half_age)
print(response.results)# Output:# name result# 0 Fred 19# 1 Wilma 18
The type of the result is the same as the type of the numerator in the division.
Since the age
property is an integer, the result is also an integer.
For negative numbers, the result is rounded towards negative infinity:
with model.query() as select: person = Person() response = select(person.account_balance // 2)
print(response.results)# Output:# result# 0 -62.0# 1 61.0
.__ge__()
Section titled “.__ge__()”Producer.__ge__(other: Any) -> Expression
Returns an Expression
that restricts Producer
to values greater than or equal to other
.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | A numeric value or another Producer object. |
Returns
Section titled “Returns”An Expression
object.
Example
Section titled “Example”The Producer.__ge__()
method is called when you use the >=
operator with a Producer
object:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() # Restrict `person.age` to values that are greater than or equal # to 36. `person.age` returns an `InstanceProperty` object, # which is also a `Producer` object. person.age >= 36 response = select(person.name, person.age)
print(response.results)# Output:# name age# 0 Fred 39# 1 Wilma 36
You may use >=
with two Producer
objects:
with model.query() as select: person1, person2 = Person(), Person() person1.age > person2.age response = select(person1.name, person2.name)
print(response.results)# Output:# name name2# 0 Fred Wilma
.__getattribute__()
Section titled “.__getattribute__()”Producer.__getattribute__(name: str) -> InstanceProperty | None
Restricts the values produced to those for which a property named name
is set
and returns an InstanceProperty
object.
.__getattribute__()
is called whenever you access a property using dot notation, such as book.title
, or person.age
.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
name | str | The name of the property to get. |
Returns
Section titled “Returns”An InstanceProperty
object,
except for Expression
objects, in which case .__getattribute__()
returns None
.
Example
Section titled “Example”It is essential to keep in mind that property access adds a constraint to your context.
For example, the following query only returns objects in Person
that have a name
and age
property:
# Add a person with an age property.with model.rule(): Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() # Restrict `person` to objects with an `age` property. person.age response = select(person.name)
# Fred is not included in the results because he has no `age` property.print(response.results)# Output:# name# 0 Wilma
.__gt__()
Section titled “.__gt__()”Producer.__gt__(other: Any) -> Expression
Returns an Expression
object that restricts the values
represented by the Producer
object to the values that are strictly greater than other
.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | A numeric value or another Producer object. |
Returns
Section titled “Returns”An Expression
object.
Example
Section titled “Example”The Producer.__gt__()
method is called when you use the >
operator with a Producer
object:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() # Restrict `person.age` to values that are strictly greater # than 36. `person.age` returns an `InstanceProperty` object, # which is also a `Producer` object. person.age > 36 response = select(person.name, person.age)
print(response.results)# Output:# name age# 0 Fred 39
You may use >
with two Producer
objects:
with model.query() as select: person1, person2 = Person(), Person() person1.age > person2.age response = select(person1.name, person2.name)
print(response.results)# Output:# name name2# 0 Fred Wilma
.__le__()
Section titled “.__le__()”Producer.__le__(other: Any) -> Expression
Returns an Expression
that restricts Producer
to values less than or equal to other
.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | A numeric value or another Producer object. |
Returns
Section titled “Returns”An Expression
object.
Example
Section titled “Example”The Producer.__le__()
method is called when you use the <=
operator with a Producer
object:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() # Restrict `person.age` to values that are greater than or equal # to 36. `person.age` returns an `InstanceProperty` object, # which is also a `Producer` object. person.age <= 39 response = select(person.name, person.age)
print(response.results)# Output:# name age# 0 Fred 39# 1 Wilma 36
You may use <=
with two Producer
objects:
with model.query() as select: person1, person2 = Person(), Person() person1.age <= person2.age response = select(person1.name, person2.name)
print(response.results)# Output:# name name2# 0 Wilma Fred
.__lt__()
Section titled “.__lt__()”Producer.__lt__(other: Any) -> Expression
Returns an Expression
that restricts Producer
to values strictly less than other
.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | A numeric value or another Producer object. |
Returns
Section titled “Returns”An Expression
object.
Example
Section titled “Example”The Producer.__lt__()
method is called when you use the <
operator with a Producer
object:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() # Restrict `person.age` to values that are strictly less # than 39. `person.age` returns an `InstanceProperty` object, # which is also a `Producer` object. person.age < 39 response = select(person.name, person.age)
print(response.results)# Output:# name age# 0 Wilma 36
You may use <
with two Producer
objects:
with model.query() as select: person1, person2 = Person(), Person() person1.age < person2.age response = select(person1.name, person2.name)
print(response.results)# Output:# name name2# 0 Wilma Fred
.__mod__()
Section titled “.__mod__()”Producer.__mod__(other: Any) -> Expression
Returns an Expression
object representing the remainder of dividing the Producer
and another value.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | A numeric value or another Producer object. |
Returns
Section titled “Returns”An Expression
object that produces values of the same type as other
.
Example
Section titled “Example”You may calculate the remainder of dividing a Producer
by a number literal:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
# Get people with an even age.with model.query() as select: person = Person() person.age % 2 == 0 response = select(person.name, person.age)
print(response.results)# Output:# name age# 0 Wilma 36
You may also calculate the remainder of dividing two Producer
objects:
with model.query() as select: fred = Person(name="Fred") wilma = Person(name="Wilma") response = select(fred.age % wilma.age)
print(response.results)# Output:# v# 0 3
.__mul__()
Section titled “.__mul__()”Producer.__mul__(other: Any) -> Expression
Returns an Expression
the produces the product of the Producer
values and other
.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | A numeric value or another Producer object. |
Returns
Section titled “Returns”An Expression
object.
Example
Section titled “Example”You may multiply a Producer
object by a number literal:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() # `person.age` returns an `InstanceProperty` object, # which is also a `Producer` object. double_age = person.age * 2 response = select(person.name, double_age)
print(response.results)# Output:# name v# 0 Fred 78# 1 Wilma 72
You may also multiply two Producer
objects:
with model.rule(): fred = Person(name="Fred") fred.set(hours=30.0, wage=20.0)
with model.rule(): wilma = Person(name="Wilma") wilma.set(hours=40.0, wage=30.0)
with model.query() as select: person = Person() # `person.hours` and `person.wage` return `InstanceProperty` # objects, which are also `Producer` objects. pay = person.hours * person.wage response = select(person.name, pay)
print(response.results)# Output:# name v# 0 Fred 600.0# 1 Wilma 1200.0
.__ne__()
Section titled “.__ne__()”Producer.__ne__(other: Any) -> Expression
Returns an Expression
that restricts Producer
to values not equal to other
.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | A numeric value or another Producer object. |
Returns
Section titled “Returns”An Expression
object.
Example
Section titled “Example”The Producer.__ne__()
method is called when you use the !=
operator with a Producer
object:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() # Restrict `person.age` to values that are equal to 36. # `person.age` returns an `InstanceProperty` object, # which is also a `Producer` object. person.age != 36 response = select(person.name, person.age)
print(response.results)# Output:# name age# 0 Fred 39
You may use !=
with two Producer
objects:
with model.query() as select: person1, person2 = Person(), Person() person1.age != person2.age response = select(person1.name, person2.name)
print(response.results)# Output:# name name2# name name2# 0 Fred Wilma# 1 Wilma Fred
.__pow__()
Section titled “.__pow__()”Producer.__pow__(exp: Any) -> Expression
Returns an Expression
the produces the values of the Producer
to the power of exp
.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
exp | Any | A numeric value or another Producer object. |
Returns
Section titled “Returns”An Expression
object.
Example
Section titled “Example”You may raise a Producer
object by a number literal:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() # `person.age` returns an `InstanceProperty` object, # which is also a `Producer` object. square_age = person.age ** 2 response = select(person.name, square_age)
print(response.results)# Output:# name result# 0 Fred 1521# 1 Wilma 1296
You may also use a Producer
as the exponent:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() val = 1.01 ** person.age # A producer can be the exponent. response = select(person.name, val)
print(response.results)# Output:# name result# 0 Fred 1.474123# 1 Wilma 1.430769
.__radd__()
Section titled “.__radd__()”Producer.__radd__(other: Any) -> Expression
Returns an Expression
that produces the sum of the Producer
values and other
.
.__radd__()
is implemented so that you may use a non-Producer
object as the left operand.
.__rfloordiv__()
Section titled “.__rfloordiv__()”Producer.__rfloordiv__(other: Any) -> Expression
Returns an Expression
that produces the quotient of other
and the Producer
values, rounded towards negative infinity.
The type of the result is the same as the type of other
.
.__rfloordiv__()
is implemented so that you may use a non-Producer
object as the left operand with the //
operator.
.__rmod__()
Section titled “.__rmod__()”Producer.__rmod__(other: Any) -> Expression
Returns an Expression
object representing the remainder of dividing other
by the values of the Producer
.
.__rmod__()
is implemented so that you may use a non-Producer
object as the left operand.
.__rmul__()
Section titled “.__rmul__()”Producer.__rmul__(other: Any) -> Expression
Returns an Expression
that produces the product of Producer
values and other
.
.__rmul__()
is implemented so that you may use a non-Producer
object as the left operand.
.__rpow__()
Section titled “.__rpow__()”Producer.__rpow__(base: Any) -> Expression
Returns an Expression
that produces the power of base
raised to the values produced by the Producer
.
.__rpow__()
is implemented so that you may use a non-Producer
object as the base of the exponent.
.__rsub__()
Section titled “.__rsub__()”Producer.__rsub__(other: Any) -> Expression
Returns an Expression
that produces the difference between the Producer
values and other
.
.__rsub__()
is implemented so that you may use a non-Producer
object as the left operand.
.__rtruediv__()
Section titled “.__rtruediv__()”Producer.__rtruediv__(other: Any) -> Expression
Returns an Expression
that produces the quotient of the Producer
values and other
.
.__rtruediv__()
is implemented so that you may use a non-Producer
object as the left operand.
.__sub__()
Section titled “.__sub__()”Producer.__sub__(other: Any) -> Expression
Returns an Expression
that produces the difference between the Producer
values and other
.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | A numeric value or another Producer object. |
Returns
Section titled “Returns”An Expression
object.
Example
Section titled “Example”You may subtract a number literal from a Producer
object:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() # `person.age` returns an `InstanceProperty` object, # which are also `Producer` objects. years_as_adult = person.age - 18 response = select(person.name, years_as_adult)
print(response.results)# Output:# name v# 0 Fred 21# 1 Wilma 18
You may also subtract two Producer
objects:
with model.rule(): fred = Person(name="Fred") fred.set(expected_retirement_age=65)
with model.rule(): wilma = Person(name="Wilma") wilma.set(expected_retirement_age=62)
with model.query() as select: person = Person() # `person.age`, and `person.expected_retirement_age` return # `InstanceProperty` objects, which are also `Producer` objects. years_to_retirement = person.retirement_age - person.age response = select(person.name, years_to_retirement)
print(response.results)# Output:# name v# 0 Fred 26# 1 Wilma 26
.__truediv__()
Section titled “.__truediv__()”Producer.__truediv__(other: Any) -> Expression
Returns an Expression
that produces the quotient of the Producer
values and other
.
Parameters
Section titled “Parameters”Name | Type | Description |
---|---|---|
other | Any | A numeric value or another Producer object. |
Returns
Section titled “Returns”An Expression
object.
Example
Section titled “Example”A Producer
object may be divided by a numeric literal:
import relationalai as rai
model = rai.Model("people")Person = model.Type("Person")
with model.rule(): Person.add(name="Fred", age=39) Person.add(name="Wilma", age=36)
with model.query() as select: person = Person() # `person.age` returns an `InstanceProperty` object, # which is also a `Producer` object. percent_life_completed = person.age / 76 response = select(person.name, percent_life_completed)
print(response.results)# Output:# v# name v# 0 Fred 0.513158# 1 Wilma 0.473684
You may also divide two Producer
objects:
with model.rule(): fred = Person(name="Fred") fred.set(savings=200.0, savings_goal=1000.0)
with model.rule(): wilma = Person(name="Wilma") wilma.set(savings=300.0, savings_goal=500.0)
with model.query() as select: person = Person() # `person.savings`, and `person.savings_goal`return # `InstanceProperty` objects, which are also `Producer` objects. percent_goal_completed = savings / savings_goal response = select(person.name, percent_goal_completed)
print(response.results)# Output:# name v# 0 Fred 0.2# 1 Wilma 0.6