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.
Files changed (276) hide show
  1. data/Gemfile +5 -2
  2. data/Gemfile.lock +29 -10
  3. data/bin/alf +2 -0
  4. data/doc/man/alf-explain.man +22 -0
  5. data/doc/man/alf-metadata.man +13 -0
  6. data/doc/man/alf-show.man +16 -0
  7. data/doc/man/alf.man +77 -0
  8. data/doc/man/allbut.man +39 -0
  9. data/doc/man/among.man +25 -0
  10. data/doc/man/avg.man +37 -0
  11. data/doc/man/between.man +24 -0
  12. data/doc/man/concat.man +55 -0
  13. data/doc/man/contradiction.man +26 -0
  14. data/doc/man/count.man +20 -0
  15. data/doc/man/eq.man +29 -0
  16. data/doc/man/extend.man +33 -0
  17. data/doc/man/frame.man +60 -0
  18. data/doc/man/group.man +51 -0
  19. data/doc/man/gt.man +30 -0
  20. data/doc/man/gte.man +30 -0
  21. data/doc/man/intersect.man +54 -0
  22. data/doc/man/join.man +84 -0
  23. data/doc/man/lt.man +30 -0
  24. data/doc/man/lte.man +30 -0
  25. data/doc/man/matching.man +73 -0
  26. data/doc/man/max.man +36 -0
  27. data/doc/man/min.man +36 -0
  28. data/doc/man/minus.man +54 -0
  29. data/doc/man/native.man +32 -0
  30. data/doc/man/neq.man +29 -0
  31. data/doc/man/not_matching.man +51 -0
  32. data/doc/man/page.man +60 -0
  33. data/doc/man/project.man +36 -0
  34. data/doc/man/rank.man +42 -0
  35. data/doc/man/rename.man +29 -0
  36. data/doc/man/restrict.man +38 -0
  37. data/doc/man/stddev.man +37 -0
  38. data/doc/man/sum.man +37 -0
  39. data/doc/man/summarize.man +45 -0
  40. data/doc/man/tautology.man +26 -0
  41. data/doc/man/ungroup.man +30 -0
  42. data/doc/man/union.man +55 -0
  43. data/doc/man/unwrap.man +37 -0
  44. data/doc/man/variance.man +37 -0
  45. data/doc/man/wrap.man +37 -0
  46. data/doc/txt/alf-explain.man +22 -0
  47. data/doc/txt/alf-metadata.man +16 -0
  48. data/doc/txt/alf-show.man +19 -0
  49. data/doc/txt/alf.man +80 -0
  50. data/doc/txt/allbut.txt +31 -0
  51. data/doc/txt/among.txt +20 -0
  52. data/doc/txt/avg.txt +22 -0
  53. data/doc/txt/between.txt +19 -0
  54. data/doc/txt/concat.txt +31 -0
  55. data/doc/txt/contradiction.txt +15 -0
  56. data/doc/txt/count.txt +14 -0
  57. data/doc/txt/eq.txt +19 -0
  58. data/doc/txt/extend.txt +29 -0
  59. data/doc/txt/frame.txt +48 -0
  60. data/doc/txt/group.txt +37 -0
  61. data/doc/txt/gt.txt +20 -0
  62. data/doc/txt/gte.txt +20 -0
  63. data/doc/txt/intersect.txt +42 -0
  64. data/doc/txt/join.txt +65 -0
  65. data/doc/txt/lt.txt +20 -0
  66. data/doc/txt/lte.txt +20 -0
  67. data/doc/txt/matching.txt +54 -0
  68. data/doc/txt/max.txt +21 -0
  69. data/doc/txt/min.txt +21 -0
  70. data/doc/txt/minus.txt +42 -0
  71. data/doc/txt/native.txt +27 -0
  72. data/doc/txt/neq.txt +19 -0
  73. data/doc/txt/not_matching.txt +39 -0
  74. data/doc/txt/page.txt +48 -0
  75. data/doc/txt/project.txt +28 -0
  76. data/doc/txt/rank.txt +34 -0
  77. data/doc/txt/rename.txt +25 -0
  78. data/doc/txt/restrict.txt +26 -0
  79. data/doc/txt/stddev.txt +22 -0
  80. data/doc/txt/sum.txt +22 -0
  81. data/doc/txt/summarize.txt +33 -0
  82. data/doc/txt/tautology.txt +15 -0
  83. data/doc/txt/ungroup.txt +26 -0
  84. data/doc/txt/union.txt +43 -0
  85. data/doc/txt/unwrap.txt +29 -0
  86. data/doc/txt/variance.txt +22 -0
  87. data/doc/txt/wrap.txt +29 -0
  88. data/lib/alf/shell.rb +2 -32
  89. data/lib/alf/shell/alfrc.rb +3 -0
  90. data/lib/alf/shell/command.rb +2 -18
  91. data/lib/alf/shell/command/explain.rb +37 -0
  92. data/lib/alf/shell/command/help.rb +3 -21
  93. data/lib/alf/shell/command/main.rb +20 -78
  94. data/lib/alf/shell/command/metadata.rb +32 -0
  95. data/lib/alf/shell/command/show.rb +17 -5
  96. data/lib/alf/shell/support.rb +21 -13
  97. data/lib/alf/shell/version.rb +1 -1
  98. data/spec/integration/explain/explain.cmd +1 -0
  99. data/spec/integration/explain/explain.stdout +11 -0
  100. data/spec/integration/show/group.alf +2 -0
  101. data/spec/integration/show/show_alf.cmd +1 -0
  102. data/spec/integration/{group/group_0.stdout → show/show_alf.stdout} +0 -0
  103. data/tasks/doc.rake +4 -0
  104. metadata +116 -178
  105. data/doc/commands/exec.md +0 -16
  106. data/doc/commands/help.md +0 -11
  107. data/doc/commands/main.md +0 -33
  108. data/doc/commands/show.md +0 -12
  109. data/doc/operators/non_relational/autonum.md +0 -23
  110. data/doc/operators/non_relational/clip.md +0 -31
  111. data/doc/operators/non_relational/coerce.md +0 -15
  112. data/doc/operators/non_relational/compact.md +0 -20
  113. data/doc/operators/non_relational/defaults.md +0 -32
  114. data/doc/operators/non_relational/generator.md +0 -20
  115. data/doc/operators/non_relational/sort.md +0 -24
  116. data/doc/operators/non_relational/type-safe.md +0 -20
  117. data/doc/operators/relational/extend.md +0 -18
  118. data/doc/operators/relational/frame.md +0 -26
  119. data/doc/operators/relational/group.md +0 -27
  120. data/doc/operators/relational/hierarchize.md +0 -14
  121. data/doc/operators/relational/infer-heading.md +0 -20
  122. data/doc/operators/relational/intersect.md +0 -13
  123. data/doc/operators/relational/join.md +0 -28
  124. data/doc/operators/relational/matching.md +0 -24
  125. data/doc/operators/relational/minus.md +0 -12
  126. data/doc/operators/relational/not-matching.md +0 -20
  127. data/doc/operators/relational/page.md +0 -31
  128. data/doc/operators/relational/project.md +0 -28
  129. data/doc/operators/relational/quota.md +0 -21
  130. data/doc/operators/relational/rank.md +0 -27
  131. data/doc/operators/relational/rename.md +0 -17
  132. data/doc/operators/relational/restrict.md +0 -25
  133. data/doc/operators/relational/summarize.md +0 -25
  134. data/doc/operators/relational/ungroup.md +0 -20
  135. data/doc/operators/relational/union.md +0 -14
  136. data/doc/operators/relational/unwrap.md +0 -20
  137. data/doc/operators/relational/wrap.md +0 -24
  138. data/lib/alf/shell/command/exec.rb +0 -16
  139. data/lib/alf/shell/doc_manager.rb +0 -84
  140. data/lib/alf/shell/ext/signature.rb +0 -45
  141. data/lib/alf/shell/from_argv.rb +0 -84
  142. data/lib/alf/shell/operator.rb +0 -63
  143. data/spec/integration/__database__/group.alf +0 -3
  144. data/spec/integration/alf/alf_e.cmd +0 -1
  145. data/spec/integration/alf/alf_e.stdout +0 -4
  146. data/spec/integration/alf/alf_help.cmd +0 -1
  147. data/spec/integration/alf/alf_help.stdout +0 -76
  148. data/spec/integration/alf/alf_r.cmd +0 -1
  149. data/spec/integration/alf/alf_r.stdout +0 -5
  150. data/spec/integration/autonum/autonum_0.cmd +0 -1
  151. data/spec/integration/autonum/autonum_0.stdout +0 -9
  152. data/spec/integration/autonum/autonum_1.cmd +0 -1
  153. data/spec/integration/autonum/autonum_1.stdout +0 -9
  154. data/spec/integration/clip/clip_0.cmd +0 -1
  155. data/spec/integration/clip/clip_0.stdout +0 -9
  156. data/spec/integration/clip/clip_1.cmd +0 -1
  157. data/spec/integration/clip/clip_1.stdout +0 -9
  158. data/spec/integration/coerce/coerce_1.cmd +0 -1
  159. data/spec/integration/coerce/coerce_1.stdout +0 -5
  160. data/spec/integration/compact/compact_0.cmd +0 -1
  161. data/spec/integration/compact/compact_0.stdout +0 -9
  162. data/spec/integration/defaults/defaults_0.cmd +0 -1
  163. data/spec/integration/defaults/defaults_0.stdout +0 -9
  164. data/spec/integration/defaults/defaults_1.cmd +0 -1
  165. data/spec/integration/defaults/defaults_1.stdout +0 -9
  166. data/spec/integration/defaults/defaults_2.cmd +0 -1
  167. data/spec/integration/defaults/defaults_2.stdout +0 -9
  168. data/spec/integration/extend/extend_0.cmd +0 -1
  169. data/spec/integration/extend/extend_0.stdout +0 -16
  170. data/spec/integration/frame/frame_0.cmd +0 -1
  171. data/spec/integration/frame/frame_0.stdout +0 -6
  172. data/spec/integration/generator/generator_1.cmd +0 -1
  173. data/spec/integration/generator/generator_1.stdout +0 -10
  174. data/spec/integration/generator/generator_2.cmd +0 -1
  175. data/spec/integration/generator/generator_2.stdout +0 -5
  176. data/spec/integration/generator/generator_3.cmd +0 -1
  177. data/spec/integration/generator/generator_3.stdout +0 -5
  178. data/spec/integration/group/group_0.cmd +0 -1
  179. data/spec/integration/group/group_1.cmd +0 -1
  180. data/spec/integration/group/group_1.stdout +0 -32
  181. data/spec/integration/help/help_1.cmd +0 -1
  182. data/spec/integration/help/help_1.stdout +0 -12
  183. data/spec/integration/intersect/intersect_0.cmd +0 -1
  184. data/spec/integration/intersect/intersect_0.stdout +0 -9
  185. data/spec/integration/join/join_0.cmd +0 -1
  186. data/spec/integration/join/join_0.stdout +0 -16
  187. data/spec/integration/matching/matching_0.cmd +0 -1
  188. data/spec/integration/matching/matching_0.stdout +0 -8
  189. data/spec/integration/minus/minus_0.cmd +0 -1
  190. data/spec/integration/minus/minus_0.stdout +0 -4
  191. data/spec/integration/not-matching/not-matching_0.cmd +0 -1
  192. data/spec/integration/not-matching/not-matching_0.stdout +0 -5
  193. data/spec/integration/page/page_0.cmd +0 -1
  194. data/spec/integration/page/page_0.stdout +0 -6
  195. data/spec/integration/project/project_0.cmd +0 -1
  196. data/spec/integration/project/project_0.stdout +0 -9
  197. data/spec/integration/project/project_1.cmd +0 -1
  198. data/spec/integration/project/project_1.stdout +0 -9
  199. data/spec/integration/quota/quota_0.cmd +0 -1
  200. data/spec/integration/quota/quota_0.stdout +0 -16
  201. data/spec/integration/rank/rank_1.cmd +0 -1
  202. data/spec/integration/rank/rank_1.stdout +0 -10
  203. data/spec/integration/rank/rank_2.cmd +0 -1
  204. data/spec/integration/rank/rank_2.stdout +0 -10
  205. data/spec/integration/rank/rank_3.cmd +0 -1
  206. data/spec/integration/rank/rank_3.stdout +0 -10
  207. data/spec/integration/rank/rank_4.cmd +0 -1
  208. data/spec/integration/rank/rank_4.stdout +0 -6
  209. data/spec/integration/rank/rank_5.cmd +0 -1
  210. data/spec/integration/rank/rank_5.stdout +0 -6
  211. data/spec/integration/rename/rename_0.cmd +0 -1
  212. data/spec/integration/rename/rename_0.stdout +0 -9
  213. data/spec/integration/restrict/restrict_0.cmd +0 -1
  214. data/spec/integration/restrict/restrict_0.stdout +0 -6
  215. data/spec/integration/restrict/restrict_1.cmd +0 -1
  216. data/spec/integration/restrict/restrict_1.stdout +0 -6
  217. data/spec/integration/sort/sort_0.cmd +0 -1
  218. data/spec/integration/sort/sort_0.stdout +0 -9
  219. data/spec/integration/sort/sort_1.cmd +0 -1
  220. data/spec/integration/sort/sort_1.stdout +0 -9
  221. data/spec/integration/sort/sort_2.cmd +0 -1
  222. data/spec/integration/sort/sort_2.stdout +0 -9
  223. data/spec/integration/sort/sort_3.cmd +0 -1
  224. data/spec/integration/sort/sort_3.stdout +0 -9
  225. data/spec/integration/summarize/summarize_0.cmd +0 -1
  226. data/spec/integration/summarize/summarize_0.stdout +0 -8
  227. data/spec/integration/union/union_0.cmd +0 -1
  228. data/spec/integration/union/union_0.stdout +0 -9
  229. data/spec/integration/unwrap/unwrap_0.cmd +0 -1
  230. data/spec/integration/unwrap/unwrap_0.stdout +0 -9
  231. data/spec/integration/wrap/wrap_0.cmd +0 -1
  232. data/spec/integration/wrap/wrap_0.stdout +0 -9
  233. data/spec/unit/doc_manager/dynamic.md +0 -1
  234. data/spec/unit/doc_manager/example.md +0 -1
  235. data/spec/unit/doc_manager/example_1.txt +0 -11
  236. data/spec/unit/doc_manager/static.md +0 -1
  237. data/spec/unit/doc_manager/test_call.rb +0 -41
  238. data/spec/unit/ext/signature/test_argv2args.rb +0 -82
  239. data/spec/unit/ext/signature/test_to_shell.rb +0 -103
  240. data/spec/unit/from_argv/test_to_attr_list.rb +0 -30
  241. data/spec/unit/from_argv/test_to_attr_name.rb +0 -27
  242. data/spec/unit/from_argv/test_to_boolean.rb +0 -32
  243. data/spec/unit/from_argv/test_to_heading.rb +0 -37
  244. data/spec/unit/from_argv/test_to_ordering.rb +0 -28
  245. data/spec/unit/from_argv/test_to_predicate.rb +0 -26
  246. data/spec/unit/from_argv/test_to_renaming.rb +0 -23
  247. data/spec/unit/from_argv/test_to_size.rb +0 -32
  248. data/spec/unit/from_argv/test_to_summarization.rb +0 -19
  249. data/spec/unit/from_argv/test_to_tuple_computation.rb +0 -18
  250. data/spec/unit/from_argv/test_to_tuple_expression.rb +0 -38
  251. data/spec/unit/main/test_class_methods.rb +0 -44
  252. data/spec/unit/operator/test_autonum.rb +0 -28
  253. data/spec/unit/operator/test_clip.rb +0 -29
  254. data/spec/unit/operator/test_coerce.rb +0 -22
  255. data/spec/unit/operator/test_compact.rb +0 -16
  256. data/spec/unit/operator/test_defaults.rb +0 -29
  257. data/spec/unit/operator/test_extend.rb +0 -21
  258. data/spec/unit/operator/test_generator.rb +0 -37
  259. data/spec/unit/operator/test_group.rb +0 -32
  260. data/spec/unit/operator/test_infer_heading.rb +0 -16
  261. data/spec/unit/operator/test_intersect.rb +0 -18
  262. data/spec/unit/operator/test_join.rb +0 -18
  263. data/spec/unit/operator/test_matching.rb +0 -18
  264. data/spec/unit/operator/test_minus.rb +0 -18
  265. data/spec/unit/operator/test_not_matching.rb +0 -18
  266. data/spec/unit/operator/test_project.rb +0 -38
  267. data/spec/unit/operator/test_quota.rb +0 -23
  268. data/spec/unit/operator/test_rank.rb +0 -30
  269. data/spec/unit/operator/test_rename.rb +0 -21
  270. data/spec/unit/operator/test_restrict.rb +0 -36
  271. data/spec/unit/operator/test_sort.rb +0 -49
  272. data/spec/unit/operator/test_summarize.rb +0 -30
  273. data/spec/unit/operator/test_ungroup.rb +0 -28
  274. data/spec/unit/operator/test_union.rb +0 -18
  275. data/spec/unit/operator/test_unwrap.rb +0 -28
  276. data/spec/unit/operator/test_wrap.rb +0 -30
@@ -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.
@@ -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.
@@ -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.
@@ -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_)`.
@@ -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.
@@ -0,0 +1,15 @@
1
+ # Contradiction
2
+
3
+ FALSE
4
+
5
+ ## Signature
6
+
7
+ contradiction() -> Predicate
8
+
9
+ ## Examples
10
+ false
11
+ contradiction
12
+
13
+ ## Description
14
+
15
+ This predicate always return false. It is equivalent to `->(t){ false }`.
@@ -0,0 +1,14 @@
1
+ # Count
2
+
3
+ Count
4
+
5
+ ## Signature
6
+
7
+ count() -> Aggregator
8
+
9
+ ## Examples
10
+ count()
11
+
12
+ ## Description
13
+
14
+ Counts the number of input values.
@@ -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_ }`.
@@ -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.
@@ -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`.
@@ -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)
@@ -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_ }`.
@@ -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))
@@ -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])