alf-shell 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +5 -2
- data/Gemfile.lock +29 -10
- data/bin/alf +2 -0
- data/doc/man/alf-explain.man +22 -0
- data/doc/man/alf-metadata.man +13 -0
- data/doc/man/alf-show.man +16 -0
- data/doc/man/alf.man +77 -0
- data/doc/man/allbut.man +39 -0
- data/doc/man/among.man +25 -0
- data/doc/man/avg.man +37 -0
- data/doc/man/between.man +24 -0
- data/doc/man/concat.man +55 -0
- data/doc/man/contradiction.man +26 -0
- data/doc/man/count.man +20 -0
- data/doc/man/eq.man +29 -0
- data/doc/man/extend.man +33 -0
- data/doc/man/frame.man +60 -0
- data/doc/man/group.man +51 -0
- data/doc/man/gt.man +30 -0
- data/doc/man/gte.man +30 -0
- data/doc/man/intersect.man +54 -0
- data/doc/man/join.man +84 -0
- data/doc/man/lt.man +30 -0
- data/doc/man/lte.man +30 -0
- data/doc/man/matching.man +73 -0
- data/doc/man/max.man +36 -0
- data/doc/man/min.man +36 -0
- data/doc/man/minus.man +54 -0
- data/doc/man/native.man +32 -0
- data/doc/man/neq.man +29 -0
- data/doc/man/not_matching.man +51 -0
- data/doc/man/page.man +60 -0
- data/doc/man/project.man +36 -0
- data/doc/man/rank.man +42 -0
- data/doc/man/rename.man +29 -0
- data/doc/man/restrict.man +38 -0
- data/doc/man/stddev.man +37 -0
- data/doc/man/sum.man +37 -0
- data/doc/man/summarize.man +45 -0
- data/doc/man/tautology.man +26 -0
- data/doc/man/ungroup.man +30 -0
- data/doc/man/union.man +55 -0
- data/doc/man/unwrap.man +37 -0
- data/doc/man/variance.man +37 -0
- data/doc/man/wrap.man +37 -0
- data/doc/txt/alf-explain.man +22 -0
- data/doc/txt/alf-metadata.man +16 -0
- data/doc/txt/alf-show.man +19 -0
- data/doc/txt/alf.man +80 -0
- data/doc/txt/allbut.txt +31 -0
- data/doc/txt/among.txt +20 -0
- data/doc/txt/avg.txt +22 -0
- data/doc/txt/between.txt +19 -0
- data/doc/txt/concat.txt +31 -0
- data/doc/txt/contradiction.txt +15 -0
- data/doc/txt/count.txt +14 -0
- data/doc/txt/eq.txt +19 -0
- data/doc/txt/extend.txt +29 -0
- data/doc/txt/frame.txt +48 -0
- data/doc/txt/group.txt +37 -0
- data/doc/txt/gt.txt +20 -0
- data/doc/txt/gte.txt +20 -0
- data/doc/txt/intersect.txt +42 -0
- data/doc/txt/join.txt +65 -0
- data/doc/txt/lt.txt +20 -0
- data/doc/txt/lte.txt +20 -0
- data/doc/txt/matching.txt +54 -0
- data/doc/txt/max.txt +21 -0
- data/doc/txt/min.txt +21 -0
- data/doc/txt/minus.txt +42 -0
- data/doc/txt/native.txt +27 -0
- data/doc/txt/neq.txt +19 -0
- data/doc/txt/not_matching.txt +39 -0
- data/doc/txt/page.txt +48 -0
- data/doc/txt/project.txt +28 -0
- data/doc/txt/rank.txt +34 -0
- data/doc/txt/rename.txt +25 -0
- data/doc/txt/restrict.txt +26 -0
- data/doc/txt/stddev.txt +22 -0
- data/doc/txt/sum.txt +22 -0
- data/doc/txt/summarize.txt +33 -0
- data/doc/txt/tautology.txt +15 -0
- data/doc/txt/ungroup.txt +26 -0
- data/doc/txt/union.txt +43 -0
- data/doc/txt/unwrap.txt +29 -0
- data/doc/txt/variance.txt +22 -0
- data/doc/txt/wrap.txt +29 -0
- data/lib/alf/shell.rb +2 -32
- data/lib/alf/shell/alfrc.rb +3 -0
- data/lib/alf/shell/command.rb +2 -18
- data/lib/alf/shell/command/explain.rb +37 -0
- data/lib/alf/shell/command/help.rb +3 -21
- data/lib/alf/shell/command/main.rb +20 -78
- data/lib/alf/shell/command/metadata.rb +32 -0
- data/lib/alf/shell/command/show.rb +17 -5
- data/lib/alf/shell/support.rb +21 -13
- data/lib/alf/shell/version.rb +1 -1
- data/spec/integration/explain/explain.cmd +1 -0
- data/spec/integration/explain/explain.stdout +11 -0
- data/spec/integration/show/group.alf +2 -0
- data/spec/integration/show/show_alf.cmd +1 -0
- data/spec/integration/{group/group_0.stdout → show/show_alf.stdout} +0 -0
- data/tasks/doc.rake +4 -0
- metadata +116 -178
- data/doc/commands/exec.md +0 -16
- data/doc/commands/help.md +0 -11
- data/doc/commands/main.md +0 -33
- data/doc/commands/show.md +0 -12
- data/doc/operators/non_relational/autonum.md +0 -23
- data/doc/operators/non_relational/clip.md +0 -31
- data/doc/operators/non_relational/coerce.md +0 -15
- data/doc/operators/non_relational/compact.md +0 -20
- data/doc/operators/non_relational/defaults.md +0 -32
- data/doc/operators/non_relational/generator.md +0 -20
- data/doc/operators/non_relational/sort.md +0 -24
- data/doc/operators/non_relational/type-safe.md +0 -20
- data/doc/operators/relational/extend.md +0 -18
- data/doc/operators/relational/frame.md +0 -26
- data/doc/operators/relational/group.md +0 -27
- data/doc/operators/relational/hierarchize.md +0 -14
- data/doc/operators/relational/infer-heading.md +0 -20
- data/doc/operators/relational/intersect.md +0 -13
- data/doc/operators/relational/join.md +0 -28
- data/doc/operators/relational/matching.md +0 -24
- data/doc/operators/relational/minus.md +0 -12
- data/doc/operators/relational/not-matching.md +0 -20
- data/doc/operators/relational/page.md +0 -31
- data/doc/operators/relational/project.md +0 -28
- data/doc/operators/relational/quota.md +0 -21
- data/doc/operators/relational/rank.md +0 -27
- data/doc/operators/relational/rename.md +0 -17
- data/doc/operators/relational/restrict.md +0 -25
- data/doc/operators/relational/summarize.md +0 -25
- data/doc/operators/relational/ungroup.md +0 -20
- data/doc/operators/relational/union.md +0 -14
- data/doc/operators/relational/unwrap.md +0 -20
- data/doc/operators/relational/wrap.md +0 -24
- data/lib/alf/shell/command/exec.rb +0 -16
- data/lib/alf/shell/doc_manager.rb +0 -84
- data/lib/alf/shell/ext/signature.rb +0 -45
- data/lib/alf/shell/from_argv.rb +0 -84
- data/lib/alf/shell/operator.rb +0 -63
- data/spec/integration/__database__/group.alf +0 -3
- data/spec/integration/alf/alf_e.cmd +0 -1
- data/spec/integration/alf/alf_e.stdout +0 -4
- data/spec/integration/alf/alf_help.cmd +0 -1
- data/spec/integration/alf/alf_help.stdout +0 -76
- data/spec/integration/alf/alf_r.cmd +0 -1
- data/spec/integration/alf/alf_r.stdout +0 -5
- data/spec/integration/autonum/autonum_0.cmd +0 -1
- data/spec/integration/autonum/autonum_0.stdout +0 -9
- data/spec/integration/autonum/autonum_1.cmd +0 -1
- data/spec/integration/autonum/autonum_1.stdout +0 -9
- data/spec/integration/clip/clip_0.cmd +0 -1
- data/spec/integration/clip/clip_0.stdout +0 -9
- data/spec/integration/clip/clip_1.cmd +0 -1
- data/spec/integration/clip/clip_1.stdout +0 -9
- data/spec/integration/coerce/coerce_1.cmd +0 -1
- data/spec/integration/coerce/coerce_1.stdout +0 -5
- data/spec/integration/compact/compact_0.cmd +0 -1
- data/spec/integration/compact/compact_0.stdout +0 -9
- data/spec/integration/defaults/defaults_0.cmd +0 -1
- data/spec/integration/defaults/defaults_0.stdout +0 -9
- data/spec/integration/defaults/defaults_1.cmd +0 -1
- data/spec/integration/defaults/defaults_1.stdout +0 -9
- data/spec/integration/defaults/defaults_2.cmd +0 -1
- data/spec/integration/defaults/defaults_2.stdout +0 -9
- data/spec/integration/extend/extend_0.cmd +0 -1
- data/spec/integration/extend/extend_0.stdout +0 -16
- data/spec/integration/frame/frame_0.cmd +0 -1
- data/spec/integration/frame/frame_0.stdout +0 -6
- data/spec/integration/generator/generator_1.cmd +0 -1
- data/spec/integration/generator/generator_1.stdout +0 -10
- data/spec/integration/generator/generator_2.cmd +0 -1
- data/spec/integration/generator/generator_2.stdout +0 -5
- data/spec/integration/generator/generator_3.cmd +0 -1
- data/spec/integration/generator/generator_3.stdout +0 -5
- data/spec/integration/group/group_0.cmd +0 -1
- data/spec/integration/group/group_1.cmd +0 -1
- data/spec/integration/group/group_1.stdout +0 -32
- data/spec/integration/help/help_1.cmd +0 -1
- data/spec/integration/help/help_1.stdout +0 -12
- data/spec/integration/intersect/intersect_0.cmd +0 -1
- data/spec/integration/intersect/intersect_0.stdout +0 -9
- data/spec/integration/join/join_0.cmd +0 -1
- data/spec/integration/join/join_0.stdout +0 -16
- data/spec/integration/matching/matching_0.cmd +0 -1
- data/spec/integration/matching/matching_0.stdout +0 -8
- data/spec/integration/minus/minus_0.cmd +0 -1
- data/spec/integration/minus/minus_0.stdout +0 -4
- data/spec/integration/not-matching/not-matching_0.cmd +0 -1
- data/spec/integration/not-matching/not-matching_0.stdout +0 -5
- data/spec/integration/page/page_0.cmd +0 -1
- data/spec/integration/page/page_0.stdout +0 -6
- data/spec/integration/project/project_0.cmd +0 -1
- data/spec/integration/project/project_0.stdout +0 -9
- data/spec/integration/project/project_1.cmd +0 -1
- data/spec/integration/project/project_1.stdout +0 -9
- data/spec/integration/quota/quota_0.cmd +0 -1
- data/spec/integration/quota/quota_0.stdout +0 -16
- data/spec/integration/rank/rank_1.cmd +0 -1
- data/spec/integration/rank/rank_1.stdout +0 -10
- data/spec/integration/rank/rank_2.cmd +0 -1
- data/spec/integration/rank/rank_2.stdout +0 -10
- data/spec/integration/rank/rank_3.cmd +0 -1
- data/spec/integration/rank/rank_3.stdout +0 -10
- data/spec/integration/rank/rank_4.cmd +0 -1
- data/spec/integration/rank/rank_4.stdout +0 -6
- data/spec/integration/rank/rank_5.cmd +0 -1
- data/spec/integration/rank/rank_5.stdout +0 -6
- data/spec/integration/rename/rename_0.cmd +0 -1
- data/spec/integration/rename/rename_0.stdout +0 -9
- data/spec/integration/restrict/restrict_0.cmd +0 -1
- data/spec/integration/restrict/restrict_0.stdout +0 -6
- data/spec/integration/restrict/restrict_1.cmd +0 -1
- data/spec/integration/restrict/restrict_1.stdout +0 -6
- data/spec/integration/sort/sort_0.cmd +0 -1
- data/spec/integration/sort/sort_0.stdout +0 -9
- data/spec/integration/sort/sort_1.cmd +0 -1
- data/spec/integration/sort/sort_1.stdout +0 -9
- data/spec/integration/sort/sort_2.cmd +0 -1
- data/spec/integration/sort/sort_2.stdout +0 -9
- data/spec/integration/sort/sort_3.cmd +0 -1
- data/spec/integration/sort/sort_3.stdout +0 -9
- data/spec/integration/summarize/summarize_0.cmd +0 -1
- data/spec/integration/summarize/summarize_0.stdout +0 -8
- data/spec/integration/union/union_0.cmd +0 -1
- data/spec/integration/union/union_0.stdout +0 -9
- data/spec/integration/unwrap/unwrap_0.cmd +0 -1
- data/spec/integration/unwrap/unwrap_0.stdout +0 -9
- data/spec/integration/wrap/wrap_0.cmd +0 -1
- data/spec/integration/wrap/wrap_0.stdout +0 -9
- data/spec/unit/doc_manager/dynamic.md +0 -1
- data/spec/unit/doc_manager/example.md +0 -1
- data/spec/unit/doc_manager/example_1.txt +0 -11
- data/spec/unit/doc_manager/static.md +0 -1
- data/spec/unit/doc_manager/test_call.rb +0 -41
- data/spec/unit/ext/signature/test_argv2args.rb +0 -82
- data/spec/unit/ext/signature/test_to_shell.rb +0 -103
- data/spec/unit/from_argv/test_to_attr_list.rb +0 -30
- data/spec/unit/from_argv/test_to_attr_name.rb +0 -27
- data/spec/unit/from_argv/test_to_boolean.rb +0 -32
- data/spec/unit/from_argv/test_to_heading.rb +0 -37
- data/spec/unit/from_argv/test_to_ordering.rb +0 -28
- data/spec/unit/from_argv/test_to_predicate.rb +0 -26
- data/spec/unit/from_argv/test_to_renaming.rb +0 -23
- data/spec/unit/from_argv/test_to_size.rb +0 -32
- data/spec/unit/from_argv/test_to_summarization.rb +0 -19
- data/spec/unit/from_argv/test_to_tuple_computation.rb +0 -18
- data/spec/unit/from_argv/test_to_tuple_expression.rb +0 -38
- data/spec/unit/main/test_class_methods.rb +0 -44
- data/spec/unit/operator/test_autonum.rb +0 -28
- data/spec/unit/operator/test_clip.rb +0 -29
- data/spec/unit/operator/test_coerce.rb +0 -22
- data/spec/unit/operator/test_compact.rb +0 -16
- data/spec/unit/operator/test_defaults.rb +0 -29
- data/spec/unit/operator/test_extend.rb +0 -21
- data/spec/unit/operator/test_generator.rb +0 -37
- data/spec/unit/operator/test_group.rb +0 -32
- data/spec/unit/operator/test_infer_heading.rb +0 -16
- data/spec/unit/operator/test_intersect.rb +0 -18
- data/spec/unit/operator/test_join.rb +0 -18
- data/spec/unit/operator/test_matching.rb +0 -18
- data/spec/unit/operator/test_minus.rb +0 -18
- data/spec/unit/operator/test_not_matching.rb +0 -18
- data/spec/unit/operator/test_project.rb +0 -38
- data/spec/unit/operator/test_quota.rb +0 -23
- data/spec/unit/operator/test_rank.rb +0 -30
- data/spec/unit/operator/test_rename.rb +0 -21
- data/spec/unit/operator/test_restrict.rb +0 -36
- data/spec/unit/operator/test_sort.rb +0 -49
- data/spec/unit/operator/test_summarize.rb +0 -30
- data/spec/unit/operator/test_ungroup.rb +0 -28
- data/spec/unit/operator/test_union.rb +0 -18
- data/spec/unit/operator/test_unwrap.rb +0 -28
- data/spec/unit/operator/test_wrap.rb +0 -30
data/doc/txt/allbut.txt
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Allbut
|
|
2
|
+
|
|
3
|
+
Projects a subset of attributes away.
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
allbut(operand: Relation, attributes: AttrList) -> Relation
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
|
|
11
|
+
allbut(suppliers, [:city])
|
|
12
|
+
|
|
13
|
+
## Description
|
|
14
|
+
|
|
15
|
+
Computes the relation obtained by removing a subset of attributes from
|
|
16
|
+
`operand` tuples.
|
|
17
|
+
|
|
18
|
+
This operator is the inverse of `project`. While the latter _keeps_
|
|
19
|
+
attributes, this one _removes_ them. `project` actually supports an allbut
|
|
20
|
+
variant, which is equivalent to this operator. In other words, this
|
|
21
|
+
operator can be understood as follows:
|
|
22
|
+
|
|
23
|
+
def allbut(operand, attributes)
|
|
24
|
+
project(operand, attributes, allbut: true)
|
|
25
|
+
end
|
|
26
|
+
allbut(suppliers, [:city, :status])
|
|
27
|
+
|
|
28
|
+
## Implementation notes
|
|
29
|
+
|
|
30
|
+
Unlike SQL, this operator ALWAYS remove duplicates. There is no way, in
|
|
31
|
+
Alf, to compute _bags_ of tuples.
|
data/doc/txt/among.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Among
|
|
2
|
+
|
|
3
|
+
Among a set of values
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
among(val: Alpha|AttrName, vals: Set<Alpha>) -> Predicate
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
among(:status, [10, 30])
|
|
11
|
+
|
|
12
|
+
## Description
|
|
13
|
+
|
|
14
|
+
This predicates checks whether `val` belongs to the set of values `vals`.
|
|
15
|
+
|
|
16
|
+
## Implementation notes
|
|
17
|
+
|
|
18
|
+
The set `vals` may only contain pure values, attribute names are not
|
|
19
|
+
supported. Any enumerable of such values is supported in practice, e.g.
|
|
20
|
+
an Array literal.
|
data/doc/txt/avg.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Avg
|
|
2
|
+
|
|
3
|
+
Average
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
avg(expr: AttrName|(Tuple->Numeric)) -> Aggregator
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
avg(:qty)
|
|
11
|
+
avg{|t| t.qty * t.price }
|
|
12
|
+
avg(->(t){ t.qty * t.price })
|
|
13
|
+
|
|
14
|
+
## Description
|
|
15
|
+
|
|
16
|
+
Aggregates through `v1 + v2 + ... + vn / n`.
|
|
17
|
+
|
|
18
|
+
## Implementation notes
|
|
19
|
+
|
|
20
|
+
This aggregate function should only be used with numeric types. As of
|
|
21
|
+
current Alf version, it does not aggregate empty sets correctly on
|
|
22
|
+
non-numeric data types.
|
data/doc/txt/between.txt
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Between
|
|
2
|
+
|
|
3
|
+
Between (inclusive)
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
between(val: Alpha|AttrName, min: Alpha|AttrName, max: Alpha|AttrName) -> Predicate
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
between(:status, 10, 30)
|
|
11
|
+
|
|
12
|
+
## Description
|
|
13
|
+
|
|
14
|
+
This predicates checks whether a value (`val`) is between two bounds `min`
|
|
15
|
+
and `max`, inclusive on both sides.
|
|
16
|
+
|
|
17
|
+
## Implementation notes
|
|
18
|
+
|
|
19
|
+
This predicate is equivalent to `gte(_val_,_min_) & lte(_val_,_max_)`.
|
data/doc/txt/concat.txt
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Concat
|
|
2
|
+
|
|
3
|
+
String concatenation
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
concat(expr: AttrName|(Tuple->Numeric)) -> Aggregator
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
concat(:name)
|
|
11
|
+
concat(:name, between: ', ')
|
|
12
|
+
concat(between: ', '){|t| t.name }
|
|
13
|
+
concat(->(t){ t.name.upcase }, between: ', ')
|
|
14
|
+
|
|
15
|
+
## Description
|
|
16
|
+
|
|
17
|
+
Concatenates string representations of input values.
|
|
18
|
+
|
|
19
|
+
## Implementation notes
|
|
20
|
+
|
|
21
|
+
This aggregate function can be applied to any data type, not only String
|
|
22
|
+
attributes. Ruby's `to_s` will be used on values prior to concatenation.
|
|
23
|
+
|
|
24
|
+
The options are:
|
|
25
|
+
|
|
26
|
+
* `before` starts the resulting string (defaults to '')
|
|
27
|
+
* `after` ends the resulting string (defaults to '')
|
|
28
|
+
* `between` is used between each value
|
|
29
|
+
|
|
30
|
+
As of current Alf version, the order in which the values are concatenated
|
|
31
|
+
is not guaranteed. So far, this function is thus non-deterministic.
|
data/doc/txt/count.txt
ADDED
data/doc/txt/eq.txt
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Eq
|
|
2
|
+
|
|
3
|
+
Equals to
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
eq(left: Alpha|AttrName, right: Alpha|AttrName) -> Predicate
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
eq(:city, 'London')
|
|
11
|
+
eq(:supplier_city, :part_city)
|
|
12
|
+
|
|
13
|
+
## Description
|
|
14
|
+
|
|
15
|
+
This predicates checks whether two values are equal.
|
|
16
|
+
|
|
17
|
+
## Implementation notes
|
|
18
|
+
|
|
19
|
+
This predicate is equivalent to `->(t){ _left_ == _right_ }`.
|
data/doc/txt/extend.txt
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Extend
|
|
2
|
+
|
|
3
|
+
Extends input tuples with derived/computed attributes
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
extend(operand: Relation, ext: TupleComputation) -> Relation
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
|
|
11
|
+
extend(suppliers,
|
|
12
|
+
big: ->(t){ t.name.upcase },
|
|
13
|
+
small: ->(t){ t.name.downcase })
|
|
14
|
+
|
|
15
|
+
## Description
|
|
16
|
+
|
|
17
|
+
Computes a relation which is the same as `operand`, except that each of
|
|
18
|
+
its tuples has new attributes whose value is the result of evaluating the
|
|
19
|
+
tuple expressions specified in `ext`.
|
|
20
|
+
|
|
21
|
+
## Implementation notes
|
|
22
|
+
|
|
23
|
+
As of current Alf version, this operator cannot be translated to SQL code.
|
|
24
|
+
In other words, all computations are done in ruby, which may seriously
|
|
25
|
+
hurt performance.
|
|
26
|
+
|
|
27
|
+
Similarly, as `extend` tends to be a showstopper during compilation, it is
|
|
28
|
+
strongly recommanded to use it as high as possible in query expressions
|
|
29
|
+
trees so as to delegate the largest possible query parts to data engines.
|
data/doc/txt/frame.txt
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Frame
|
|
2
|
+
|
|
3
|
+
Aka limit/offset
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
frame(operand: Relation, order: Ordering, offset: Integer, limit: Integer) -> Relation
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
|
|
11
|
+
frame(suppliers, [:status, :sid], 0, 3)
|
|
12
|
+
|
|
13
|
+
frame(suppliers, [[:status, :asc], [:sid, :desc]], 1, 2)
|
|
14
|
+
|
|
15
|
+
## Description
|
|
16
|
+
|
|
17
|
+
Computes a relation by restricting the tuples of `operand` to a particular
|
|
18
|
+
frame. This frame can be easily remembered through the "skip `offset`,
|
|
19
|
+
take `limit`" mnemonic mean, provided `order` is a total order.
|
|
20
|
+
|
|
21
|
+
Formally, the frame is defined by those tuples whose ranking according to
|
|
22
|
+
`order` is such that `offset <= rank < limit`. In other words, this
|
|
23
|
+
operator is actually equivalent to the following definition:
|
|
24
|
+
|
|
25
|
+
def frame(operand, order, offset, limit)
|
|
26
|
+
allbut(
|
|
27
|
+
restrict(
|
|
28
|
+
rank(operand, order, :rank),
|
|
29
|
+
lte(offset, :rank) & lt(:rank, offset+limit)),
|
|
30
|
+
[:rank])
|
|
31
|
+
end
|
|
32
|
+
frame(suppliers, [:city, :sid], 2, 3)
|
|
33
|
+
|
|
34
|
+
As of current Alf version, for this operator to be semantically sound and
|
|
35
|
+
deterministic, `order` MUST be a total order, that is, it must at least
|
|
36
|
+
cover a candidate key. As of current Alf version, no error is raised if
|
|
37
|
+
this is not the case but that might change in future versions.
|
|
38
|
+
|
|
39
|
+
## Implementation notes
|
|
40
|
+
|
|
41
|
+
Contrary to the longer expression shown above, this operator compiles to
|
|
42
|
+
'efficient' SQL (rank does not, so far) at the cost of having to provide a
|
|
43
|
+
total order.
|
|
44
|
+
|
|
45
|
+
As the result is a relation and relations are not ordered by definition,
|
|
46
|
+
the order in which tuples can be observed in the result (e.g. through
|
|
47
|
+
explicit tuple iteration, casting to an array, json encoding) is NOT
|
|
48
|
+
guaranteed to follow `order`.
|
data/doc/txt/group.txt
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Group
|
|
2
|
+
|
|
3
|
+
Relation-valued attribute
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
group(operand: Relation, attributes: AttrList, as: AttrName) -> Relation
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
|
|
11
|
+
group(suppliers, [:sid, :name, :status], :suppliers)
|
|
12
|
+
|
|
13
|
+
group(suppliers, [:city], :suppliers, allbut: true)
|
|
14
|
+
|
|
15
|
+
## Description
|
|
16
|
+
|
|
17
|
+
Summarizes `operand` by all but the specified `attributes` and groups the
|
|
18
|
+
latter under a relation-value attribute `as`.
|
|
19
|
+
|
|
20
|
+
This operator could be formally defined as the following shortcut:
|
|
21
|
+
|
|
22
|
+
def group(operand, attributes, as)
|
|
23
|
+
extend(
|
|
24
|
+
allbut(operand, attributes),
|
|
25
|
+
as: ->(t){ project(matching(operand, Relation(t)), attributes) })
|
|
26
|
+
end
|
|
27
|
+
group(suppliers, [:sid, :name, :status], :suppliers)
|
|
28
|
+
|
|
29
|
+
This operators supports an ALL BUT variant, through the `allbut` option.
|
|
30
|
+
When set to true, the operator keeps specified attributes and groups all
|
|
31
|
+
remaining ones as a relation-valued attribute.
|
|
32
|
+
|
|
33
|
+
## Implementation notes
|
|
34
|
+
|
|
35
|
+
This operator does not compile to SQL so far. Contributions are welcome
|
|
36
|
+
to provide it with a SQL compilation for SQL DBMSs that support this kind
|
|
37
|
+
of feature (e.g. PostgreSQL with JSON data type)
|
data/doc/txt/gt.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Gt
|
|
2
|
+
|
|
3
|
+
Greater than
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
gt(left: Alpha|AttrName, right: Alpha|AttrName) -> Predicate
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
gt(:status, 20)
|
|
11
|
+
gt(:status, 30)
|
|
12
|
+
|
|
13
|
+
## Description
|
|
14
|
+
|
|
15
|
+
This predicates checks whether a value (`left`) is greater than another
|
|
16
|
+
one (`right`).
|
|
17
|
+
|
|
18
|
+
## Implementation notes
|
|
19
|
+
|
|
20
|
+
This predicate is equivalent to `->(t){ _left_ > _right_ }`.
|
data/doc/txt/gte.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Gte
|
|
2
|
+
|
|
3
|
+
Greater than or equal to
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
gte(left: Alpha|AttrName, right: Alpha|AttrName) -> Predicate
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
gte(:status, 20)
|
|
11
|
+
gte(:status, 30)
|
|
12
|
+
|
|
13
|
+
## Description
|
|
14
|
+
|
|
15
|
+
This predicates checks whether a value (`left`) is greater than or equal
|
|
16
|
+
to another one (`right`).
|
|
17
|
+
|
|
18
|
+
## Implementation notes
|
|
19
|
+
|
|
20
|
+
This predicate is equivalent to `->(t){ _left_ >= _right_ }`.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Intersect
|
|
2
|
+
|
|
3
|
+
Logical AND
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
intersect(left: Relation, right: Relation) -> Relation
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
|
|
11
|
+
intersect(
|
|
12
|
+
restrict(suppliers, eq(:city, 'Paris')),
|
|
13
|
+
restrict(suppliers, gt(:status, 10)))
|
|
14
|
+
|
|
15
|
+
## Description
|
|
16
|
+
|
|
17
|
+
Computes the relation as the set intersection of `left` and `right`.
|
|
18
|
+
|
|
19
|
+
The `left` and `right` relations must be intersect-compatible, meaning that
|
|
20
|
+
they must have same heading (type inheritance is partly supported through
|
|
21
|
+
ruby's own type system, so that the actual behavior is slighlty more
|
|
22
|
+
permissive).
|
|
23
|
+
|
|
24
|
+
## Implementation notes
|
|
25
|
+
|
|
26
|
+
Unlike SQL, this operator ALWAYS remove duplicates. There is no way, in
|
|
27
|
+
Alf, to compute _bags_ of tuples and therefore no way to express something
|
|
28
|
+
such as SQL's INTERSECT ALL.
|
|
29
|
+
|
|
30
|
+
It is sometimes idiomatic in Alf to use `intersect` as a logical AND, as
|
|
31
|
+
illustrated below. So far, the optimizer/compiler is not smart enough to
|
|
32
|
+
translate the former into the latter (which is likely to have a better query
|
|
33
|
+
when using faithful SQL compilation and available SQL DBMSs). Any patch is
|
|
34
|
+
welcome here too!
|
|
35
|
+
|
|
36
|
+
intersect(
|
|
37
|
+
restrict(suppliers, eq(:city, 'Paris')),
|
|
38
|
+
restrict(suppliers, gt(:status, 10)))
|
|
39
|
+
|
|
40
|
+
is equivalent to
|
|
41
|
+
|
|
42
|
+
restrict(suppliers, eq(:city, 'Paris') & gt(:status, 10))
|
data/doc/txt/join.txt
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Join
|
|
2
|
+
|
|
3
|
+
Natural join
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
join(left: Relation, right: Relation) -> Relation
|
|
8
|
+
|
|
9
|
+
## Examples
|
|
10
|
+
|
|
11
|
+
join(suppliers, supplies)
|
|
12
|
+
|
|
13
|
+
## Description
|
|
14
|
+
|
|
15
|
+
Computes the relation resuting from joining tuples from `left` and `right`
|
|
16
|
+
whose respective projections on common attributes are equal.
|
|
17
|
+
|
|
18
|
+
## Implementation notes
|
|
19
|
+
|
|
20
|
+
Alf only support natural join for now. Other kinds of join can generally
|
|
21
|
+
be computed through longer expressions. For instance, joining on attributes
|
|
22
|
+
with different names requires some renaming first:
|
|
23
|
+
|
|
24
|
+
# suppose preferences has type Relation[supplier_id: String, ...]
|
|
25
|
+
# suppose we want to join on suppliers.sid == preferences.supplier_id
|
|
26
|
+
join(suppliers, rename(preferences, :supplier_id => :sid))
|
|
27
|
+
|
|
28
|
+
Cross joins can be computed through operands having no attribute in common.
|
|
29
|
+
For instance, all pairs of supplier and part identifiers can be computed
|
|
30
|
+
as follows:
|
|
31
|
+
|
|
32
|
+
pairs = join(project(suppliers, [:sid]), project(parts, [:pid]))
|
|
33
|
+
|
|
34
|
+
Non equi-joins can be computed through a latter restriction. For instance,
|
|
35
|
+
the (supplier, part) pairs not located in the same city:
|
|
36
|
+
|
|
37
|
+
ps = project(rename(parts, :city => :part_city), [:pid, :part_city])
|
|
38
|
+
ss = project(rename(suppliers, :city => :supplier_city), [:sid, :supplier_city])
|
|
39
|
+
pairs = join(ps, ss)
|
|
40
|
+
project(restrict(pairs, neq(:part_city, :supplier_city)), [:sid, :pid])
|
|
41
|
+
|
|
42
|
+
As obviously demonstrated by the example above, such query is rather
|
|
43
|
+
cumbersome to write and verbous. Future versions of Alf will come with
|
|
44
|
+
useful shortcuts and new operators. In the mean time, don't forget that
|
|
45
|
+
defining your own shortcuts and operators is easy! Don't hesitate to
|
|
46
|
+
contribute them if of general purpose.
|
|
47
|
+
|
|
48
|
+
Last, natural join tends to be error prone; in particular, you must take
|
|
49
|
+
care of common attributes of your design on which you do not want to join
|
|
50
|
+
(such as `latest_change` and `deleted` fields and the like). Renamings and
|
|
51
|
+
projections are worth having at hand when joining.
|
|
52
|
+
|
|
53
|
+
Alternatively, shortcuts can be considered. A (advanced) example below:
|
|
54
|
+
|
|
55
|
+
# The following shortcut joins `left` and `right` on `wish` attributes
|
|
56
|
+
# only. Other common attributes are simply projected away from `right`
|
|
57
|
+
# before joining.
|
|
58
|
+
def join_on(left, right, wish)
|
|
59
|
+
commons = left.attr_list & right.attr_list
|
|
60
|
+
join(left, allbut(right, commons - wish))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# observe here how part names have been discarded to avoid joining them
|
|
64
|
+
# with supplier names (empty result guaranteed)
|
|
65
|
+
join_on(suppliers, parts, [:city])
|