relationalai.dsl.Producer
class ProducerInstances 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:
personProduces aPersonobject.person.age >= 18only lets through objects with an age of 18 or more.person.set(Adult)sets theAdulttype 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 BobBoth 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) -> ExpressionReturns 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 37You 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__() -> NoneProducer 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 36The 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) -> ExpressionReturns 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 36You 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__() -> NoneProducer 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) -> ExpressionReturns 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 18The 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) -> ExpressionReturns 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 36You 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 | NoneRestricts 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) -> ExpressionReturns 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 39You 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) -> ExpressionReturns 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 36You 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) -> ExpressionReturns 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 36You 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) -> ExpressionReturns 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 36You 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) -> ExpressionReturns 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 72You 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) -> ExpressionReturns 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 39You 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) -> ExpressionReturns 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 1296You 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) -> ExpressionReturns 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) -> ExpressionReturns 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) -> ExpressionReturns 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) -> ExpressionReturns 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) -> ExpressionReturns 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) -> ExpressionReturns 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) -> ExpressionReturns 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) -> ExpressionReturns 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 18You 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) -> ExpressionReturns 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.473684You 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