Expressions evaluate into useful objects via a query builder like interface.
Expressions provides an API for expression types. You can build your own Expression, or use expressions created via the gems below:
# Via method definition:
def method(my_var: MyType); end
# Via type() helper:
my_var = type MyType | fetch_my_object(id: 123)my_var is now type checked to be of type MyType when assigned to.
ℹ️ Requires: LowType
def method(my_var: Dependency); endmy_var is now automatically assigned to via dependency injection.
ℹ️ Requires: LowType and Providers
The table expression inverts the usual database query logic. Instead of building a query of what we want from the database, we build the table we want and let the expression build the query.
class PostsData < LowData
def all
Table[:username, :title, :body]
end
endThis expression joins the posts table with the users table without any joins from the user's perspective.
class PostsData < LowData
def all
Users[:username] + Posts[:title, :body]
end
endThe above expression generates SQL to join the user table with the posts table and results in a list of posts with the user's username included in each row.
ℹ️ Requires: LowData
Inherit from Expressions::Expression and define a hook/callback:
| Hook / callback method | Trigger |
|---|---|
def union_expression(expression) |
MyExpression | MyExpression[] |
def union_value(value) |
MyExpression | :my_value |
def union_type(type) |
MyExpression | MyType |
def intersect_expression(expression) |
MyExpression & MyExpression[] |
def intersect_value(value) |
MyExpression & :my_value |
def intersect_type(type) |
MyExpression & MyType |
def add_expression(expression) |
MyExpression + MyExpression[] |
def add_value(value) |
MyExpression + :my_value |
def add_type(type) |
MyExpression + MyType |
def gt_expression(expression) |
MyExpression > MyExpression[] |
def gt_value(value) |
MyExpression > :my_value |
def gt_type(type) |
MyExpression > MyType |
def gt_or_eq_expression(expression) |
MyExpression >= MyExpression[] |
def gt_or_eq_value(value) |
MyExpression >= :my_value |
def gt_or_eq_type(type) |
MyExpression >= MyType |
def lt_expression(expression) |
MyExpression < MyExpression[] |
def lt_value(value) |
MyExpression < :my_value |
def lt_type(type) |
MyExpression < MyType |
def lt_or_eq_expression(expression) |
MyExpression <= MyExpression[] |
def lt_or_eq_value(value) |
MyExpression <= :my_value |
def lt_or_eq_type(type) |
MyExpression <= MyType |
def compare_expression(expression) |
MyExpression <=> MyExpression[] |
def compare_value(value) |
MyExpression <=> :my_value |
def compare_type(type) |
MyExpression <=> MyType |
def xor_expression(expression) |
MyExpression ^ MyExpression[] |
def xor_value(value) |
MyExpression ^ :my_value |
def xor_type(type) |
MyExpression ^ MyType |
def multiply_expression(expression) |
MyExpression * MyExpression[] |
def multiply_value(value) |
MyExpression * :my_value |
def multiply_type(type) |
MyExpression * MyType |
def divide_expression(expression) |
MyExpression / MyExpression[] |
def divide_value(value) |
MyExpression / :my_value |
def divide_type(type) |
MyExpression / MyType |
def append_expression(expression) |
MyExpression << MyExpression[] |
def append_value(value) |
MyExpression << :my_value |
def append_type(type) |
MyExpression << MyType |
Each operator calls its hook on a copy of the expression and returns the copy, so the expression it's called on is unchanged and can be reused. A subclass with mutable state, such as an array, copies it in initialize_copy. a += b works as usual: Ruby turns it into a = a + b.
<< is the exception, which is an action like Ruby's Array#<<. It calls its hook on the expression itself and returns what was inserted.
Gems using Expressions will do this step for you, but if you'd like to build your own expression then add gem 'expressions' to your Gemfile and run:
bundle install