Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name = "QueryableBackend"
uuid = "0898d9ac-042b-5d31-8dcc-959fb3365f19"
version = "1.0.1-DEV"
version = "1.1.0-DEV"

[deps]
QueryOperators = "2aef5ad7-51ca-5a8f-8e88-e75cf067b44b"
Expand All @@ -13,8 +13,8 @@ TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[compat]
julia = "1"
QueryOperators = "0.8, 0.9, 1"
julia = "1.10"
QueryOperators = "1.2"
IteratorInterfaceExtensions = "1"
TableTraits = "1"

Expand Down
8 changes: 8 additions & 0 deletions src/QueryableBackend.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,21 @@ include("queryable/queryable_orderby.jl")
include("queryable/queryable_thenby.jl")
include("queryable/queryable_join.jl")
include("queryable/queryable_groupjoin.jl")
include("queryable/queryable_outerjoin.jl")
include("queryable/queryable_mapmany.jl")
include("queryable/queryable_take.jl")
include("queryable/queryable_drop.jl")
include("queryable/queryable_unique.jl")
include("queryable/queryable_setops.jl")
include("queryable/queryable_partition.jl")
include("queryable/queryable_ordering.jl")
include("queryable/queryable_combining.jl")
include("queryable/queryable_keyedaggregation.jl")
include("queryable/queryable_typefiltering.jl")

include("source_queryable.jl")
include("query_tree.jl")
include("queryable/queryable_scalar.jl")
include("query_plan.jl")

end
59 changes: 59 additions & 0 deletions src/query_plan.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
return "Drop: $(q.n)"
end

function describe_node(q::QueryableUnique)

Check notice on line 50 in src/query_plan.jl

View workflow job for this annotation

GitHub Actions / julia-ci / lint

unused_function_argument

An argument is included in a function signature but not used within its body.
return "Unique"
end

Expand All @@ -71,6 +71,65 @@
return "MapMany: $(string(q.collectionSelector_expr)) => $(string(q.resultSelector_expr))"
end

function describe_node(q::QueryableLeftJoin)
return "LeftJoin: $(string(q.outerKeySelector_expr)) = $(string(q.innerKeySelector_expr)) => $(string(q.resultSelector_expr))"
end

function describe_node(q::QueryableRightJoin)
return "RightJoin: $(string(q.outerKeySelector_expr)) = $(string(q.innerKeySelector_expr)) => $(string(q.resultSelector_expr))"
end

function describe_node(q::QueryableFullJoin)
return "FullJoin: $(string(q.outerKeySelector_expr)) = $(string(q.innerKeySelector_expr)) => $(string(q.resultSelector_expr))"
end

describe_node(::QueryableConcat) = "Concat"

describe_node(q::QueryableUnion) = _describe_setop("Union", q)

describe_node(q::QueryableExcept) = _describe_setop("Except", q)

describe_node(q::QueryableIntersect) = _describe_setop("Intersect", q)

# A `nothing` key selector is the plain form, which compares whole elements.
function _describe_setop(name, q)
return q.f_expr === nothing ? name : "$(name)By: $(string(q.f_expr))"
end

describe_node(q::QueryableTakeWhile) = "TakeWhile: $(string(q.f_expr))"

describe_node(q::QueryableDropWhile) = "DropWhile: $(string(q.f_expr))"

describe_node(q::QueryableTakeLast) = "TakeLast: $(q.n)"

describe_node(q::QueryableDropLast) = "DropLast: $(q.n)"

describe_node(::QueryableReverse) = "Reverse"

describe_node(::QueryableShuffle) = "Shuffle"

describe_node(::QueryableIndex) = "Index"

describe_node(q::QueryableAppend) = "Append: $(repr(q.element))"

describe_node(q::QueryablePrepend) = "Prepend: $(repr(q.element))"

function describe_node(q::QueryableZip)
return q.resultSelector_expr === nothing ? "Zip" : "Zip: $(string(q.resultSelector_expr))"
end

describe_node(q::QueryableCountBy) = "CountBy: $(string(q.f_expr))"

describe_node(q::QueryableAggregateBy) = "AggregateBy: $(string(q.f_expr))"

describe_node(q::QueryableChunk) = "Chunk: $(q.n)"

describe_node(q::QueryableOfType) = "OfType: $(q.T)"

describe_node(q::QueryableCast) = "Cast: $(q.T)"

describe_node(q::QueryableScalar) = "Scalar: $(q.op)"

# Fallback for unknown/extension types
describe_node(q::Queryable) = string(typeof(q))

Expand Down
16 changes: 4 additions & 12 deletions src/query_tree.jl
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
"""
get_source(q::Queryable)

Follow the `.source` (or `.outer`) chain to the root `QueryableSource`.
Follow the `.source` (or, for two-input nodes, `.outer`) chain to the root
`QueryableSource`.
"""
function get_source(q::QueryableSource)
return q
end

function get_source(q::QueryableJoin)
return get_source(q.outer)
end

function get_source(q::QueryableGroupJoin)
function get_source(q::QueryableBinary)
return get_source(q.outer)
end

Expand All @@ -34,12 +31,7 @@ function _collect_nodes!(nodes, q::QueryableSource)
push!(nodes, q)
end

function _collect_nodes!(nodes, q::QueryableJoin)
push!(nodes, q)
_collect_nodes!(nodes, q.outer)
end

function _collect_nodes!(nodes, q::QueryableGroupJoin)
function _collect_nodes!(nodes, q::QueryableBinary)
push!(nodes, q)
_collect_nodes!(nodes, q.outer)
end
Expand Down
10 changes: 10 additions & 0 deletions src/queryable/queryable.jl
Original file line number Diff line number Diff line change
@@ -1,9 +1,19 @@
abstract type Queryable end

"""
QueryableBinary <: Queryable

Nodes that combine two sources — joins, set operations, `zip`. They carry
`outer` and `inner` fields, and the tree walk follows `outer`, so the query
plan reads as a chain hanging off the primary input with the secondary input
attached at the node.
"""
abstract type QueryableBinary <: Queryable end

QueryOperators.query(x::Queryable) = x

IteratorInterfaceExtensions.isiterable(x::Queryable) = true

Check notice on line 15 in src/queryable/queryable.jl

View workflow job for this annotation

GitHub Actions / julia-ci / lint

unused_function_argument

An argument is included in a function signature but not used within its body.
TableTraits.isiterabletable(x::Queryable) = true

Check notice on line 16 in src/queryable/queryable.jl

View workflow job for this annotation

GitHub Actions / julia-ci / lint

unused_function_argument

An argument is included in a function signature but not used within its body.

function IteratorInterfaceExtensions.getiterator(x::Queryable)
return x.getiterator(x)
Expand Down
37 changes: 37 additions & 0 deletions src/queryable/queryable_combining.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
struct QueryableAppend <: Queryable
source
element
getiterator
end

struct QueryablePrepend <: Queryable
source
element
getiterator
end

struct QueryableZip <: QueryableBinary
outer
inner
resultSelector_func
resultSelector_expr
getiterator
end

function QueryOperators.append(source::Queryable, element)
return QueryableAppend(source, element, source.getiterator)
end

function QueryOperators.prepend(source::Queryable, element)
return QueryablePrepend(source, element, source.getiterator)
end

# As with the set operators, a `nothing` result selector means the default:
# pair the two elements into a tuple.
function QueryOperators.zip(outer::Queryable, inner)
return QueryableZip(outer, inner, nothing, nothing, outer.getiterator)
end

function QueryOperators.zip(outer::Queryable, inner, f_resultSelector::Function, resultSelector::Expr)
return QueryableZip(outer, inner, f_resultSelector, resultSelector, outer.getiterator)
end
2 changes: 1 addition & 1 deletion src/queryable/queryable_groupjoin.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
struct QueryableGroupJoin <: Queryable
struct QueryableGroupJoin <: QueryableBinary
outer
inner
outerKeySelector_func
Expand Down
2 changes: 1 addition & 1 deletion src/queryable/queryable_join.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
struct QueryableJoin <: Queryable
struct QueryableJoin <: QueryableBinary
outer
inner
outerKeySelector_func
Expand Down
33 changes: 33 additions & 0 deletions src/queryable/queryable_keyedaggregation.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
struct QueryableCountBy <: Queryable
source
f_func
f_expr
getiterator
end

struct QueryableAggregateBy <: Queryable
source
f_func
f_expr
seed
accumulator_func
getiterator
end

struct QueryableChunk <: Queryable
source
n::Int
getiterator
end

function QueryOperators.count_by(source::Queryable, f::Function, f_expr::Expr)
return QueryableCountBy(source, f, f_expr, source.getiterator)
end

function QueryOperators.aggregate_by(source::Queryable, f::Function, f_expr::Expr, seed, accumulator::Function)
return QueryableAggregateBy(source, f, f_expr, seed, accumulator, source.getiterator)
end

function QueryOperators.chunk(source::Queryable, n::Integer)
return QueryableChunk(source, Int(n), source.getiterator)
end
43 changes: 43 additions & 0 deletions src/queryable/queryable_ordering.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
struct QueryableReverse <: Queryable
source
getiterator
end

struct QueryableShuffle <: Queryable
source
rng
getiterator
end

struct QueryableIndex <: Queryable
source
getiterator
end

# `order` and `order_descending` sort by the elements themselves, which is an
# orderby with an identity key selector. They reuse QueryableOrderBy rather
# than adding a node type, so `thenby` can still follow them and a backend can
# recognise the identity selector to sort by every column.
function QueryOperators.order(source::Queryable)
return QueryOperators.orderby(source, identity, :(i -> i))
end

function QueryOperators.order_descending(source::Queryable)
return QueryOperators.orderby_descending(source, identity, :(i -> i))
end

function QueryOperators.reverse(source::Queryable)
return QueryableReverse(source, source.getiterator)
end

function QueryOperators.shuffle(source::Queryable)
return QueryableShuffle(source, nothing, source.getiterator)
end

function QueryOperators.shuffle(source::Queryable, rng)
return QueryableShuffle(source, rng, source.getiterator)
end

function QueryOperators.index(source::Queryable)
return QueryableIndex(source, source.getiterator)
end
43 changes: 43 additions & 0 deletions src/queryable/queryable_outerjoin.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
struct QueryableLeftJoin <: QueryableBinary
outer
inner
outerKeySelector_func
outerKeySelector_expr
innerKeySelector_func
innerKeySelector_expr
resultSelector_func
resultSelector_expr
getiterator
end

struct QueryableRightJoin <: QueryableBinary
outer
inner
outerKeySelector_func
outerKeySelector_expr
innerKeySelector_func
innerKeySelector_expr
resultSelector_func
resultSelector_expr
getiterator
end

struct QueryableFullJoin <: QueryableBinary
outer
inner
outerKeySelector_func
outerKeySelector_expr
innerKeySelector_func
innerKeySelector_expr
resultSelector_func
resultSelector_expr
getiterator
end

for (op, node) in ((:left_join, :QueryableLeftJoin),
(:right_join, :QueryableRightJoin),
(:full_join, :QueryableFullJoin))
@eval function QueryOperators.$op(outer::Queryable, inner, f_outerKeySelector::Function, outerKeySelector::Expr, f_innerKeySelector::Function, innerKeySelector::Expr, f_resultSelector::Function, resultSelector::Expr)
return $node(outer, inner, f_outerKeySelector, outerKeySelector, f_innerKeySelector, innerKeySelector, f_resultSelector, resultSelector, outer.getiterator)
end
end
41 changes: 41 additions & 0 deletions src/queryable/queryable_partition.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
struct QueryableTakeWhile <: Queryable
source
f_func
f_expr
getiterator
end

struct QueryableDropWhile <: Queryable
source
f_func
f_expr
getiterator
end

struct QueryableTakeLast <: Queryable
source
n::Int
getiterator
end

struct QueryableDropLast <: Queryable
source
n::Int
getiterator
end

function QueryOperators.take_while(source::Queryable, f::Function, f_expr::Expr)
return QueryableTakeWhile(source, f, f_expr, source.getiterator)
end

function QueryOperators.drop_while(source::Queryable, f::Function, f_expr::Expr)
return QueryableDropWhile(source, f, f_expr, source.getiterator)
end

function QueryOperators.take_last(source::Queryable, n::Integer)
return QueryableTakeLast(source, Int(n), source.getiterator)
end

function QueryOperators.drop_last(source::Queryable, n::Integer)
return QueryableDropLast(source, Int(n), source.getiterator)
end
Loading
Loading