alf 0.9.3 → 0.10.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/CHANGELOG.md +255 -129
- data/Gemfile +31 -1
- data/Gemfile.lock +17 -20
- data/LICENCE.md +1 -1
- data/Manifest.txt +2 -0
- data/README.md +37 -43
- data/TODO.md +1 -1
- data/alf.gemspec +10 -7
- data/alf.noespec +24 -13
- data/bin/alf +2 -2
- data/doc/commands/exec.md +16 -0
- data/doc/commands/help.md +11 -0
- data/doc/commands/main.md +33 -0
- data/doc/commands/show.md +19 -0
- data/doc/operators/non_relational/autonum.md +23 -0
- data/doc/operators/non_relational/clip.md +31 -0
- data/doc/operators/non_relational/coerce.md +15 -0
- data/doc/operators/non_relational/compact.md +20 -0
- data/doc/operators/non_relational/defaults.md +32 -0
- data/doc/operators/non_relational/generator.md +20 -0
- data/doc/operators/non_relational/sort.md +24 -0
- data/doc/operators/relational/extend.md +18 -0
- data/doc/operators/relational/group.md +27 -0
- data/doc/operators/relational/intersect.md +13 -0
- data/doc/operators/relational/join.md +27 -0
- data/doc/operators/relational/matching.md +20 -0
- data/doc/operators/relational/minus.md +12 -0
- data/doc/operators/relational/not-matching.md +20 -0
- data/doc/operators/relational/project.md +28 -0
- data/doc/operators/relational/quota.md +21 -0
- data/doc/operators/relational/rank.md +27 -0
- data/doc/operators/relational/rename.md +17 -0
- data/doc/operators/relational/restrict.md +25 -0
- data/doc/operators/relational/summarize.md +25 -0
- data/doc/operators/relational/ungroup.md +20 -0
- data/doc/operators/relational/union.md +14 -0
- data/doc/operators/relational/unwrap.md +20 -0
- data/doc/operators/relational/wrap.md +24 -0
- data/examples/csv/suppliers.csv +6 -0
- data/examples/logs/access.log +1000 -0
- data/examples/logs/combined.alf +2 -0
- data/examples/logs/hits.alf +14 -0
- data/examples/logs/not_found.alf +7 -0
- data/examples/logs/robots-cheating.alf +11 -0
- data/examples/logs/robots.alf +8 -0
- data/examples/northwind/customers.csv +92 -0
- data/examples/northwind/northwind.db +0 -0
- data/examples/northwind/orders.csv +831 -0
- data/examples/operators/clip.alf +1 -1
- data/examples/operators/database.alf +5 -6
- data/examples/operators/defaults.alf +1 -1
- data/examples/operators/group.alf +1 -1
- data/examples/operators/project.alf +2 -1
- data/examples/operators/pseudo-with.alf +2 -2
- data/examples/operators/quota.alf +2 -2
- data/examples/operators/summarize.alf +2 -2
- data/lib/alf/aggregator/aggregators.rb +77 -0
- data/lib/alf/aggregator/base.rb +95 -0
- data/lib/alf/aggregator/class_methods.rb +57 -0
- data/lib/alf/buffer/sorted.rb +48 -0
- data/lib/alf/command/class_methods.rb +27 -0
- data/lib/alf/command/doc_manager.rb +72 -0
- data/lib/alf/command/exec.rb +12 -0
- data/lib/alf/command/help.rb +31 -0
- data/lib/alf/command/main.rb +146 -0
- data/lib/alf/command/show.rb +33 -0
- data/lib/alf/environment/base.rb +37 -0
- data/lib/alf/environment/class_methods.rb +93 -0
- data/lib/alf/environment/explicit.rb +38 -0
- data/lib/alf/environment/folder.rb +62 -0
- data/lib/alf/extra/csv.rb +104 -0
- data/lib/alf/extra/logs.rb +100 -0
- data/lib/alf/extra/sequel.rb +77 -0
- data/lib/alf/{yaml.rb → extra/yaml.rb} +0 -0
- data/lib/alf/extra.rb +5 -0
- data/lib/alf/iterator/base.rb +38 -0
- data/lib/alf/iterator/class_methods.rb +22 -0
- data/lib/alf/iterator/proxy.rb +33 -0
- data/lib/alf/lispy/instance_methods.rb +157 -0
- data/lib/alf/operator/base.rb +74 -0
- data/lib/alf/operator/binary.rb +32 -0
- data/lib/alf/operator/cesure.rb +45 -0
- data/lib/alf/operator/class_methods.rb +132 -0
- data/lib/alf/operator/experimental.rb +9 -0
- data/lib/alf/operator/non_relational/autonum.rb +24 -0
- data/lib/alf/operator/non_relational/clip.rb +20 -0
- data/lib/alf/operator/non_relational/coerce.rb +21 -0
- data/lib/alf/operator/non_relational/compact.rb +62 -0
- data/lib/alf/operator/non_relational/defaults.rb +25 -0
- data/lib/alf/operator/non_relational/generator.rb +38 -0
- data/lib/alf/operator/non_relational/sort.rb +23 -0
- data/lib/alf/operator/nullary.rb +20 -0
- data/lib/alf/operator/relational/extend.rb +24 -0
- data/lib/alf/operator/relational/group.rb +32 -0
- data/lib/alf/operator/relational/intersect.rb +37 -0
- data/lib/alf/operator/relational/join.rb +106 -0
- data/lib/alf/operator/relational/matching.rb +45 -0
- data/lib/alf/operator/relational/minus.rb +37 -0
- data/lib/alf/operator/relational/not_matching.rb +45 -0
- data/lib/alf/operator/relational/project.rb +22 -0
- data/lib/alf/operator/relational/quota.rb +51 -0
- data/lib/alf/operator/relational/rank.rb +55 -0
- data/lib/alf/operator/relational/rename.rb +19 -0
- data/lib/alf/operator/relational/restrict.rb +20 -0
- data/lib/alf/operator/relational/summarize.rb +83 -0
- data/lib/alf/operator/relational/ungroup.rb +25 -0
- data/lib/alf/operator/relational/union.rb +32 -0
- data/lib/alf/operator/relational/unwrap.rb +21 -0
- data/lib/alf/operator/relational/wrap.rb +22 -0
- data/lib/alf/operator/shortcut.rb +53 -0
- data/lib/alf/operator/signature.rb +262 -0
- data/lib/alf/operator/transform.rb +27 -0
- data/lib/alf/operator/unary.rb +38 -0
- data/lib/alf/reader/alf_file.rb +24 -0
- data/lib/alf/reader/base.rb +119 -0
- data/lib/alf/reader/class_methods.rb +82 -0
- data/lib/alf/reader/rash.rb +28 -0
- data/lib/alf/relation/class_methods.rb +37 -0
- data/lib/alf/relation/instance_methods.rb +127 -0
- data/lib/alf/renderer/base.rb +72 -0
- data/lib/alf/renderer/class_methods.rb +58 -0
- data/lib/alf/renderer/rash.rb +19 -0
- data/lib/alf/{text.rb → renderer/text.rb} +1 -1
- data/lib/alf/tools/coerce.rb +14 -0
- data/lib/alf/tools/miscellaneous.rb +77 -0
- data/lib/alf/tools/to_lispy.rb +99 -0
- data/lib/alf/tools/to_ruby_literal.rb +14 -0
- data/lib/alf/tools/tuple_handle.rb +50 -0
- data/lib/alf/types/attr_list.rb +56 -0
- data/lib/alf/types/attr_name.rb +28 -0
- data/lib/alf/types/boolean.rb +12 -0
- data/lib/alf/types/heading.rb +96 -0
- data/lib/alf/types/ordering.rb +93 -0
- data/lib/alf/types/renaming.rb +57 -0
- data/lib/alf/types/summarization.rb +76 -0
- data/lib/alf/types/tuple_computation.rb +61 -0
- data/lib/alf/types/tuple_expression.rb +61 -0
- data/lib/alf/types/tuple_predicate.rb +49 -0
- data/lib/alf/version.rb +2 -2
- data/lib/alf.rb +193 -3714
- data/spec/integration/__database__/group.alf +1 -1
- data/spec/integration/__database__/suppliers_csv.csv +6 -0
- data/spec/integration/command/alf/alf.db +0 -0
- data/spec/integration/command/alf/alf_env_sqlite.cmd +1 -0
- data/spec/integration/command/alf/alf_env_sqlite.stdout +9 -0
- data/spec/integration/command/alf/alf_help.cmd +1 -0
- data/spec/integration/command/alf/alf_help.stdout +67 -0
- data/spec/integration/command/autonum/autonum_0.cmd +1 -1
- data/spec/integration/command/coerce/coerce_1.cmd +1 -0
- data/spec/integration/command/coerce/coerce_1.stdout +5 -0
- data/spec/integration/command/defaults/defaults_0.cmd +1 -1
- data/spec/integration/command/defaults/defaults_0.stdout +9 -9
- data/spec/integration/command/defaults/defaults_2.cmd +1 -0
- data/spec/integration/command/defaults/defaults_2.stdout +9 -0
- data/spec/integration/command/generator/generator_1.cmd +1 -0
- data/spec/integration/command/generator/generator_1.stdout +10 -0
- data/spec/integration/command/generator/generator_2.cmd +1 -0
- data/spec/integration/command/generator/generator_2.stdout +5 -0
- data/spec/integration/command/generator/generator_3.cmd +1 -0
- data/spec/integration/command/generator/generator_3.stdout +5 -0
- data/spec/integration/command/group/group_0.cmd +1 -1
- data/spec/integration/command/group/group_1.cmd +1 -1
- data/spec/integration/command/help/help_1.cmd +1 -0
- data/spec/integration/command/help/help_1.stdout +22 -0
- data/spec/integration/command/quota/quota_0.cmd +1 -1
- data/spec/integration/command/rank/rank_1.cmd +1 -1
- data/spec/integration/command/rank/rank_1.stdout +10 -10
- data/spec/integration/command/rank/rank_2.cmd +1 -1
- data/spec/integration/command/rank/rank_2.stdout +10 -10
- data/spec/integration/command/rank/rank_3.cmd +1 -1
- data/spec/integration/command/rank/rank_3.stdout +10 -10
- data/spec/integration/command/rank/rank_4.cmd +1 -1
- data/spec/integration/command/rank/rank_5.cmd +1 -1
- data/spec/integration/command/show/show_csv.cmd +1 -0
- data/spec/integration/command/show/show_csv.stdout +6 -0
- data/spec/integration/command/show/show_rash_2.cmd +1 -1
- data/spec/integration/command/show/show_rash_2.stdout +5 -5
- data/spec/integration/command/sort/sort_0.cmd +1 -1
- data/spec/integration/command/sort/sort_1.cmd +1 -1
- data/spec/integration/command/sort/sort_1.stdout +2 -2
- data/spec/integration/command/sort/sort_2.cmd +1 -0
- data/spec/integration/command/sort/sort_2.stdout +9 -0
- data/spec/integration/command/sort/sort_3.cmd +1 -0
- data/spec/integration/command/sort/sort_3.stdout +9 -0
- data/spec/integration/command/summarize/summarize_0.cmd +1 -1
- data/spec/integration/command/ungroup/ungroup_0.cmd +1 -1
- data/spec/integration/command/wrap/wrap_0.cmd +1 -1
- data/spec/integration/semantics/test_project.alf +5 -6
- data/spec/integration/semantics/test_rank.alf +16 -16
- data/spec/integration/test_command.rb +17 -6
- data/spec/integration/test_examples.rb +1 -1
- data/spec/regression/logs/apache_combined.log +5 -0
- data/spec/regression/logs/test_path_attribute.rb +25 -0
- data/spec/regression/relation/test_relation_allbut_all.rb +14 -0
- data/spec/shared/an_operator_class.rb +10 -5
- data/spec/spec_helper.rb +1 -7
- data/spec/unit/assumptions/test_set.rb +64 -0
- data/spec/unit/command/doc_manager/dynamic.md +1 -0
- data/spec/unit/command/doc_manager/example.md +1 -0
- data/spec/unit/command/doc_manager/example_1.txt +11 -0
- data/spec/unit/command/doc_manager/static.md +1 -0
- data/spec/unit/command/doc_manager/test_call.rb +49 -0
- data/spec/unit/csv/input.csv +3 -0
- data/spec/unit/csv/test_reader.rb +66 -0
- data/spec/unit/csv/test_renderer.rb +73 -0
- data/spec/unit/lispy/test_relation.rb +37 -0
- data/spec/unit/lispy/test_run.rb +40 -0
- data/spec/unit/lispy/test_tuple.rb +36 -0
- data/spec/unit/logs/apache_combined.log +5 -0
- data/spec/unit/logs/postgresql.log +29 -0
- data/spec/unit/logs/test_reader.rb +56 -0
- data/spec/unit/operator/non_relational/compact/{buffer_based.rb → test_buffer_based.rb} +0 -0
- data/spec/unit/operator/non_relational/test_clip.rb +1 -1
- data/spec/unit/operator/non_relational/test_coerce.rb +35 -0
- data/spec/unit/operator/non_relational/test_defaults.rb +15 -2
- data/spec/unit/operator/non_relational/test_generator.rb +78 -0
- data/spec/unit/operator/relational/join/test_hash_based.rb +4 -4
- data/spec/unit/operator/relational/matching/test_hash_based.rb +6 -6
- data/spec/unit/operator/relational/not_matching/test_hash_based.rb +4 -4
- data/spec/unit/operator/relational/summarize/test_hash_based.rb +10 -6
- data/spec/unit/operator/relational/summarize/test_sort_based.rb +18 -7
- data/spec/unit/operator/relational/test_group.rb +8 -8
- data/spec/unit/operator/relational/test_intersect.rb +3 -3
- data/spec/unit/operator/relational/test_minus.rb +3 -3
- data/spec/unit/operator/relational/test_project.rb +12 -2
- data/spec/unit/operator/relational/test_quota.rb +5 -6
- data/spec/unit/operator/relational/test_summarize.rb +9 -11
- data/spec/unit/operator/relational/test_union.rb +1 -1
- data/spec/unit/operator/relational/test_wrap.rb +1 -1
- data/spec/unit/operator/signature/test_collect_on.rb +45 -0
- data/spec/unit/operator/signature/test_initialize.rb +17 -0
- data/spec/unit/operator/signature/test_install.rb +56 -0
- data/spec/unit/operator/signature/test_option_parser.rb +36 -0
- data/spec/unit/operator/signature/test_parse_args.rb +60 -0
- data/spec/unit/operator/signature/test_parse_argv.rb +87 -0
- data/spec/unit/operator/signature/test_to_lispy.rb +102 -0
- data/spec/unit/operator/signature/test_to_shell.rb +103 -0
- data/spec/unit/operator/test_non_relational.rb +3 -1
- data/spec/unit/relation/test_relops.rb +20 -15
- data/spec/unit/sequel/alf.db +0 -0
- data/spec/unit/sequel/test_environment.rb +54 -0
- data/spec/unit/test_aggregator.rb +32 -22
- data/spec/unit/test_environment.rb +5 -0
- data/spec/unit/test_lispy.rb +4 -0
- data/spec/unit/test_relation.rb +5 -0
- data/spec/unit/text/test_cell.rb +6 -6
- data/spec/unit/text/test_row.rb +3 -3
- data/spec/unit/text/test_table.rb +6 -6
- data/spec/unit/tools/test_coalesce.rb +15 -0
- data/spec/unit/tools/test_coerce.rb +10 -0
- data/spec/unit/tools/test_to_lispy.rb +138 -0
- data/spec/unit/tools/test_to_ruby_literal.rb +10 -0
- data/spec/unit/tools/test_tuple_handle.rb +1 -59
- data/spec/unit/types/test_attr_list.rb +106 -0
- data/spec/unit/types/test_attr_name.rb +52 -0
- data/spec/unit/{test_heading.rb → types/test_heading.rb} +10 -0
- data/spec/unit/types/test_ordering.rb +127 -0
- data/spec/unit/types/test_renaming.rb +55 -0
- data/spec/unit/types/test_summarization.rb +63 -0
- data/spec/unit/types/test_tuple_computation.rb +60 -0
- data/spec/unit/types/test_tuple_expression.rb +64 -0
- data/spec/unit/types/test_tuple_predicate.rb +79 -0
- data/tasks/debug_mail.rake +1 -1
- data/tasks/debug_mail.txt +5 -0
- data/tasks/gh-pages.rake +63 -0
- metadata +325 -52
- data/spec/unit/operator/test_command_methods.rb +0 -38
- data/spec/unit/tools/test_ordering_key.rb +0 -94
- data/spec/unit/tools/test_parse_commandline_args.rb +0 -47
- data/spec/unit/tools/test_projection_key.rb +0 -83
data/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Alf - Relational Algebra at your fingertips (version 0.
|
|
1
|
+
# Alf - Relational Algebra at your fingertips (version 0.10.0)
|
|
2
2
|
|
|
3
3
|
## Description
|
|
4
4
|
|
|
@@ -12,19 +12,24 @@ _relations_... Let's stop the segregation ;-)
|
|
|
12
12
|
|
|
13
13
|
### Install
|
|
14
14
|
|
|
15
|
-
% [sudo] gem install alf
|
|
15
|
+
% [sudo] gem install alf [fastercsv, ...]
|
|
16
16
|
% alf --help
|
|
17
17
|
|
|
18
18
|
### Bundler & Require
|
|
19
19
|
|
|
20
20
|
# API is not considered stable enough for now, please use
|
|
21
|
-
gem "alf", "= 0.
|
|
21
|
+
gem "alf", "= 0.10.0"
|
|
22
|
+
|
|
23
|
+
# The following should not break your code, but is a bit less safe,
|
|
24
|
+
# until 1.0.0 has been reached
|
|
25
|
+
gem "alf", "~> 0.10.0"
|
|
22
26
|
|
|
23
27
|
### Links
|
|
24
28
|
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
29
|
+
* http://blambeau.github.com/alf
|
|
30
|
+
* http://rubydoc.info/gems/alf
|
|
31
|
+
* http://github.com/blambeau/alf
|
|
32
|
+
* http://rubygems.org/gems/alf
|
|
28
33
|
|
|
29
34
|
### Quick overview
|
|
30
35
|
|
|
@@ -65,9 +70,9 @@ of a truly relational algebra approach. Objectives behind Alf are manifold:
|
|
|
65
70
|
|
|
66
71
|
* Alf is also an educational tool, that I've written to draw people attention
|
|
67
72
|
about the ill-known relational theory (and ill-represented by SQL). The tool
|
|
68
|
-
is largely inspired from
|
|
73
|
+
is largely inspired from **Tutorial D**, the tutorial language of Chris Date and
|
|
69
74
|
Hugh Darwen in their books, more specifically in
|
|
70
|
-
{http://www.thethirdmanifesto.com/ The Third Manifesto (TTM)}.
|
|
75
|
+
{http://www.thethirdmanifesto.com/ *The Third Manifesto* (TTM)}.
|
|
71
76
|
However, Alf only provides an overview of the relational _algebra_ defined
|
|
72
77
|
there (Alf is neither a relational _database_, nor a relational _language_).
|
|
73
78
|
I hope that people (especially talented developers) will be sufficiently
|
|
@@ -76,7 +81,7 @@ of a truly relational algebra approach. Objectives behind Alf are manifold:
|
|
|
76
81
|
the following query for the kind of things that you'll never ever have in SQL
|
|
77
82
|
(see also 'alf help quota', 'alf help wrap', 'alf help group', ...):
|
|
78
83
|
|
|
79
|
-
% alf --text summarize supplies --
|
|
84
|
+
% alf --text summarize supplies -- sid -- total "sum{ qty }" which "collect{ pid }"
|
|
80
85
|
|
|
81
86
|
* Last, but not least, Alf is an attempt to help me test some research ideas and
|
|
82
87
|
communicate about them with people that already know (all or part) of the TTM
|
|
@@ -87,7 +92,7 @@ of a truly relational algebra approach. Objectives behind Alf are manifold:
|
|
|
87
92
|
'research work in progress', and used with care because not necessarily in
|
|
88
93
|
conformance with the TTM.
|
|
89
94
|
|
|
90
|
-
% alf --text quota supplies --
|
|
95
|
+
% alf --text quota supplies -- sid -- qty -- pos "count()"
|
|
91
96
|
|
|
92
97
|
## Overview of relational theory
|
|
93
98
|
|
|
@@ -233,7 +238,7 @@ you want! The same query, in shell:
|
|
|
233
238
|
|
|
234
239
|
## What is Alf exactly?
|
|
235
240
|
|
|
236
|
-
The Third Manifesto defines a series of prescriptions, proscriptions and very
|
|
241
|
+
*The Third Manifesto* defines a series of prescriptions, proscriptions and very
|
|
237
242
|
strong suggestions for designing a truly relational _language_, called a _D_,
|
|
238
243
|
as an alternative to SQL for managing relational databases. This is far behind
|
|
239
244
|
my objective with Alf, as it does not touch at database issues at all (persistence,
|
|
@@ -267,7 +272,7 @@ section about versioning policy at the end of this file).
|
|
|
267
272
|
If you take a look at .alf example files, you'll find functional ruby expressions
|
|
268
273
|
like the following (called Lispy expressions):
|
|
269
274
|
|
|
270
|
-
% cat examples/minus.alf
|
|
275
|
+
% cat examples/operators/minus.alf
|
|
271
276
|
|
|
272
277
|
# Give all suppliers, except those living in Paris
|
|
273
278
|
(minus :suppliers,
|
|
@@ -280,7 +285,7 @@ like the following (called Lispy expressions):
|
|
|
280
285
|
You can simply execute such expressions with the alf command line itself (the
|
|
281
286
|
three following invocations return the same result):
|
|
282
287
|
|
|
283
|
-
% alf examples/minus.alf | alf show
|
|
288
|
+
% alf examples/operators/minus.alf | alf show
|
|
284
289
|
% alf show minus
|
|
285
290
|
% alf -e "(restrict :suppliers, lambda{ city != 'Paris' })" | alf show
|
|
286
291
|
|
|
@@ -373,7 +378,7 @@ operators works on relations and return relations), you can use a sub expression
|
|
|
373
378
|
:supplies),
|
|
374
379
|
:cities),
|
|
375
380
|
[:country],
|
|
376
|
-
:which => Agg::
|
|
381
|
+
:which => Agg::collect(:pid),
|
|
377
382
|
:total => Agg::sum{ qty })
|
|
378
383
|
|
|
379
384
|
Of course, complex queries quickly become unreadable that way. But you can always
|
|
@@ -384,30 +389,19 @@ split complex tasks in more simple ones:
|
|
|
384
389
|
supplying = (join with_countries, :supplies)
|
|
385
390
|
(summarize supplying,
|
|
386
391
|
[:country],
|
|
387
|
-
:which => Agg::
|
|
392
|
+
:which => Agg::collect(:pid),
|
|
388
393
|
:total => Agg::sum{ qty })
|
|
389
394
|
|
|
390
395
|
And here is the result !
|
|
391
396
|
|
|
392
|
-
|
|
393
|
-
| :
|
|
394
|
-
|
|
395
|
-
|
|
|
396
|
-
|
|
|
397
|
-
|
|
|
398
|
-
|
|
|
399
|
-
|
|
400
|
-
| | | P3 | | |
|
|
401
|
-
| | | P4 | | |
|
|
402
|
-
| | | P5 | | |
|
|
403
|
-
| | | P6 | | |
|
|
404
|
-
| | +------+ | |
|
|
405
|
-
| France | +------+ | 200 |
|
|
406
|
-
| | | :pid | | |
|
|
407
|
-
| | +------+ | |
|
|
408
|
-
| | | P2 | | |
|
|
409
|
-
| | +------+ | |
|
|
410
|
-
+----------+----------+--------+
|
|
397
|
+
+------+--------+--------------------------+
|
|
398
|
+
| :sid | :total | :which |
|
|
399
|
+
+------+--------+--------------------------+
|
|
400
|
+
| S1 | 1300 | [P1, P2, P3, P4, P5, P6] |
|
|
401
|
+
| S2 | 700 | [P1, P2] |
|
|
402
|
+
| S3 | 200 | [P2] |
|
|
403
|
+
| S4 | 900 | [P2, P4, P5] |
|
|
404
|
+
+------+--------+--------------------------+
|
|
411
405
|
|
|
412
406
|
### Reference API
|
|
413
407
|
|
|
@@ -522,11 +516,11 @@ For example, try the following:
|
|
|
522
516
|
### Recognized data streams/files (.rash files)
|
|
523
517
|
|
|
524
518
|
For educational purposes, 'suppliers' and 'cities' inputs are magically resolved
|
|
525
|
-
as denoting the files examples/suppliers.rash and
|
|
526
|
-
respectively. You'll find other data files:
|
|
527
|
-
resolved magically as well and with which you
|
|
528
|
-
purposes, operands may always be explicit files,
|
|
529
|
-
which datasource files have to be found:
|
|
519
|
+
as denoting the files examples/operators/suppliers.rash and
|
|
520
|
+
examples/operators/cities.rash, respectively. You'll find other data files:
|
|
521
|
+
parts.rash, supplies.rash that are resolved magically as well and with which you
|
|
522
|
+
can play. For non-educational purposes, operands may always be explicit files,
|
|
523
|
+
or you can force the folder in which datasource files have to be found:
|
|
530
524
|
|
|
531
525
|
# The following invocations are equivalent
|
|
532
526
|
% alf restrict /tmp/foo.rash -- "..."
|
|
@@ -541,13 +535,13 @@ operand on standard input if not specific as command argument. For example, the
|
|
|
541
535
|
invocation below is equivalent to the one given above.
|
|
542
536
|
|
|
543
537
|
# display suppliers that live in Paris
|
|
544
|
-
% cat examples/suppliers.rash | alf restrict -- "city == 'Paris'"
|
|
538
|
+
% cat examples/operators/suppliers.rash | alf restrict -- "city == 'Paris'"
|
|
545
539
|
|
|
546
540
|
Similarly, when only one operand is present in invocations of binary operators,
|
|
547
541
|
they read their left operand from standard input. Therefore, the join given in
|
|
548
542
|
previous section can also be written as follows:
|
|
549
543
|
|
|
550
|
-
% cat examples/suppliers.rash | alf join cities
|
|
544
|
+
% cat examples/operators/suppliers.rash | alf join cities
|
|
551
545
|
|
|
552
546
|
The relational algebra is _closed_ under its operators, which means that these
|
|
553
547
|
operators take relations as operands and return a relation. Therefore operator
|
|
@@ -595,7 +589,7 @@ a .yaml file, as follows:
|
|
|
595
589
|
You'll also find .alf files in the examples folder, that contain more complex
|
|
596
590
|
examples in the Ruby functional syntax (see section below).
|
|
597
591
|
|
|
598
|
-
% cat examples/group.alf
|
|
592
|
+
% cat examples/operators/group.alf
|
|
599
593
|
#!/usr/bin/env alf
|
|
600
594
|
(group :supplies, [:pid, :qty], :supplying)
|
|
601
595
|
|
|
@@ -779,7 +773,7 @@ following template for contributions in lib/alf/renderer
|
|
|
779
773
|
third manifesto paper} itself?
|
|
780
774
|
- Also have a look at {http://www.dcs.warwick.ac.uk/~hugh/TTM/Projects.html other
|
|
781
775
|
implementation projects}, especially {http://dbappbuilder.sourceforge.net/Rel.php Rel}
|
|
782
|
-
which provides an implementation of the
|
|
776
|
+
which provides an implementation of the **Tutorial D** language.
|
|
783
777
|
- {https://github.com/dkubb/veritas Dan Kubb's Veritas} project is worth considering
|
|
784
778
|
also in the Ruby community. While very similar to Alf in providing a pure ruby
|
|
785
779
|
algebra implementation, Veritas mostly provides a framework for manipulating
|
data/TODO.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
(rename :suppliers, [:name, :city], :suffix => "_sup")
|
|
5
5
|
(rename :suppliers, [:name, :city], lambda{|name| name.upcase})
|
|
6
6
|
|
|
7
|
-
* WRAP: provide a multi-
|
|
7
|
+
* WRAP: provide a multi-wrapping ability?
|
|
8
8
|
|
|
9
9
|
(wrap (wrap :supplies, [:a, :b], :x), [:x, :c], :y)
|
|
10
10
|
=> (wrap :supplies, :x => [:a, :b], :y => [:x, :c])
|
data/alf.gemspec
CHANGED
|
@@ -30,7 +30,7 @@ Gem::Specification.new do |s|
|
|
|
30
30
|
s.description = "Alf brings the relational algebra both in Shell and in Ruby. In Shell, because \nmanipulating any relation-like data source should be as straightforward as a \none-liner. In Ruby, because I've never understood why programming languages \nprovide data structures like arrays, hashes, sets, trees and graphs but not \n_relations_... Let's stop the segregation ;-)"
|
|
31
31
|
|
|
32
32
|
# The URL of this gem home page (optional)
|
|
33
|
-
s.homepage = "http://
|
|
33
|
+
s.homepage = "http://blambeau.github.com/alf"
|
|
34
34
|
|
|
35
35
|
# Gem publication date (required but auto)
|
|
36
36
|
#
|
|
@@ -124,15 +124,18 @@ Gem::Specification.new do |s|
|
|
|
124
124
|
# for each development dependency. These gems are required for developers
|
|
125
125
|
#
|
|
126
126
|
s.add_development_dependency("rake", "~> 0.9.2")
|
|
127
|
-
s.add_development_dependency("bundler", "~> 1.0")
|
|
128
127
|
s.add_development_dependency("rspec", "~> 2.6.0")
|
|
128
|
+
s.add_development_dependency("wlang", "~> 0.10.2")
|
|
129
129
|
s.add_development_dependency("rcov", "~> 0.9.9")
|
|
130
130
|
s.add_development_dependency("yard", "~> 0.7.2")
|
|
131
|
-
s.add_development_dependency("bluecloth", "~> 2.0
|
|
132
|
-
s.add_development_dependency("
|
|
133
|
-
s.add_development_dependency("
|
|
134
|
-
s.
|
|
135
|
-
s.
|
|
131
|
+
s.add_development_dependency("bluecloth", "~> 2.1.0")
|
|
132
|
+
s.add_development_dependency("redcarpet", "~> 1.17.2")
|
|
133
|
+
s.add_development_dependency("fastercsv", "~> 1.5.4")
|
|
134
|
+
s.add_development_dependency("request-log-analyzer", "~> 1.11.0")
|
|
135
|
+
s.add_development_dependency("sequel", "~> 3.25.0")
|
|
136
|
+
s.add_development_dependency("sqlite3", "~> 1.3.0")
|
|
137
|
+
s.add_dependency("quickl", "~> 0.4.0")
|
|
138
|
+
s.add_dependency("myrrha", "~> 1.2.0")
|
|
136
139
|
|
|
137
140
|
# The version of ruby required by this gem
|
|
138
141
|
#
|
data/alf.noespec
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
template-info:
|
|
2
2
|
name: "ruby"
|
|
3
|
-
version: 1.
|
|
3
|
+
version: 1.5.0
|
|
4
4
|
manifest:
|
|
5
|
+
tasks/spec_test.rake:
|
|
6
|
+
ignore: true
|
|
7
|
+
spec/test___lower__.rb:
|
|
8
|
+
ignore: true
|
|
5
9
|
tasks/unit_test.rake:
|
|
6
10
|
safe-override: false
|
|
11
|
+
tasks/debug_mail.txt:
|
|
12
|
+
safe-override: false
|
|
7
13
|
variables:
|
|
8
14
|
lower:
|
|
9
15
|
alf
|
|
10
16
|
upper:
|
|
11
17
|
Alf
|
|
12
18
|
version:
|
|
13
|
-
0.
|
|
19
|
+
0.10.0
|
|
14
20
|
summary: |-
|
|
15
21
|
Relational Algebra at your fingertips
|
|
16
22
|
description: |-
|
|
@@ -22,17 +28,22 @@ variables:
|
|
|
22
28
|
authors:
|
|
23
29
|
- {name: Bernard Lambeau, email: blambeau@gmail.com}
|
|
24
30
|
links:
|
|
25
|
-
- http://
|
|
31
|
+
- http://blambeau.github.com/alf
|
|
26
32
|
- http://github.com/blambeau/alf
|
|
27
33
|
- http://rubygems.org/gems/alf
|
|
34
|
+
- http://rubydoc.info/gems/alf
|
|
28
35
|
dependencies:
|
|
29
|
-
- {name:
|
|
30
|
-
- {name:
|
|
31
|
-
- {name:
|
|
32
|
-
- {name:
|
|
33
|
-
- {name:
|
|
34
|
-
- {name:
|
|
35
|
-
- {name:
|
|
36
|
-
- {name:
|
|
37
|
-
- {name:
|
|
38
|
-
- {name:
|
|
36
|
+
- {name: quickl, version: "~> 0.4.0", groups: [runtime ]}
|
|
37
|
+
- {name: myrrha, version: "~> 1.2.0", groups: [runtime ]}
|
|
38
|
+
- {name: rake, version: "~> 0.9.2", groups: [test, release]}
|
|
39
|
+
- {name: rspec, version: "~> 2.6.0", groups: [test, release]}
|
|
40
|
+
- {name: wlang, version: "~> 0.10.2", groups: [release ]}
|
|
41
|
+
- {name: rcov, version: "~> 0.9.9", groups: [doc ]}
|
|
42
|
+
- {name: yard, version: "~> 0.7.2", groups: [doc ]}
|
|
43
|
+
- {name: bluecloth, version: "~> 2.1.0", groups: [doc ]}
|
|
44
|
+
- {name: redcarpet, version: "~> 1.17.2", groups: [doc ]}
|
|
45
|
+
- {name: fastercsv, version: "~> 1.5.4", groups: [extra ]}
|
|
46
|
+
- {name: request-log-analyzer, version: "~> 1.11.0", groups: [extra]}
|
|
47
|
+
- {name: sequel, version: "~> 3.25.0", groups: [extra ]}
|
|
48
|
+
- {name: sqlite3, version: "~> 1.3.0", groups: [extra ]}
|
|
49
|
+
|
data/bin/alf
CHANGED
|
@@ -18,10 +18,10 @@ module AlfLauncher
|
|
|
18
18
|
def self.start(argv)
|
|
19
19
|
load
|
|
20
20
|
if ENV["ALF_OPTS"]
|
|
21
|
-
argv =
|
|
21
|
+
argv = Quickl.parse_commandline_args(ENV["ALF_OPTS"]) + argv
|
|
22
22
|
end
|
|
23
23
|
Alf::Command::Main.run(argv, __FILE__)
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
end # module AlfLaucher
|
|
27
|
-
AlfLauncher.start(ARGV)
|
|
27
|
+
AlfLauncher.start(ARGV)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
Executes an .alf file on current environment
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
alf #(command_name) [FILE]
|
|
7
|
+
|
|
8
|
+
OPTIONS
|
|
9
|
+
|
|
10
|
+
#(summarized_options)
|
|
11
|
+
|
|
12
|
+
DESCRIPTION
|
|
13
|
+
|
|
14
|
+
This command executes the .alf file passed as first argument (or what comes
|
|
15
|
+
on standard input) as a alf query to be executed on the current environment.
|
|
16
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
|
|
2
|
+
alf - Relational algebra at your fingertips
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
alf [--version] [--help]
|
|
7
|
+
alf -e '(lispy command)'
|
|
8
|
+
alf [FILE.alf]
|
|
9
|
+
alf [alf opts] OPERATOR [operator opts] ARGS ...
|
|
10
|
+
alf help OPERATOR
|
|
11
|
+
|
|
12
|
+
OPTIONS
|
|
13
|
+
|
|
14
|
+
#(summarized_options)
|
|
15
|
+
|
|
16
|
+
RELATIONAL OPERATORS
|
|
17
|
+
|
|
18
|
+
#(summarized_subcommands relational_operators)
|
|
19
|
+
|
|
20
|
+
EXPERIMENTAL RELATIONAL OPERATORS
|
|
21
|
+
|
|
22
|
+
#(summarized_subcommands experimental_operators)
|
|
23
|
+
|
|
24
|
+
NON-RELATIONAL OPERATORS
|
|
25
|
+
|
|
26
|
+
#(summarized_subcommands non_relational_operators)
|
|
27
|
+
|
|
28
|
+
OTHER NON-RELATIONAL COMMANDS
|
|
29
|
+
|
|
30
|
+
#(summarized_subcommands other_non_relational_commands)
|
|
31
|
+
|
|
32
|
+
See 'alf help COMMAND' for details about a specific command.
|
|
33
|
+
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
Output input tuples through a specific renderer (text, yaml, ...)
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
alf #(command_name) DATASET
|
|
7
|
+
|
|
8
|
+
OPTIONS
|
|
9
|
+
|
|
10
|
+
#(summarized_options)
|
|
11
|
+
|
|
12
|
+
DESCRIPTION
|
|
13
|
+
|
|
14
|
+
When a dataset name is specified as commandline arg, request the
|
|
15
|
+
environment to provide this dataset and prints it. Otherwise, take what
|
|
16
|
+
comes on standard input.
|
|
17
|
+
|
|
18
|
+
Note that this command is not an operator and should not be piped anymore.
|
|
19
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
|
|
2
|
+
Extend its operand with an unique autonumber attribute
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
#(signature)
|
|
7
|
+
|
|
8
|
+
DESCRIPTION
|
|
9
|
+
|
|
10
|
+
This non-relational operator guarantees uniqueness of output tuples by adding
|
|
11
|
+
an attribute called AS whose value is an auto-numbered Integer.
|
|
12
|
+
|
|
13
|
+
If the presence of duplicates was the only "non-relational" aspect of the input,
|
|
14
|
+
the result is a valid relation for which AS is a candidate key.
|
|
15
|
+
|
|
16
|
+
EXAMPLE
|
|
17
|
+
|
|
18
|
+
# Autonumber suppliers with default attribute name
|
|
19
|
+
!(alf autonum suppliers)
|
|
20
|
+
|
|
21
|
+
# Autonumber suppliers with a `unique_id` attribute
|
|
22
|
+
!(alf autonum suppliers -- unique_id)
|
|
23
|
+
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
|
|
2
|
+
Clip input tuples to a subset of attributes
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
#(signature)
|
|
7
|
+
|
|
8
|
+
OPTIONS
|
|
9
|
+
|
|
10
|
+
#(summarized_options)
|
|
11
|
+
|
|
12
|
+
DESCRIPTION
|
|
13
|
+
|
|
14
|
+
This operator clips tuples on attributes whose names are specified in
|
|
15
|
+
ATTRIBUTES. This is similar to the relational PROJECT operator, expect
|
|
16
|
+
that CLIP does not remove duplicates afterwards.
|
|
17
|
+
|
|
18
|
+
Clipping may therefore lead to bags of tuples instead of sets. The result
|
|
19
|
+
is therefore **not** a valid relation unless a candidate key is preserved.
|
|
20
|
+
|
|
21
|
+
With the allbut option, the operator keeps attributes in ATTRIBUTES, instead
|
|
22
|
+
of projecting them away.
|
|
23
|
+
|
|
24
|
+
EXAMPLE
|
|
25
|
+
|
|
26
|
+
# Clip suppliers on `name` and `city`
|
|
27
|
+
!(alf clip suppliers -- name city)
|
|
28
|
+
|
|
29
|
+
# Clip suppliers on all other attributes
|
|
30
|
+
!(alf clip suppliers --allbut -- name city)
|
|
31
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
Remove tuple duplicates
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
#(signature)
|
|
7
|
+
|
|
8
|
+
DESCRIPTION
|
|
9
|
+
|
|
10
|
+
This non-relational operator removes duplicates from its input operand.
|
|
11
|
+
In other words, it converts a bag of tuples to a set of tuples in a
|
|
12
|
+
brute-force manner.
|
|
13
|
+
|
|
14
|
+
If the presence of duplicates was the only "non-relational" aspect of
|
|
15
|
+
the operand, the result is a valid relation.
|
|
16
|
+
|
|
17
|
+
EXAMPLE
|
|
18
|
+
|
|
19
|
+
alf compact suppliers
|
|
20
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
Force default values on missing/nil attributes
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
#(signature)
|
|
7
|
+
|
|
8
|
+
OPTIONS
|
|
9
|
+
|
|
10
|
+
#(summarized_options)
|
|
11
|
+
|
|
12
|
+
DESCRIPTION
|
|
13
|
+
|
|
14
|
+
This non-relational operator rewrites input tuples to ensure that all values
|
|
15
|
+
for attribute names specified in DEFAULTS are present and not nil. Missing or
|
|
16
|
+
nil attributes are replaced by the specified default value.
|
|
17
|
+
|
|
18
|
+
A value specified in DEFAULTS may be any tuple expression. This allows computing
|
|
19
|
+
the default value as an expression on the current tuple.
|
|
20
|
+
|
|
21
|
+
With the strict option, the operator projects resulting tuples on attributes for
|
|
22
|
+
which a default value has been specified. Using the strict mode guarantees that
|
|
23
|
+
the heading of all tuples is the same, and that no nil value ever remains.
|
|
24
|
+
|
|
25
|
+
Note that this operator never removes duplicates. Even in strict mode the result
|
|
26
|
+
might be an invalid relation.
|
|
27
|
+
|
|
28
|
+
EXAMPLE
|
|
29
|
+
|
|
30
|
+
alf defaults suppliers -- country "'Belgium'"
|
|
31
|
+
alf defaults --strict suppliers -- country "'Belgium'"
|
|
32
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
Generate a relation with an auto-numbered attribute
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
#(signature)
|
|
7
|
+
|
|
8
|
+
DESCRIPTION
|
|
9
|
+
|
|
10
|
+
This non-relational operator generates a relation of one attribute called AS,
|
|
11
|
+
whose value is an auto-number ranging from 1 to SIZE, inclusively.
|
|
12
|
+
|
|
13
|
+
EXAMPLE
|
|
14
|
+
|
|
15
|
+
# Default behavior: AS is `num` and SIZE is 10
|
|
16
|
+
!(alf generator)
|
|
17
|
+
|
|
18
|
+
# That you can override
|
|
19
|
+
!(alf generator -- 5 -- id)
|
|
20
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
|
|
2
|
+
Sort input tuples according to an order relation
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
#(signature)
|
|
7
|
+
|
|
8
|
+
DESCRIPTION
|
|
9
|
+
|
|
10
|
+
This non-relational operator sorts input tuples according to ORDERING.
|
|
11
|
+
|
|
12
|
+
This is, of course, a non relational operator as relations are unordered
|
|
13
|
+
sets. It is provided for displaying purposes and normalization of
|
|
14
|
+
non-relational inputs.
|
|
15
|
+
|
|
16
|
+
EXAMPLE
|
|
17
|
+
|
|
18
|
+
# Sort suppliers by name
|
|
19
|
+
!(alf sort suppliers -- name asc)
|
|
20
|
+
|
|
21
|
+
# Sort suppliers by city in descending order, then on name on ascending
|
|
22
|
+
# order
|
|
23
|
+
!(alf sort suppliers -- city desc name asc)
|
|
24
|
+
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
|
|
2
|
+
Relational extension (additional, computed attributes)
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
#(signature)
|
|
7
|
+
|
|
8
|
+
DESCRIPTION
|
|
9
|
+
|
|
10
|
+
This operator extends its operand with new attributes whose value is the result
|
|
11
|
+
of evaluating tuple expressions specified in EXT. The latter are specified as
|
|
12
|
+
(name, expression) pairs.
|
|
13
|
+
|
|
14
|
+
EXAMPLE
|
|
15
|
+
|
|
16
|
+
# Compute a few attributes on suppliers by extension
|
|
17
|
+
!(alf extend supplies -- big "qty > 100" price "qty * 12.2")
|
|
18
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
Relational grouping (relation-valued attributes)
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
#(signature)
|
|
7
|
+
|
|
8
|
+
OPTIONS
|
|
9
|
+
|
|
10
|
+
#(summarized_options)
|
|
11
|
+
|
|
12
|
+
DESCRIPTION
|
|
13
|
+
|
|
14
|
+
This operator groups attributes in ATTRIBUTES as a new, relation-valued
|
|
15
|
+
attribute named AS.
|
|
16
|
+
|
|
17
|
+
With the allbut option, it groups all attributes not specified in ATTRIBUTES
|
|
18
|
+
instead.
|
|
19
|
+
|
|
20
|
+
EXAMPLE
|
|
21
|
+
|
|
22
|
+
# Group pid and qty as a relation-valued attribute names supplying
|
|
23
|
+
!(alf group supplies -- pid qty -- supplying)
|
|
24
|
+
|
|
25
|
+
# Group all but pid ...
|
|
26
|
+
!(alf group supplies --allbut -- pid -- supplying)
|
|
27
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
|
|
2
|
+
Relational intersection (aka a logical and)
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
#(signature)
|
|
7
|
+
|
|
8
|
+
DESCRIPTION
|
|
9
|
+
|
|
10
|
+
This operator computes the relational intersection of its operands. Such
|
|
11
|
+
intersection is simply the set of tuples that appear both in LEFT and in
|
|
12
|
+
RIGHT.
|
|
13
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
Relational join (and cartesian product)
|
|
3
|
+
|
|
4
|
+
SYNOPSIS
|
|
5
|
+
|
|
6
|
+
#(signature)
|
|
7
|
+
|
|
8
|
+
DESCRIPTION
|
|
9
|
+
|
|
10
|
+
This operator computes the (natural) join of its operands.
|
|
11
|
+
|
|
12
|
+
Natural join means that, unlike what is commonly used in SQL, the join is
|
|
13
|
+
performed on common attribute names. You can use the `rename` operator if this
|
|
14
|
+
behavior does not fit your needs.
|
|
15
|
+
|
|
16
|
+
When operands have no attribute in common, this operator naturally "degenerates"
|
|
17
|
+
to a cartesian product.
|
|
18
|
+
|
|
19
|
+
EXAMPLE
|
|
20
|
+
|
|
21
|
+
# Computes natural join of suppliers and supplies (on sid, the only
|
|
22
|
+
# attribute they have in common)
|
|
23
|
+
!(alf join suppliers supplies)
|
|
24
|
+
|
|
25
|
+
# The following example demontrates the cartesian product with a generated
|
|
26
|
+
# relation
|
|
27
|
+
!(alf generator -- 3 -- num | alf join cities)
|