alf 0.12.2 → 0.13.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 (549) hide show
  1. data/CHANGELOG.md +186 -80
  2. data/Gemfile +16 -32
  3. data/Gemfile.lock +35 -34
  4. data/LICENCE.md +1 -1
  5. data/Manifest.txt +7 -9
  6. data/README.md +139 -809
  7. data/alf.gemspec +6 -15
  8. data/alf.noespec +16 -34
  9. data/lib/alf.rb +3 -73
  10. data/lib/alf/loader.rb +3 -3
  11. data/lib/alf/version.rb +2 -2
  12. data/spec/spec_helper.rb +3 -18
  13. data/spec/test_alf.rb +8 -0
  14. data/tasks/test.rake +6 -0
  15. data/test/migrations/test_folder_migration.rb +18 -0
  16. data/test/migrations/test_sequel_migration.rb +34 -0
  17. data/test/seeding/test_seeding.rb +49 -0
  18. data/test/test_alf.rb +8 -0
  19. data/test/test_helpers.rb +24 -0
  20. metadata +54 -952
  21. data/TODO.md +0 -21
  22. data/bin/alf +0 -27
  23. data/doc/commands/exec.md +0 -16
  24. data/doc/commands/help.md +0 -11
  25. data/doc/commands/main.md +0 -33
  26. data/doc/commands/show.md +0 -19
  27. data/doc/operators/non_relational/autonum.md +0 -23
  28. data/doc/operators/non_relational/clip.md +0 -31
  29. data/doc/operators/non_relational/coerce.md +0 -15
  30. data/doc/operators/non_relational/compact.md +0 -20
  31. data/doc/operators/non_relational/defaults.md +0 -32
  32. data/doc/operators/non_relational/generator.md +0 -20
  33. data/doc/operators/non_relational/sort.md +0 -24
  34. data/doc/operators/relational/extend.md +0 -18
  35. data/doc/operators/relational/group.md +0 -27
  36. data/doc/operators/relational/heading.md +0 -20
  37. data/doc/operators/relational/intersect.md +0 -13
  38. data/doc/operators/relational/join.md +0 -28
  39. data/doc/operators/relational/matching.md +0 -24
  40. data/doc/operators/relational/minus.md +0 -12
  41. data/doc/operators/relational/not-matching.md +0 -20
  42. data/doc/operators/relational/project.md +0 -28
  43. data/doc/operators/relational/quota.md +0 -21
  44. data/doc/operators/relational/rank.md +0 -27
  45. data/doc/operators/relational/rename.md +0 -17
  46. data/doc/operators/relational/restrict.md +0 -25
  47. data/doc/operators/relational/summarize.md +0 -25
  48. data/doc/operators/relational/ungroup.md +0 -20
  49. data/doc/operators/relational/union.md +0 -14
  50. data/doc/operators/relational/unwrap.md +0 -20
  51. data/doc/operators/relational/wrap.md +0 -24
  52. data/examples/csv/suppliers.csv +0 -6
  53. data/examples/logs/access.log +0 -1000
  54. data/examples/logs/combined.alf +0 -2
  55. data/examples/logs/hits.alf +0 -14
  56. data/examples/logs/not_found.alf +0 -7
  57. data/examples/logs/robots-cheating.alf +0 -11
  58. data/examples/logs/robots.alf +0 -8
  59. data/examples/operators/autonum.alf +0 -6
  60. data/examples/operators/cities.rash +0 -4
  61. data/examples/operators/clip.alf +0 -3
  62. data/examples/operators/compact.alf +0 -2
  63. data/examples/operators/database.alf +0 -5
  64. data/examples/operators/defaults.alf +0 -3
  65. data/examples/operators/extend.alf +0 -3
  66. data/examples/operators/group.alf +0 -3
  67. data/examples/operators/intersect.alf +0 -4
  68. data/examples/operators/join.alf +0 -2
  69. data/examples/operators/matching.alf +0 -2
  70. data/examples/operators/minus.alf +0 -8
  71. data/examples/operators/not_matching.alf +0 -2
  72. data/examples/operators/nulls.rash +0 -3
  73. data/examples/operators/parts.rash +0 -6
  74. data/examples/operators/project.alf +0 -3
  75. data/examples/operators/pseudo-with.alf +0 -7
  76. data/examples/operators/quota.alf +0 -4
  77. data/examples/operators/rank.alf +0 -4
  78. data/examples/operators/rename.alf +0 -3
  79. data/examples/operators/restrict.alf +0 -2
  80. data/examples/operators/schema.yaml +0 -28
  81. data/examples/operators/sort.alf +0 -4
  82. data/examples/operators/summarize.alf +0 -16
  83. data/examples/operators/suppliers.rash +0 -5
  84. data/examples/operators/supplies.rash +0 -12
  85. data/examples/operators/ungroup.alf +0 -4
  86. data/examples/operators/union.alf +0 -3
  87. data/examples/operators/unwrap.alf +0 -4
  88. data/examples/operators/wrap.alf +0 -2
  89. data/lib/alf-csv/alf/csv.rb +0 -3
  90. data/lib/alf-csv/alf/csv/commons.rb +0 -36
  91. data/lib/alf-csv/alf/csv/reader.rb +0 -33
  92. data/lib/alf-csv/alf/csv/renderer.rb +0 -38
  93. data/lib/alf-engine/alf/engine.rb +0 -25
  94. data/lib/alf-engine/alf/engine/aggregate.rb +0 -44
  95. data/lib/alf-engine/alf/engine/autonum.rb +0 -45
  96. data/lib/alf-engine/alf/engine/cesure.rb +0 -45
  97. data/lib/alf-engine/alf/engine/clip.rb +0 -53
  98. data/lib/alf-engine/alf/engine/coerce.rb +0 -46
  99. data/lib/alf-engine/alf/engine/cog.rb +0 -7
  100. data/lib/alf-engine/alf/engine/compact.rb +0 -26
  101. data/lib/alf-engine/alf/engine/compact/set.rb +0 -23
  102. data/lib/alf-engine/alf/engine/compact/uniq.rb +0 -23
  103. data/lib/alf-engine/alf/engine/concat.rb +0 -25
  104. data/lib/alf-engine/alf/engine/defaults.rb +0 -43
  105. data/lib/alf-engine/alf/engine/filter.rb +0 -41
  106. data/lib/alf-engine/alf/engine/generator.rb +0 -50
  107. data/lib/alf-engine/alf/engine/group.rb +0 -7
  108. data/lib/alf-engine/alf/engine/group/hash.rb +0 -40
  109. data/lib/alf-engine/alf/engine/join.rb +0 -7
  110. data/lib/alf-engine/alf/engine/join/hash.rb +0 -35
  111. data/lib/alf-engine/alf/engine/materialize.rb +0 -8
  112. data/lib/alf-engine/alf/engine/materialize/array.rb +0 -78
  113. data/lib/alf-engine/alf/engine/materialize/hash.rb +0 -122
  114. data/lib/alf-engine/alf/engine/quota.rb +0 -7
  115. data/lib/alf-engine/alf/engine/quota/cesure.rb +0 -46
  116. data/lib/alf-engine/alf/engine/rank.rb +0 -7
  117. data/lib/alf-engine/alf/engine/rank/cesure.rb +0 -48
  118. data/lib/alf-engine/alf/engine/rename.rb +0 -39
  119. data/lib/alf-engine/alf/engine/semi.rb +0 -7
  120. data/lib/alf-engine/alf/engine/semi/hash.rb +0 -39
  121. data/lib/alf-engine/alf/engine/set_attr.rb +0 -46
  122. data/lib/alf-engine/alf/engine/sort.rb +0 -28
  123. data/lib/alf-engine/alf/engine/sort/in_memory.rb +0 -39
  124. data/lib/alf-engine/alf/engine/summarize.rb +0 -8
  125. data/lib/alf-engine/alf/engine/summarize/cesure.rb +0 -51
  126. data/lib/alf-engine/alf/engine/summarize/hash.rb +0 -35
  127. data/lib/alf-engine/alf/engine/ungroup.rb +0 -29
  128. data/lib/alf-engine/alf/engine/unwrap.rb +0 -31
  129. data/lib/alf-engine/alf/engine/wrap.rb +0 -39
  130. data/lib/alf-logs/alf/logs.rb +0 -1
  131. data/lib/alf-logs/alf/logs/reader.rb +0 -98
  132. data/lib/alf-sequel/alf/sequel.rb +0 -2
  133. data/lib/alf-sequel/alf/sequel/environment.rb +0 -61
  134. data/lib/alf-sequel/alf/sequel/iterator.rb +0 -21
  135. data/lib/alf-shell/alf/shell.rb +0 -40
  136. data/lib/alf-shell/alf/shell/command.rb +0 -26
  137. data/lib/alf-shell/alf/shell/command/exec.rb +0 -11
  138. data/lib/alf-shell/alf/shell/command/help.rb +0 -30
  139. data/lib/alf-shell/alf/shell/command/main.rb +0 -136
  140. data/lib/alf-shell/alf/shell/command/main/class_methods.rb +0 -46
  141. data/lib/alf-shell/alf/shell/command/show.rb +0 -63
  142. data/lib/alf-shell/alf/shell/doc_manager.rb +0 -72
  143. data/lib/alf-shell/alf/shell/operator.rb +0 -86
  144. data/lib/alf-yaml/alf/yaml.rb +0 -1
  145. data/lib/alf-yaml/alf/yaml/renderer.rb +0 -22
  146. data/lib/alf/aggregator.rb +0 -51
  147. data/lib/alf/aggregator/avg.rb +0 -39
  148. data/lib/alf/aggregator/class_methods.rb +0 -77
  149. data/lib/alf/aggregator/collect.rb +0 -32
  150. data/lib/alf/aggregator/concat.rb +0 -47
  151. data/lib/alf/aggregator/count.rb +0 -32
  152. data/lib/alf/aggregator/instance_methods.rb +0 -119
  153. data/lib/alf/aggregator/max.rb +0 -32
  154. data/lib/alf/aggregator/min.rb +0 -32
  155. data/lib/alf/aggregator/stddev.rb +0 -25
  156. data/lib/alf/aggregator/sum.rb +0 -32
  157. data/lib/alf/aggregator/variance.rb +0 -45
  158. data/lib/alf/environment.rb +0 -34
  159. data/lib/alf/environment/class_methods.rb +0 -95
  160. data/lib/alf/environment/folder.rb +0 -60
  161. data/lib/alf/environment/instance_methods.rb +0 -26
  162. data/lib/alf/errors.rb +0 -5
  163. data/lib/alf/ext.rb +0 -4
  164. data/lib/alf/ext/relation.rb +0 -4
  165. data/lib/alf/iterator.rb +0 -28
  166. data/lib/alf/iterator/class_methods.rb +0 -20
  167. data/lib/alf/iterator/proxy.rb +0 -27
  168. data/lib/alf/lispy.rb +0 -24
  169. data/lib/alf/lispy/instance_methods.rb +0 -157
  170. data/lib/alf/operator.rb +0 -68
  171. data/lib/alf/operator/binary.rb +0 -21
  172. data/lib/alf/operator/class_methods.rb +0 -82
  173. data/lib/alf/operator/experimental.rb +0 -9
  174. data/lib/alf/operator/instance_methods.rb +0 -29
  175. data/lib/alf/operator/non_relational/autonum.rb +0 -19
  176. data/lib/alf/operator/non_relational/clip.rb +0 -20
  177. data/lib/alf/operator/non_relational/coerce.rb +0 -19
  178. data/lib/alf/operator/non_relational/compact.rb +0 -18
  179. data/lib/alf/operator/non_relational/defaults.rb +0 -22
  180. data/lib/alf/operator/non_relational/generator.rb +0 -20
  181. data/lib/alf/operator/non_relational/sort.rb +0 -19
  182. data/lib/alf/operator/nullary.rb +0 -11
  183. data/lib/alf/operator/relational/extend.rb +0 -19
  184. data/lib/alf/operator/relational/group.rb +0 -21
  185. data/lib/alf/operator/relational/heading.rb +0 -20
  186. data/lib/alf/operator/relational/intersect.rb +0 -18
  187. data/lib/alf/operator/relational/join.rb +0 -18
  188. data/lib/alf/operator/relational/matching.rb +0 -18
  189. data/lib/alf/operator/relational/minus.rb +0 -18
  190. data/lib/alf/operator/relational/not_matching.rb +0 -18
  191. data/lib/alf/operator/relational/project.rb +0 -22
  192. data/lib/alf/operator/relational/quota.rb +0 -23
  193. data/lib/alf/operator/relational/rank.rb +0 -22
  194. data/lib/alf/operator/relational/rename.rb +0 -18
  195. data/lib/alf/operator/relational/restrict.rb +0 -18
  196. data/lib/alf/operator/relational/summarize.rb +0 -27
  197. data/lib/alf/operator/relational/ungroup.rb +0 -19
  198. data/lib/alf/operator/relational/union.rb +0 -20
  199. data/lib/alf/operator/relational/unwrap.rb +0 -19
  200. data/lib/alf/operator/relational/wrap.rb +0 -20
  201. data/lib/alf/operator/signature.rb +0 -233
  202. data/lib/alf/operator/unary.rb +0 -16
  203. data/lib/alf/reader.rb +0 -37
  204. data/lib/alf/reader/alf_file.rb +0 -24
  205. data/lib/alf/reader/class_methods.rb +0 -91
  206. data/lib/alf/reader/instance_methods.rb +0 -97
  207. data/lib/alf/reader/rash.rb +0 -28
  208. data/lib/alf/relation.rb +0 -28
  209. data/lib/alf/relation/class_methods.rb +0 -28
  210. data/lib/alf/relation/instance_methods.rb +0 -119
  211. data/lib/alf/renderer.rb +0 -32
  212. data/lib/alf/renderer/class_methods.rb +0 -58
  213. data/lib/alf/renderer/instance_methods.rb +0 -55
  214. data/lib/alf/renderer/rash.rb +0 -33
  215. data/lib/alf/renderer/text.rb +0 -198
  216. data/lib/alf/tools.rb +0 -15
  217. data/lib/alf/tools/coerce.rb +0 -25
  218. data/lib/alf/tools/miscellaneous.rb +0 -111
  219. data/lib/alf/tools/to_lispy.rb +0 -96
  220. data/lib/alf/tools/to_relation.rb +0 -54
  221. data/lib/alf/tools/to_ruby_literal.rb +0 -31
  222. data/lib/alf/tools/tuple_handle.rb +0 -60
  223. data/lib/alf/types.rb +0 -49
  224. data/lib/alf/types/attr_list.rb +0 -160
  225. data/lib/alf/types/attr_name.rb +0 -66
  226. data/lib/alf/types/boolean.rb +0 -25
  227. data/lib/alf/types/heading.rb +0 -135
  228. data/lib/alf/types/ordering.rb +0 -146
  229. data/lib/alf/types/renaming.rb +0 -97
  230. data/lib/alf/types/size.rb +0 -57
  231. data/lib/alf/types/summarization.rb +0 -138
  232. data/lib/alf/types/tuple_computation.rb +0 -136
  233. data/lib/alf/types/tuple_expression.rb +0 -152
  234. data/lib/alf/types/tuple_predicate.rb +0 -73
  235. data/spec/integration/__database__/group.alf +0 -3
  236. data/spec/integration/__database__/parts.rash +0 -6
  237. data/spec/integration/__database__/suppliers.rash +0 -5
  238. data/spec/integration/__database__/suppliers_csv.csv +0 -6
  239. data/spec/integration/__database__/supplies.rash +0 -12
  240. data/spec/integration/alf/example.rash +0 -1
  241. data/spec/integration/alf/test_Relation.rb +0 -32
  242. data/spec/integration/ext/test_relation.rb +0 -16
  243. data/spec/integration/lispy/test_relation.rb +0 -37
  244. data/spec/integration/lispy/test_run.rb +0 -40
  245. data/spec/integration/lispy/test_tuple.rb +0 -36
  246. data/spec/integration/semantics/test_join.alf +0 -9
  247. data/spec/integration/semantics/test_minus.alf +0 -5
  248. data/spec/integration/semantics/test_project.alf +0 -8
  249. data/spec/integration/semantics/test_rank.alf +0 -34
  250. data/spec/integration/shell/alf/alf.db +0 -0
  251. data/spec/integration/shell/alf/alf_e.cmd +0 -1
  252. data/spec/integration/shell/alf/alf_e.stdout +0 -4
  253. data/spec/integration/shell/alf/alf_env.cmd +0 -1
  254. data/spec/integration/shell/alf/alf_env.stdout +0 -5
  255. data/spec/integration/shell/alf/alf_env_sqlite.cmd +0 -1
  256. data/spec/integration/shell/alf/alf_env_sqlite.stdout +0 -9
  257. data/spec/integration/shell/alf/alf_help.cmd +0 -1
  258. data/spec/integration/shell/alf/alf_help.stdout +0 -69
  259. data/spec/integration/shell/alf/alf_implicit.alf +0 -1
  260. data/spec/integration/shell/alf/alf_implicit_exec.cmd +0 -1
  261. data/spec/integration/shell/alf/alf_implicit_exec.stdout +0 -4
  262. data/spec/integration/shell/alf/alf_r.cmd +0 -1
  263. data/spec/integration/shell/alf/alf_r.stdout +0 -5
  264. data/spec/integration/shell/alf/alf_version.cmd +0 -1
  265. data/spec/integration/shell/alf/alf_version.stdout +0 -2
  266. data/spec/integration/shell/alf/alf_yaml.cmd +0 -1
  267. data/spec/integration/shell/alf/alf_yaml.stdout +0 -22
  268. data/spec/integration/shell/alf/rel.rash +0 -1
  269. data/spec/integration/shell/autonum/autonum_0.cmd +0 -1
  270. data/spec/integration/shell/autonum/autonum_0.stdout +0 -9
  271. data/spec/integration/shell/autonum/autonum_1.cmd +0 -1
  272. data/spec/integration/shell/autonum/autonum_1.stdout +0 -9
  273. data/spec/integration/shell/clip/clip_0.cmd +0 -1
  274. data/spec/integration/shell/clip/clip_0.stdout +0 -9
  275. data/spec/integration/shell/clip/clip_1.cmd +0 -1
  276. data/spec/integration/shell/clip/clip_1.stdout +0 -9
  277. data/spec/integration/shell/coerce/coerce_1.cmd +0 -1
  278. data/spec/integration/shell/coerce/coerce_1.stdout +0 -5
  279. data/spec/integration/shell/compact/compact_0.cmd +0 -1
  280. data/spec/integration/shell/compact/compact_0.stdout +0 -9
  281. data/spec/integration/shell/defaults/defaults_0.cmd +0 -1
  282. data/spec/integration/shell/defaults/defaults_0.stdout +0 -9
  283. data/spec/integration/shell/defaults/defaults_1.cmd +0 -1
  284. data/spec/integration/shell/defaults/defaults_1.stdout +0 -9
  285. data/spec/integration/shell/defaults/defaults_2.cmd +0 -1
  286. data/spec/integration/shell/defaults/defaults_2.stdout +0 -9
  287. data/spec/integration/shell/extend/extend_0.cmd +0 -1
  288. data/spec/integration/shell/extend/extend_0.stdout +0 -16
  289. data/spec/integration/shell/generator/generator_1.cmd +0 -1
  290. data/spec/integration/shell/generator/generator_1.stdout +0 -10
  291. data/spec/integration/shell/generator/generator_2.cmd +0 -1
  292. data/spec/integration/shell/generator/generator_2.stdout +0 -5
  293. data/spec/integration/shell/generator/generator_3.cmd +0 -1
  294. data/spec/integration/shell/generator/generator_3.stdout +0 -5
  295. data/spec/integration/shell/group/group_0.cmd +0 -1
  296. data/spec/integration/shell/group/group_0.stdout +0 -32
  297. data/spec/integration/shell/group/group_1.cmd +0 -1
  298. data/spec/integration/shell/group/group_1.stdout +0 -32
  299. data/spec/integration/shell/help/help_1.cmd +0 -1
  300. data/spec/integration/shell/help/help_1.stdout +0 -24
  301. data/spec/integration/shell/intersect/intersect_0.cmd +0 -1
  302. data/spec/integration/shell/intersect/intersect_0.stdout +0 -9
  303. data/spec/integration/shell/join/join_0.cmd +0 -1
  304. data/spec/integration/shell/join/join_0.stdout +0 -16
  305. data/spec/integration/shell/matching/matching_0.cmd +0 -1
  306. data/spec/integration/shell/matching/matching_0.stdout +0 -8
  307. data/spec/integration/shell/minus/minus_0.cmd +0 -1
  308. data/spec/integration/shell/minus/minus_0.stdout +0 -4
  309. data/spec/integration/shell/not-matching/not-matching_0.cmd +0 -1
  310. data/spec/integration/shell/not-matching/not-matching_0.stdout +0 -5
  311. data/spec/integration/shell/project/project_0.cmd +0 -1
  312. data/spec/integration/shell/project/project_0.stdout +0 -9
  313. data/spec/integration/shell/project/project_1.cmd +0 -1
  314. data/spec/integration/shell/project/project_1.stdout +0 -9
  315. data/spec/integration/shell/quota/quota_0.cmd +0 -1
  316. data/spec/integration/shell/quota/quota_0.stdout +0 -16
  317. data/spec/integration/shell/rank/rank_1.cmd +0 -1
  318. data/spec/integration/shell/rank/rank_1.stdout +0 -10
  319. data/spec/integration/shell/rank/rank_2.cmd +0 -1
  320. data/spec/integration/shell/rank/rank_2.stdout +0 -10
  321. data/spec/integration/shell/rank/rank_3.cmd +0 -1
  322. data/spec/integration/shell/rank/rank_3.stdout +0 -10
  323. data/spec/integration/shell/rank/rank_4.cmd +0 -1
  324. data/spec/integration/shell/rank/rank_4.stdout +0 -6
  325. data/spec/integration/shell/rank/rank_5.cmd +0 -1
  326. data/spec/integration/shell/rank/rank_5.stdout +0 -6
  327. data/spec/integration/shell/rename/rename_0.cmd +0 -1
  328. data/spec/integration/shell/rename/rename_0.stdout +0 -9
  329. data/spec/integration/shell/restrict/restrict_0.cmd +0 -1
  330. data/spec/integration/shell/restrict/restrict_0.stdout +0 -6
  331. data/spec/integration/shell/restrict/restrict_1.cmd +0 -1
  332. data/spec/integration/shell/restrict/restrict_1.stdout +0 -6
  333. data/spec/integration/shell/show/show_base.cmd +0 -1
  334. data/spec/integration/shell/show/show_base.stdout +0 -9
  335. data/spec/integration/shell/show/show_base_sort_1.cmd +0 -1
  336. data/spec/integration/shell/show/show_base_sort_1.stdout +0 -9
  337. data/spec/integration/shell/show/show_base_sort_2.cmd +0 -1
  338. data/spec/integration/shell/show/show_base_sort_2.stdout +0 -9
  339. data/spec/integration/shell/show/show_conflictual.cmd +0 -1
  340. data/spec/integration/shell/show/show_conflictual.stdout +0 -5
  341. data/spec/integration/shell/show/show_csv.cmd +0 -1
  342. data/spec/integration/shell/show/show_csv.stdout +0 -6
  343. data/spec/integration/shell/show/show_ff.cmd +0 -1
  344. data/spec/integration/shell/show/show_ff.stdout +0 -10
  345. data/spec/integration/shell/show/show_rash.cmd +0 -1
  346. data/spec/integration/shell/show/show_rash.stdout +0 -5
  347. data/spec/integration/shell/show/show_rash_pretty.cmd +0 -1
  348. data/spec/integration/shell/show/show_rash_pretty.stdout +0 -30
  349. data/spec/integration/shell/show/show_yaml.cmd +0 -1
  350. data/spec/integration/shell/show/show_yaml.stdout +0 -22
  351. data/spec/integration/shell/sort/sort_0.cmd +0 -1
  352. data/spec/integration/shell/sort/sort_0.stdout +0 -9
  353. data/spec/integration/shell/sort/sort_1.cmd +0 -1
  354. data/spec/integration/shell/sort/sort_1.stdout +0 -9
  355. data/spec/integration/shell/sort/sort_2.cmd +0 -1
  356. data/spec/integration/shell/sort/sort_2.stdout +0 -9
  357. data/spec/integration/shell/sort/sort_3.cmd +0 -1
  358. data/spec/integration/shell/sort/sort_3.stdout +0 -9
  359. data/spec/integration/shell/summarize/summarize_0.cmd +0 -1
  360. data/spec/integration/shell/summarize/summarize_0.stdout +0 -8
  361. data/spec/integration/shell/ungroup/ungroup_0.cmd +0 -1
  362. data/spec/integration/shell/ungroup/ungroup_0.stdout +0 -16
  363. data/spec/integration/shell/union/union_0.cmd +0 -1
  364. data/spec/integration/shell/union/union_0.stdout +0 -9
  365. data/spec/integration/shell/unwrap/unwrap_0.cmd +0 -1
  366. data/spec/integration/shell/unwrap/unwrap_0.stdout +0 -9
  367. data/spec/integration/shell/wrap/wrap_0.cmd +0 -1
  368. data/spec/integration/shell/wrap/wrap_0.stdout +0 -9
  369. data/spec/integration/test_alf.rb +0 -34
  370. data/spec/integration/test_examples.rb +0 -15
  371. data/spec/integration/test_lispy.rb +0 -31
  372. data/spec/integration/test_semantics.rb +0 -40
  373. data/spec/integration/test_shell.rb +0 -47
  374. data/spec/regression/alf_file/__FILE__.alf +0 -2
  375. data/spec/regression/alf_file/suppliers.rash +0 -5
  376. data/spec/regression/alf_file/test___FILE__.rb +0 -17
  377. data/spec/regression/heading/test_heading_with_date.rb +0 -12
  378. data/spec/regression/lispy/test_compile.rb +0 -14
  379. data/spec/regression/logs/apache_combined.log +0 -5
  380. data/spec/regression/logs/test_path_attribute.rb +0 -25
  381. data/spec/regression/relation/test_relation_allbut_all.rb +0 -14
  382. data/spec/regression/relation/test_relation_with_date.rb +0 -12
  383. data/spec/regression/restrict/test_restrict_with_keywords.rb +0 -17
  384. data/spec/shared/a_valid_type_implementation.rb +0 -47
  385. data/spec/shared/a_value.rb +0 -12
  386. data/spec/shared/an_operator_class.rb +0 -36
  387. data/spec/unit/alf-core/aggregator/test_avg.rb +0 -22
  388. data/spec/unit/alf-core/aggregator/test_collect.rb +0 -25
  389. data/spec/unit/alf-core/aggregator/test_concat.rb +0 -31
  390. data/spec/unit/alf-core/aggregator/test_count.rb +0 -17
  391. data/spec/unit/alf-core/aggregator/test_max.rb +0 -23
  392. data/spec/unit/alf-core/aggregator/test_min.rb +0 -23
  393. data/spec/unit/alf-core/aggregator/test_stddev.rb +0 -27
  394. data/spec/unit/alf-core/aggregator/test_sum.rb +0 -23
  395. data/spec/unit/alf-core/aggregator/test_variance.rb +0 -29
  396. data/spec/unit/alf-core/assumptions/test_file.rb +0 -17
  397. data/spec/unit/alf-core/assumptions/test_instance_eval.rb +0 -15
  398. data/spec/unit/alf-core/assumptions/test_scoping.rb +0 -29
  399. data/spec/unit/alf-core/assumptions/test_set.rb +0 -64
  400. data/spec/unit/alf-core/environment/examples/suppliers.rash +0 -5
  401. data/spec/unit/alf-core/environment/test_folder.rb +0 -53
  402. data/spec/unit/alf-core/operator/non_relational/test_autonum.rb +0 -48
  403. data/spec/unit/alf-core/operator/non_relational/test_clip.rb +0 -35
  404. data/spec/unit/alf-core/operator/non_relational/test_coerce.rb +0 -29
  405. data/spec/unit/alf-core/operator/non_relational/test_compact.rb +0 -32
  406. data/spec/unit/alf-core/operator/non_relational/test_defaults.rb +0 -53
  407. data/spec/unit/alf-core/operator/non_relational/test_generator.rb +0 -60
  408. data/spec/unit/alf-core/operator/non_relational/test_sort.rb +0 -60
  409. data/spec/unit/alf-core/operator/relational/test_extend.rb +0 -28
  410. data/spec/unit/alf-core/operator/relational/test_group.rb +0 -39
  411. data/spec/unit/alf-core/operator/relational/test_heading.rb +0 -27
  412. data/spec/unit/alf-core/operator/relational/test_intersect.rb +0 -58
  413. data/spec/unit/alf-core/operator/relational/test_join.rb +0 -36
  414. data/spec/unit/alf-core/operator/relational/test_minus.rb +0 -56
  415. data/spec/unit/alf-core/operator/relational/test_project.rb +0 -62
  416. data/spec/unit/alf-core/operator/relational/test_quota.rb +0 -36
  417. data/spec/unit/alf-core/operator/relational/test_rank.rb +0 -48
  418. data/spec/unit/alf-core/operator/relational/test_rename.rb +0 -26
  419. data/spec/unit/alf-core/operator/relational/test_restrict.rb +0 -45
  420. data/spec/unit/alf-core/operator/relational/test_summarize.rb +0 -44
  421. data/spec/unit/alf-core/operator/relational/test_ungroup.rb +0 -29
  422. data/spec/unit/alf-core/operator/relational/test_union.rb +0 -35
  423. data/spec/unit/alf-core/operator/relational/test_unwrap.rb +0 -26
  424. data/spec/unit/alf-core/operator/relational/test_wrap.rb +0 -26
  425. data/spec/unit/alf-core/operator/signature/test_argv2args.rb +0 -82
  426. data/spec/unit/alf-core/operator/signature/test_collect_on.rb +0 -38
  427. data/spec/unit/alf-core/operator/signature/test_initialize.rb +0 -17
  428. data/spec/unit/alf-core/operator/signature/test_install.rb +0 -56
  429. data/spec/unit/alf-core/operator/signature/test_option_parser.rb +0 -36
  430. data/spec/unit/alf-core/operator/signature/test_parse_args.rb +0 -90
  431. data/spec/unit/alf-core/operator/signature/test_to_lispy.rb +0 -102
  432. data/spec/unit/alf-core/operator/signature/test_to_shell.rb +0 -103
  433. data/spec/unit/alf-core/operator/test_non_relational.rb +0 -20
  434. data/spec/unit/alf-core/operator/test_relational.rb +0 -31
  435. data/spec/unit/alf-core/reader/input.rb +0 -2
  436. data/spec/unit/alf-core/reader/test_alf_file.rb +0 -30
  437. data/spec/unit/alf-core/reader/test_initialize.rb +0 -60
  438. data/spec/unit/alf-core/reader/test_looks_a_path.rb +0 -20
  439. data/spec/unit/alf-core/reader/test_rash.rb +0 -31
  440. data/spec/unit/alf-core/relation/test_coerce.rb +0 -53
  441. data/spec/unit/alf-core/relation/test_inspect.rb +0 -20
  442. data/spec/unit/alf-core/relation/test_relops.rb +0 -55
  443. data/spec/unit/alf-core/relation/test_to_a.rb +0 -41
  444. data/spec/unit/alf-core/renderer/test_initialize.rb +0 -60
  445. data/spec/unit/alf-core/test_aggregator.rb +0 -58
  446. data/spec/unit/alf-core/test_environment.rb +0 -30
  447. data/spec/unit/alf-core/test_operator.rb +0 -16
  448. data/spec/unit/alf-core/test_reader.rb +0 -40
  449. data/spec/unit/alf-core/test_relation.rb +0 -75
  450. data/spec/unit/alf-core/test_renderer.rb +0 -53
  451. data/spec/unit/alf-core/text/test_cell.rb +0 -35
  452. data/spec/unit/alf-core/text/test_row.rb +0 -30
  453. data/spec/unit/alf-core/text/test_table.rb +0 -39
  454. data/spec/unit/alf-core/tools/test_class_name.rb +0 -16
  455. data/spec/unit/alf-core/tools/test_coalesce.rb +0 -19
  456. data/spec/unit/alf-core/tools/test_coerce.rb +0 -16
  457. data/spec/unit/alf-core/tools/test_ruby_case.rb +0 -16
  458. data/spec/unit/alf-core/tools/test_to_lispy.rb +0 -145
  459. data/spec/unit/alf-core/tools/test_to_relation.rb +0 -39
  460. data/spec/unit/alf-core/tools/test_to_ruby_literal.rb +0 -10
  461. data/spec/unit/alf-core/tools/test_tuple_handle.rb +0 -52
  462. data/spec/unit/alf-core/tools/test_tuple_heading.rb +0 -15
  463. data/spec/unit/alf-core/tools/test_varargs.rb +0 -19
  464. data/spec/unit/alf-core/types/test_attr_list.rb +0 -188
  465. data/spec/unit/alf-core/types/test_attr_name.rb +0 -78
  466. data/spec/unit/alf-core/types/test_boolean.rb +0 -42
  467. data/spec/unit/alf-core/types/test_class_methods.rb +0 -24
  468. data/spec/unit/alf-core/types/test_heading.rb +0 -146
  469. data/spec/unit/alf-core/types/test_ordering.rb +0 -185
  470. data/spec/unit/alf-core/types/test_renaming.rb +0 -72
  471. data/spec/unit/alf-core/types/test_size.rb +0 -74
  472. data/spec/unit/alf-core/types/test_summarization.rb +0 -95
  473. data/spec/unit/alf-core/types/test_tuple_computation.rb +0 -96
  474. data/spec/unit/alf-core/types/test_tuple_expression.rb +0 -122
  475. data/spec/unit/alf-core/types/test_tuple_predicate.rb +0 -108
  476. data/spec/unit/alf-csv/input.csv +0 -3
  477. data/spec/unit/alf-csv/test_reader.rb +0 -66
  478. data/spec/unit/alf-csv/test_renderer.rb +0 -73
  479. data/spec/unit/alf-engine/compact/test_set.rb +0 -33
  480. data/spec/unit/alf-engine/compact/test_uniq.rb +0 -33
  481. data/spec/unit/alf-engine/group/test_hash.rb +0 -34
  482. data/spec/unit/alf-engine/join/test_hash.rb +0 -55
  483. data/spec/unit/alf-engine/materialize/test_array.rb +0 -28
  484. data/spec/unit/alf-engine/materialize/test_hash.rb +0 -76
  485. data/spec/unit/alf-engine/quota/test_cesure.rb +0 -34
  486. data/spec/unit/alf-engine/rank/test_cesure.rb +0 -47
  487. data/spec/unit/alf-engine/semi/test_hash.rb +0 -58
  488. data/spec/unit/alf-engine/sort/test_in_memory.rb +0 -32
  489. data/spec/unit/alf-engine/summarize/test_cesure.rb +0 -36
  490. data/spec/unit/alf-engine/summarize/test_hash.rb +0 -36
  491. data/spec/unit/alf-engine/test_aggregate.rb +0 -26
  492. data/spec/unit/alf-engine/test_autonum.rb +0 -24
  493. data/spec/unit/alf-engine/test_clip.rb +0 -34
  494. data/spec/unit/alf-engine/test_coerce.rb +0 -35
  495. data/spec/unit/alf-engine/test_compact.rb +0 -33
  496. data/spec/unit/alf-engine/test_concat.rb +0 -38
  497. data/spec/unit/alf-engine/test_defaults.rb +0 -37
  498. data/spec/unit/alf-engine/test_filter.rb +0 -23
  499. data/spec/unit/alf-engine/test_generator.rb +0 -25
  500. data/spec/unit/alf-engine/test_rename.rb +0 -24
  501. data/spec/unit/alf-engine/test_set_attr.rb +0 -38
  502. data/spec/unit/alf-engine/test_sort.rb +0 -32
  503. data/spec/unit/alf-engine/test_ungroup.rb +0 -28
  504. data/spec/unit/alf-engine/test_unwrap.rb +0 -20
  505. data/spec/unit/alf-engine/test_wrap.rb +0 -26
  506. data/spec/unit/alf-logs/apache_combined.log +0 -5
  507. data/spec/unit/alf-logs/postgresql.log +0 -29
  508. data/spec/unit/alf-logs/test_reader.rb +0 -57
  509. data/spec/unit/alf-sequel/alf.db +0 -0
  510. data/spec/unit/alf-sequel/test_environment.rb +0 -74
  511. data/spec/unit/alf-shell/doc_manager/dynamic.md +0 -1
  512. data/spec/unit/alf-shell/doc_manager/example.md +0 -1
  513. data/spec/unit/alf-shell/doc_manager/example_1.txt +0 -11
  514. data/spec/unit/alf-shell/doc_manager/static.md +0 -1
  515. data/spec/unit/alf-shell/doc_manager/test_call.rb +0 -48
  516. data/spec/unit/alf-shell/main/test_class_methods.rb +0 -44
  517. data/spec/unit/alf-shell/operator/test_autonum.rb +0 -28
  518. data/spec/unit/alf-shell/operator/test_clip.rb +0 -29
  519. data/spec/unit/alf-shell/operator/test_coerce.rb +0 -21
  520. data/spec/unit/alf-shell/operator/test_compact.rb +0 -16
  521. data/spec/unit/alf-shell/operator/test_defaults.rb +0 -29
  522. data/spec/unit/alf-shell/operator/test_extend.rb +0 -21
  523. data/spec/unit/alf-shell/operator/test_generator.rb +0 -37
  524. data/spec/unit/alf-shell/operator/test_group.rb +0 -32
  525. data/spec/unit/alf-shell/operator/test_heading.rb +0 -16
  526. data/spec/unit/alf-shell/operator/test_intersect.rb +0 -18
  527. data/spec/unit/alf-shell/operator/test_join.rb +0 -18
  528. data/spec/unit/alf-shell/operator/test_matching.rb +0 -18
  529. data/spec/unit/alf-shell/operator/test_minus.rb +0 -18
  530. data/spec/unit/alf-shell/operator/test_not_matching.rb +0 -18
  531. data/spec/unit/alf-shell/operator/test_project.rb +0 -38
  532. data/spec/unit/alf-shell/operator/test_quota.rb +0 -23
  533. data/spec/unit/alf-shell/operator/test_rank.rb +0 -30
  534. data/spec/unit/alf-shell/operator/test_rename.rb +0 -21
  535. data/spec/unit/alf-shell/operator/test_restrict.rb +0 -35
  536. data/spec/unit/alf-shell/operator/test_sort.rb +0 -49
  537. data/spec/unit/alf-shell/operator/test_summarize.rb +0 -30
  538. data/spec/unit/alf-shell/operator/test_ungroup.rb +0 -28
  539. data/spec/unit/alf-shell/operator/test_union.rb +0 -18
  540. data/spec/unit/alf-shell/operator/test_unwrap.rb +0 -28
  541. data/spec/unit/alf-shell/operator/test_wrap.rb +0 -30
  542. data/tasks/clean.rake +0 -3
  543. data/tasks/debug_mail.rake +0 -75
  544. data/tasks/debug_mail.txt +0 -18
  545. data/tasks/gh-pages.rake +0 -68
  546. data/tasks/integration_test.rake +0 -43
  547. data/tasks/regression_test.rake +0 -44
  548. data/tasks/unit_test.rake +0 -44
  549. data/tasks/yard.rake +0 -51
@@ -1,45 +1,46 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- backports (2.6.1)
5
- bluecloth (2.2.0)
6
- diff-lcs (1.1.3)
7
- fastercsv (1.5.4)
8
- highline (1.6.11)
9
- myrrha (1.2.2)
4
+ alf-core (0.13.0)
5
+ domain (~> 1.0)
6
+ myrrha (~> 3.0)
7
+ path (~> 1.3)
8
+ sexpr (~> 0.5.1)
9
+ alf-sequel (0.13.0)
10
+ alf-core (~> 0.13.0)
11
+ sequel (~> 3.48)
12
+ alf-shell (0.13.1)
13
+ alf-core (~> 0.13.0)
14
+ quickl (~> 0.4.3)
15
+ diff-lcs (1.2.4)
16
+ domain (1.0.0)
17
+ myrrha (3.0.0)
18
+ domain (~> 1.0)
19
+ path (1.3.1)
20
+ pg (0.14.1)
10
21
  quickl (0.4.3)
11
- rake (0.9.2.2)
12
- redcarpet (2.1.0)
13
- request-log-analyzer (1.11.1)
14
- rspec (2.8.0)
15
- rspec-core (~> 2.8.0)
16
- rspec-expectations (~> 2.8.0)
17
- rspec-mocks (~> 2.8.0)
18
- rspec-core (2.8.0)
19
- rspec-expectations (2.8.0)
20
- diff-lcs (~> 1.1.2)
21
- rspec-mocks (2.8.0)
22
- sequel (3.33.0)
23
- sqlite3 (1.3.5)
24
- wlang (0.10.2)
25
- yard (0.7.5)
22
+ rake (10.1.0)
23
+ rspec (2.14.1)
24
+ rspec-core (~> 2.14.0)
25
+ rspec-expectations (~> 2.14.0)
26
+ rspec-mocks (~> 2.14.0)
27
+ rspec-core (2.14.4)
28
+ rspec-expectations (2.14.0)
29
+ diff-lcs (>= 1.1.3, < 2.0)
30
+ rspec-mocks (2.14.1)
31
+ sequel (3.48.0)
32
+ sexpr (0.5.1)
33
+ sqlite3 (1.3.7)
26
34
 
27
35
  PLATFORMS
28
36
  ruby
29
37
 
30
38
  DEPENDENCIES
31
- backports (~> 2.6)
32
- bluecloth (~> 2.2.0)
33
- fastercsv (~> 1.5.4)
34
- highline (~> 1.6.2)
39
+ alf-core (~> 0.13.0)
40
+ alf-sequel (~> 0.13.0)
41
+ alf-shell (~> 0.13.1)
35
42
  jdbc-sqlite3 (~> 3.7)
36
- myrrha (~> 1.2.1)
37
- quickl (~> 0.4.2)
38
- rake (~> 0.9.2)
39
- redcarpet (~> 2.1.0)
40
- request-log-analyzer (~> 1.11.0)
41
- rspec (~> 2.8.0)
42
- sequel (~> 3.30)
43
+ pg (~> 0.14)
44
+ rake (~> 10.1)
45
+ rspec (~> 2.14)
43
46
  sqlite3 (~> 1.3)
44
- wlang (~> 0.10.2)
45
- yard (~> 0.7.2)
data/LICENCE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # The MIT Licence
2
2
 
3
- Copyright (c) 2011 - Bernard Lambeau & The University of Louvain (Belgium)
3
+ Copyright (c) 2013 - Bernard Lambeau
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
@@ -1,17 +1,15 @@
1
- bin/**/*
2
- doc/commands/**/*
3
- doc/operators/**/*
4
- examples/**/*
5
- lib/**/*
6
- spec/**/*
7
- tasks/**/*
8
- Rakefile
9
1
  alf.gemspec
10
2
  alf.noespec
3
+ .gemtest
11
4
  CHANGELOG.md
12
5
  Gemfile
13
6
  Gemfile.lock
7
+ bin/**/*
8
+ lib/**/*
14
9
  LICENCE.md
15
10
  Manifest.txt
11
+ Rakefile
16
12
  README.md
17
- TODO.md
13
+ spec/**/*
14
+ tasks/**/*
15
+ test/**/*
data/README.md CHANGED
@@ -1,567 +1,27 @@
1
- # Alf - Relational Algebra at your fingertips (version 0.10.0)
1
+ # Alf
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/blambeau/alf.png)](http://travis-ci.org/blambeau/alf)
4
- [![Dependency Status](https://gemnasium.com/blambeau/alf.png)](https://gemnasium.com/blambeau/alf)
3
+ Relational Algebra at your fingertips
5
4
 
6
- ## Description
5
+ [![Build Status](https://secure.travis-ci.org/alf-tool/alf.png)](http://travis-ci.org/alf-tool/alf)
6
+ [![Dependency Status](https://gemnasium.com/alf-tool/alf.png)](https://gemnasium.com/alf-tool/alf)
7
7
 
8
- ### What & Why
8
+ ## Links
9
9
 
10
- Alf brings the relational algebra both in Shell and in Ruby. In Shell, because
11
- manipulating any relation-like data source should be as straightforward as a
12
- one-liner. In Ruby, because I've never understood why programming languages
13
- provide data structures like arrays, hashes, sets, trees and graphs but not
14
- _relations_... Let's stop the segregation ;-)
10
+ * [Official documentation](http://blambeau.github.com/alf)
11
+ * [Source and Issues](http://github.com/alf-tool/alf)
12
+ * [Relational basics as needed](http://www.revision-zero.org/relational-basics-2)
15
13
 
16
- ### Install
14
+ ## What & Why
17
15
 
18
- % [sudo] gem install alf [fastercsv, ...]
19
- % alf --help
20
-
21
- ### Bundler & Require
22
-
23
- # API is not considered stable enough for now, please use
24
- gem "alf", "= 0.10.0"
25
-
26
- # The following should not break your code, but is a bit less safe,
27
- # until 1.0.0 has been reached
28
- gem "alf", "~> 0.10.0"
29
-
30
- ### Links
31
-
32
- * http://blambeau.github.com/alf
33
- * http://rubydoc.info/gems/alf
34
- * http://github.com/blambeau/alf
35
- * http://rubygems.org/gems/alf
36
-
37
- ### Quick overview
38
-
39
- Alf is a commandline tool and Ruby library to manipulate data with all the power
40
- of a truly relational algebra approach. Objectives behind Alf are manifold:
41
-
42
- * Pragmatically, Alf aims at being a useful commandline executable for manipulating
43
- relational-like data: database records, csv files, or **whatever can be interpreted
44
- as (the physical encoding of) a relation**. See 'alf --help' for the list of
45
- available commands and implemented relational operators.
46
-
47
- % alf restrict suppliers -- "city == 'London'" | alf join cities
48
-
49
- * Alf is also a 100% Ruby relational algebra implementation shipped with a simple
50
- to use, powerful, functional DSL for compiling and evaluating relational queries.
51
- Alf is not limited to simple scalar values, but admits values of arbitrary
52
- complexity (under a few requirements about their implementation, see next
53
- section). See 'alf --help' as well as .alf files in the examples directory
54
- for syntactic examples.
55
-
56
- Alf.lispy.evaluate {
57
- (join (restrict :suppliers, lambda{ city == 'London' }), :cities)
58
- }
59
-
60
- In addition to this functional syntax, Alf comes bundled with an in-memory
61
- Relation data structure that provides an object-oriented way of manipulating
62
- relations in simplest cases:
63
-
64
- suppliers = Alf::Relation[
65
- {:sid => 'S1', :name => 'Smith', :status => 20, :city => 'London'},
66
- {:sid => 'S2', :name => 'Jones', :status => 10, :city => 'Paris'},
67
- {:sid => 'S3', :name => 'Blake', :status => 30, :city => 'Paris'},
68
- {:sid => 'S4', :name => 'Clark', :status => 20, :city => 'London'},
69
- {:sid => 'S5', :name => 'Adams', :status => 30, :city => 'Athens'},
70
- ]
71
- cities = ...
72
- puts suppliers.restrict(lambda{ city == 'London' }).join(cities)
73
-
74
- * Alf is also an educational tool, that I've written to draw people attention
75
- about the ill-known relational theory (and ill-represented by SQL). The tool
76
- is largely inspired from **Tutorial D**, the tutorial language of Chris Date and
77
- Hugh Darwen in their books, more specifically in
78
- {http://www.thethirdmanifesto.com/ *The Third Manifesto* (TTM)}.
79
- However, Alf only provides an overview of the relational _algebra_ defined
80
- there (Alf is neither a relational _database_, nor a relational _language_).
81
- I hope that people (especially talented developers) will be sufficiently
82
- enticed by features shown here to open that book, read it more deeply, and
83
- implement new stuff around Date & Darwen's vision. Have a look at the result of
84
- the following query for the kind of things that you'll never ever have in SQL
85
- (see also 'alf help quota', 'alf help wrap', 'alf help group', ...):
86
-
87
- % alf --text summarize supplies -- sid -- total "sum{ qty }" which "collect{ pid }"
88
-
89
- * Last, but not least, Alf is an attempt to help me test some research ideas and
90
- communicate about them with people that already know (all or part) of the TTM
91
- vision of relational theory. These people include members of the TTM mailing
92
- list as well as other people implementing some of the TTM ideas (see
93
- {https://github.com/dkubb/veritas Dan Kubb's Veritas project} for example). For
94
- this reason, specific features and/or operators are mine, should be considered
95
- 'research work in progress', and used with care because not necessarily in
96
- conformance with the TTM.
97
-
98
- % alf --text quota supplies -- sid -- qty -- pos "count()"
99
-
100
- ## Overview of relational theory
101
-
102
- We quickly recall relational theory in this section, as described in the TTM
103
- book. Readers not familiar with Date and Darwen's vision of relational theory
104
- should probably read this section, even if fluent in SQL. Others may probably
105
- skip this section. A quick test?
106
-
107
- > _A relation is a value, precisely a set of tuples, which are themselves values.
108
- Therefore, a relation is immutable, not ordered, does not contain duplicates,
109
- and does not have null/nil attributes._
110
-
111
- Familiar? Skip. Otherwise, read on.
112
-
113
- ### The example database
114
-
115
- This README file shows a lot of examples built on top of the following suppliers
116
- & parts database (almost identical to the original version in C. J. Date's database
117
- books). By default, the alf command line is wired to this embedded example. All
118
- examples shown here should therefore work immediately, if you want to reproduce
119
- them!
120
-
121
- % alf show database
122
-
123
- +-------------------------------------+-------------------------------------------------+-------------------------+------------------------+
124
- | :suppliers | :parts | :cities | :supplies |
125
- +-------------------------------------+-------------------------------------------------+-------------------------+------------------------+
126
- | +------+-------+---------+--------+ | +------+-------+--------+------------+--------+ | +----------+----------+ | +------+------+------+ |
127
- | | :sid | :name | :status | :city | | | :pid | :name | :color | :weight | :city | | | :city | :country | | | :sid | :pid | :qty | |
128
- | +------+-------+---------+--------+ | +------+-------+--------+------------+--------+ | +----------+----------+ | +------+------+------+ |
129
- | | S1 | Smith | 20 | London | | | P1 | Nut | Red | 12.0000000 | London | | | London | England | | | S1 | P1 | 300 | |
130
- | | S2 | Jones | 10 | Paris | | | P2 | Bolt | Green | 17.0000000 | Paris | | | Paris | France | | | S1 | P2 | 200 | |
131
- | | S3 | Blake | 30 | Paris | | | P3 | Screw | Blue | 17.0000000 | Oslo | | | Athens | Greece | | | S1 | P3 | 400 | |
132
- | | S4 | Clark | 20 | London | | | P4 | Screw | Red | 14.0000000 | London | | | Brussels | Belgium | | | S1 | P4 | 200 | |
133
- | | S5 | Adams | 30 | Athens | | | P5 | Cam | Blue | 12.0000000 | Paris | | +----------+----------+ | | S1 | P5 | 100 | |
134
- | +------+-------+---------+--------+ | | P6 | Cog | Red | 19.0000000 | London | | | | S1 | P6 | 100 | |
135
- | | +------+-------+--------+------------+--------+ | | | S2 | P1 | 300 | |
136
- | | | | | S2 | P2 | 400 | |
137
- | | | | | S3 | P2 | 200 | |
138
- | | | | | S4 | P2 | 200 | |
139
- | | | | | S4 | P4 | 300 | |
140
- | | | | | S4 | P5 | 400 | |
141
- | | | | +------+------+------+ |
142
- +-------------------------------------+-------------------------------------------------+-------------------------+------------------------+
143
-
144
- Many people think that relational databases are necessary 'flat', that they are
145
- necessarily limited to simple scalar values put in two dimension tables. This is
146
- wrong; most SQL databases are indeed 'flat', but _relations_ (in the mathematical
147
- sense of the relational theory) are not! Look, **the example above is a relation!**;
148
- that 'contains' other relations as particular values, which, in turn, could
149
- 'contain' relations or any other 'simple' or more 'complex' value... This is not
150
- "flat" at all, after all :-)
151
-
152
- ### Types and Values
153
-
154
- To understand what is a relation exactly, one needs to remember elementary
155
- notions of set theory and the concepts of _type_ and _value_.
156
-
157
- * A _type_ is a finite set of values; it is not particularly ordered and, being
158
- a set, it does never contain two values which are equal (any type is necessarily
159
- accompanied with an equality operator, denoted here by '==').
160
-
161
- * A _value_ is **immutable** (you cannot 'change' a value, in any way), has no
162
- localization in time and space, and is always typed (that is, it is always
163
- accompanied by some identification of the type it belongs to).
164
-
165
- As you can see, _type_ and _value_ are not the same concepts as _class_ and
166
- _object_, which you are probably more familiar with. Alf considers that the
167
- latter are _implementations_ of the former. Alf assumes _valid_ implementations
168
- (equality and hash methods must be correct) and _valid_ usage (objects used for
169
- representing values are kept immutable in practice). Alf _assumes_ this, but
170
- does not _enforces_ it: it is your responsibility to use Alf in conformance with
171
- these preconditions. That being said, if you want **arrays, colors, ranges, or
172
- whatever in your relations**, just do it! You can even join on them, restrict on
173
- them, summarize on them, and so on:
174
-
175
- % alf extend suppliers -- chars "name.chars.to_a" | alf --text restrict -- "chars.last == 's'"
176
-
177
- +------+-------+---------+--------+-----------------+
178
- | :sid | :name | :status | :city | :chars |
179
- +------+-------+---------+--------+-----------------+
180
- | S2 | Jones | 10 | Paris | [J, o, n, e, s] |
181
- | S5 | Adams | 30 | Athens | [A, d, a, m, s] |
182
- +------+-------+---------+--------+-----------------+
183
-
184
- A last, very important word about values. **Null/nil is not a value**. Strictly
185
- speaking therefore, you may not use null/nil inside your data files or datasources
186
- representing relations. That being said, Alf provides specific support for handling
187
- them, because they appear in today's databases in practice and that Alf aims at
188
- being a tool that helps you tackling _practical_ problems. See the section with
189
- title "Why is Alf Exactly?" later.
190
-
191
- ### Tuples and Relations
192
-
193
- Tuples (aka records) and relations are values as well, which explains why you
194
- can have them inside relations!
195
-
196
- * Logically speaking, a tuple is a set of (attribute name, attribute value)
197
- pairs. Moreover, it does not contain two attributes with the same name and is
198
- **not particularly ordered**. Also, **a tuple is a _value_, and is therefore
199
- immutable**. Last, but not least, a tuple **does not admit nulls/nils**. Tuples
200
- in Alf are simply implemented with ruby hashes, taken as tuple implementations.
201
- Not all hashes are valid tuple implementations, of course (those containing nil
202
- are not, for example). Alf _assumes_ valid tuples, but does not _enforce_ this
203
- precondition. It's up to you to use Alf the right way! No support is or will
204
- ever be provided for ordering tuple attributes. However, as hashes are ordered
205
- in Ruby 1.9, Alf implements a best effort strategy to keep a friendly ordering
206
- when rendering tuples and relations. This is a very good practical reason for
207
- migrating to ruby 1.9 if not already done!
208
-
209
- {:sid => "S1", :name => "Smith", :status => 20, :city => "London"}
210
-
211
- * A _relation_ is a set of tuples. Being a set, a relation does **never contain
212
- duplicates** (unlike SQL that works on bags, not on sets) and is **not
213
- particularly ordered**. Moreover, all tuples of a relation must have the same
214
- _heading_, that is, the same set of attribute (name, type) pairs. Also, **a
215
- relation is a _value_, is therefore immutable** and **does not admit null/nil**.
216
-
217
- Alf is mainly an implementation of relational algebra (see section below). The
218
- implemented operators consider any Iterator of tuples as potentially valid
219
- operand. In addition Alf provides a Relation ruby class, that acts as an
220
- in-memory data structure that provides an Object-Oriented API to call operators
221
- (see "Interfacing Alf in Ruby" below).
222
-
223
- ### Relational Algebra
224
-
225
- In classical algebra, you can make computations like <code>(5 + 2) - 3</code>.
226
- In relational algebra, you can make similar things on relations. Alf uses an
227
- infix, functional programming-oriented syntax for algebra expressions:
228
-
229
- (minus (union :suppliers, xxx), yyy)
230
-
231
- All relational operators take relation operands in input and return a relation
232
- as output. We say that the relational algebra is _closed_ under its operators.
233
- In practice, it means that operands may always be sub-expressions, **always**.
234
-
235
- (minus (union (restrict :suppliers, lambda{ zzz }), xxx), yyy)
236
-
237
- In shell, the closure property means that you can pipe alf invocations the way
238
- you want! The same query, in shell:
239
-
240
- alf restrict suppliers -- "zzz" | alf union xxx | alf minus yyy
241
-
242
- ## What is Alf exactly?
243
-
244
- *The Third Manifesto* defines a series of prescriptions, proscriptions and very
245
- strong suggestions for designing a truly relational _language_, called a _D_,
246
- as an alternative to SQL for managing relational databases. This is far behind
247
- my objective with Alf, as it does not touch at database issues at all (persistence,
248
- transactions, and so on.) and don't actually define a programming language (only
249
- a small functional ruby DSL).
250
-
251
- Alf must simply be interpreted as a ruby library implementing (a variant of)
252
- Date and Darwen's relational algebra. This library is designed as a set of operator
253
- implementations, that work as tuple iterators taking other tuple iterators as
254
- input. Under the pre-condition that you provide them _valid_ tuple iterators as
255
- input (no duplicates, no nil, + other preconditions on an operator basis), the
256
- result is a valid iterator as well. Unless explicitely stated otherwise, any
257
- behavior observed when not respecting these preconditions, even an interesting
258
- behavior, is not guaranteed and might change with tiny version changes (see
259
- section about versioning policy at the end of this file).
260
-
261
- ### The command line utility
262
-
263
- #
264
- # Provided that suppliers and cities are valid relation representations
265
- # [something similar]
266
- #
267
- % alf restrict suppliers -- "city == 'London'" | alf join cities
268
-
269
- # the resulting stream is a valid relation representation in the output
270
- # stream format that you have selected (.rash by default). It can therefore
271
- # be piped to another alf shell invocation, or saved to a file and re-read
272
- # later (under the assumption that input and output data formats match, or
273
- # course). [Something similar about responsibility and bug].
274
-
275
- If you take a look at .alf example files, you'll find functional ruby expressions
276
- like the following (called Lispy expressions):
277
-
278
- % cat examples/operators/minus.alf
279
-
280
- # Give all suppliers, except those living in Paris
281
- (minus :suppliers,
282
- (restrict :suppliers, lambda{ city == 'Paris' }))
283
-
284
- # This is a contrived example for illustrating minus, as the
285
- # following is equivalent
286
- (restrict :suppliers, lambda{ city != 'Paris' })
287
-
288
- You can simply execute such expressions with the alf command line itself (the
289
- three following invocations return the same result):
290
-
291
- % alf examples/operators/minus.alf | alf show
292
- % alf show minus
293
- % alf -e "(restrict :suppliers, lambda{ city != 'Paris' })" | alf show
294
-
295
- Symbols are magically resolved from the environment, which is wired to the
296
- examples by default. See the dedicated sections below to update this behavior
297
- to your needs.
298
-
299
- ### The algebra compiler
300
-
301
- #
302
- # Provided that :suppliers and :cities are valid relation representations
303
- # (under the responsibility shared by you and the Reader and Environment
304
- # subclasses you use -- see later), then,
305
- #
306
- op = Alf.lispy.compile {
307
- (join (restrict :suppliers, lambda{ city == 'London' }), :cities)
308
- }
309
-
310
- # op is a thread-safe Enumerable of tuples, that can be taken as a valid
311
- # relation representation. It can therefore be used as the input operand
312
- # of any other expression. This is under Alf's responsibility, and any
313
- # failure must be considered a bug!
314
-
315
- ### The Relation data structure
316
-
317
- In addition, Alf is bundled with an in-memory Relation data structure that
318
- provided a more abstract API for manipulating relations in simple cases (the
319
- rules are the same about pre and post-conditions):
320
-
321
- # The query above can be done as follows. Note that relations are always
322
- # loaded in memory here!
323
- suppliers = Alf::Relation[ ... ]
324
- cities = Alf::Relation[ ... ]
325
- suppliers.restrict(lambda{ city == 'London' }).
326
- join(cities)
327
- # => Alf::Relation[ ... ]
328
-
329
- All relational operators have an instance method equivalent on the Alf::Relation
330
- class. Semantically, the receiver object is simply the first operand of the
331
- functional call, as illustrated above.
332
-
333
- ### Where do relations come from?
334
-
335
- Relation literals can simply be written as follows:
336
-
337
- suppliers = Alf::Relation[
338
- {:sid => 'S1', :name => 'Smith', :status => 20, :city => 'London'},
339
- {:sid => 'S2', :name => 'Jones', :status => 10, :city => 'Paris'},
340
- {:sid => 'S3', :name => 'Blake', :status => 30, :city => 'Paris'},
341
- {:sid => 'S4', :name => 'Clark', :status => 20, :city => 'London'},
342
- {:sid => 'S5', :name => 'Adams', :status => 30, :city => 'Athens'},
343
- ]
344
-
345
- Environment classes serve datasets (see later) that always have a to_rel method
346
- for obtaining in-memory relations:
347
-
348
- env = Alf::Environment.examples
349
- env.dataset(:suppliers).to_rel
350
- # => Alf::Relation[ ... ]
351
-
352
- Compiled expressions always have a to_rel method that allows obtaining an
353
- in-memory relation:
354
-
355
- op = Alf.lispy.compile {
356
- (join (restrict :suppliers, lambda{ city == 'London' }), :cities)
357
- }
358
- op.to_rel
359
- # => Alf::Relation[...]
360
-
361
- Lispy provides an 'evaluate' method which is precisely equivalent to the chain
362
- above. Therefore:
363
-
364
- rel = Alf.lispy.evaluate {
365
- (join (restrict :suppliers, lambda{ city == 'London' }), :cities)
366
- }
367
- # => Alf::Relation[...]
368
-
369
- ### Algebra is closed under its operators!
370
-
371
- Of course, from the closure property of a relational algebra (that states that
372
- operators works on relations and return relations), you can use a sub expression
373
- *everytime* a relational operand is expected, everytime:
374
-
375
- # Compute the total qty supplied in each country together with the subset
376
- # of products shipped there. Only consider suppliers that have a status
377
- # greater than 10, however.
378
- (summarize \
379
- (join \
380
- (join (restrict :suppliers, lambda{ status > 10 }),
381
- :supplies),
382
- :cities),
383
- [:country],
384
- :which => Agg::collect(:pid),
385
- :total => Agg::sum{ qty })
386
-
387
- Of course, complex queries quickly become unreadable that way. But you can always
388
- split complex tasks in more simple ones:
389
-
390
- kept_suppliers = (restrict :suppliers, lambda{ status > 10 })
391
- with_countries = (join kept_suppliers, :cities),
392
- supplying = (join with_countries, :supplies)
393
- (summarize supplying,
394
- [:country],
395
- :which => Agg::collect(:pid),
396
- :total => Agg::sum{ qty })
397
-
398
- And here is the result !
399
-
400
- +------+--------+--------------------------+
401
- | :sid | :total | :which |
402
- +------+--------+--------------------------+
403
- | S1 | 1300 | [P1, P2, P3, P4, P5, P6] |
404
- | S2 | 700 | [P1, P2] |
405
- | S3 | 200 | [P2] |
406
- | S4 | 900 | [P2, P4, P5] |
407
- +------+--------+--------------------------+
408
-
409
- ### Reference API
410
-
411
- For now, the Ruby API is documented in the commandline help itself (a cheatsheet
412
- or something will be provided as soon as possible). For example, you'll find the
413
- allowed syntaxes for RESTRICT as follows:
414
-
415
- % alf help restrict
416
-
417
- ...
418
- API & EXAMPLE
419
-
420
- # Restrict to suppliers with status greater than 20
421
- (restrict :suppliers, lambda{ status > 20 })
422
-
423
- # Restrict to suppliers that live in London
424
- (restrict :suppliers, lambda{ city == 'London' })
425
- ...
426
-
427
- ### Coping with non-relational data sources (nil, duplicates, etc.)
428
-
429
- Alf aims at being a tool that helps you tackling practical problems, and
430
- denormalized and/or noisy data is one of them. Missing values occur. Duplicates
431
- abound in SQL databases lacking primary keys, and so on. Using Alf's relational
432
- operators on such inputs is not a good idea, because it is a strong precondition
433
- violation. This is not because relational theory is weak, but because extending
434
- it to handle null/nil and duplicates correctly has been proven at best a nightmare,
435
- and at worse a mess. As a practical exercice, try to extend classical algebra
436
- with versions of +, - * and / that handle nil in such a way that the resulting
437
- theory is sound and still looks intuitive! Then do it on boolean algebra with
438
- _and_, _or_ and _not_. Then, add null/nil to classical set theory. Classical
439
- algebra, boolean algebra, and set theory are important building blocks behind
440
- relational algebra because almost all of its operators are defined on top of
441
- them...
442
-
443
- So what? The approach choosen in Alf to handle this conflict is very pragmatic.
444
- First of all, Alf implements a best effort strategy -- where possible -- to
445
- remain friendly in presence of null/nil on attributes that have no influence on
446
- an operator's job. For example, the query below will certainly fail if _status_
447
- is null/nil, but it won't probably fail if any other attribute is nil.
448
-
449
- % alf restrict suppliers -- "status > 10"
450
-
451
- This best-effort strategy is not enough, and striclty speaking, must be considered
452
- unsound (for example, it strongly hurts optimization possibilities). Therefore,
453
- I strongly encourage you to go a step further: **if relational operators want
454
- true relations as input, please, give them!**. For this, Alf also provides a few
455
- non-relational operators in addition to relational ones. Those operators must be
456
- interpreted as "pre-relational" operators, in the sense that they help obtaining
457
- valid relation representations from invalid ones. Provided that you use them
458
- correctly, their output can safely be used as input of a relational operator.
459
- You'll find,
460
-
461
- * <code>alf autonum</code> -- ensure no duplicates by generating a unique attribute
462
- * <code>alf compact</code> -- brute-force duplicates removal
463
- * <code>alf defaults</code> -- replace nulls/nil by valid values, on an attribute basis
464
-
465
- Play the game, it's easy!
466
-
467
- - _Give id, name and status of suppliers whose status is greater that 10_
468
- - Hey man, we don't know the status for all suppliers! What about these cases?
469
- - _Ignore them_
470
- - No problem dude!
471
-
472
- % alf defaults --strict suppliers -- sid '' name '' status 0 | alf restrict -- "status > 10"
473
-
474
- ### Alf is duck-typed
475
-
476
- The relational theory is often considered under a statically-typed point
477
- of view. When considering tuples and relations, for example, the notion of
478
- _heading_, a set of (name,type) pairs, is central. For example, a heading for
479
- a supplier tuple/relation could be:
480
-
481
- {:sid => String, :name => Name, :status => Integer, :city => String}
482
-
483
- Most relational operators have preconditions in terms of the headings of their
484
- operands. For example, _minus_ and _union_ require their operands to have same
485
- heading, while _rename_ requires renamed attributes to exist in operand's
486
- heading, and so on. Given an expression in relational algebra, it is always
487
- possible to compute the heading of the resulting relation, by statically
488
- analyzing the whole query expression in the light of a catalog of typed
489
- operators. This way, a tool can check that a query is statically valid, i.e.
490
- that it respects operator preconditions. While this approach has the major
491
- advantage of allowing strong optimizations, it also has a few drawbacks (as
492
- the need to know the heading of used datasources in advance) and is difficult to
493
- mary with dynamically-typed languages like Ruby. Therefore, Alf takes another
494
- approach, which is similar to duck-typing. In essence, this approach can be
495
- summarized as follows:
496
-
497
- - _You have the responsibility of not violating operators' preconditions. If you
498
- do, Alf has the responsibility of returning correct results._.
499
- - No problem dude!
500
-
501
- ## More about the shell command line
502
-
503
- % alf --help
504
-
505
- The help command will display the list of available operators. Each of them is
506
- completely described with 'alf help OPERATOR'. They all have a similar invocation
507
- syntax in shell:
508
-
509
- % alf operator operands... -- args...
510
-
511
- For example, try the following:
512
-
513
- # display suppliers that live in Paris
514
- % alf restrict suppliers -- "city == 'Paris'"
515
-
516
- # join suppliers and cities (no args here)
517
- % alf join suppliers cities
518
-
519
- ### Recognized data streams/files (.rash files)
520
-
521
- For educational purposes, 'suppliers' and 'cities' inputs are magically resolved
522
- as denoting the files examples/operators/suppliers.rash and
523
- examples/operators/cities.rash, respectively. You'll find other data files:
524
- parts.rash, supplies.rash that are resolved magically as well and with which you
525
- can play. For non-educational purposes, operands may always be explicit files,
526
- or you can force the folder in which datasource files have to be found:
527
-
528
- # The following invocations are equivalent
529
- % alf restrict /tmp/foo.rash -- "..."
530
- % alf --env=/tmp restrict foo -- "..."
531
-
532
- A .rash file is simply a file in which each line is a ruby Hash, intended to
533
- represent a tuple. Under theory-driven preconditions, a .rash file can be seen
534
- as a valid (straightforward but useful) physical representation of a relation!
535
- When used in shell, alf dumps query results in the .rash format by default,
536
- which opens the ability of piping invocations! Indeed, unary operators read their
537
- operand on standard input if not specific as command argument. For example, the
538
- invocation below is equivalent to the one given above.
539
-
540
- # display suppliers that live in Paris
541
- % cat examples/operators/suppliers.rash | alf restrict -- "city == 'Paris'"
542
-
543
- Similarly, when only one operand is present in invocations of binary operators,
544
- they read their left operand from standard input. Therefore, the join given in
545
- previous section can also be written as follows:
546
-
547
- % cat examples/operators/suppliers.rash | alf join cities
548
-
549
- The relational algebra is _closed_ under its operators, which means that these
550
- operators take relations as operands and return a relation. Therefore operator
551
- invocations can be nested, that is, operands can be other relational expressions.
552
- When you use alf in a shell, it simply means that you can pipe operators as you
553
- want:
16
+ Alf brings the relational algebra both in Shell and in Ruby. In Shell, because
17
+ manipulating any relation-like data source should be as straightforward as a one-liner.
18
+ In Ruby, because I've never understood why programming languages provide data structures
19
+ like arrays, hashes, sets, trees and graphs but not _relations_...
554
20
 
555
- % alf show --rash suppliers | alf join cities | alf restrict -- "status > 10"
21
+ ## Shell Example
556
22
 
557
- ### Obtaining a friendly output
23
+ % alf --examples show suppliers
558
24
 
559
- The show command (which is **not** a relational operator) can be used to obtain
560
- a more friendly output:
561
-
562
- # it renders a text table by default
563
- % alf show [--text] suppliers
564
-
565
25
  +------+-------+---------+--------+
566
26
  | :sid | :name | :status | :city |
567
27
  +------+-------+---------+--------+
@@ -572,226 +32,112 @@ a more friendly output:
572
32
  | S5 | Adams | 30 | Athens |
573
33
  +------+-------+---------+--------+
574
34
 
575
- # and reads from standard input without argument!
576
- % alf restrict suppliers "city == 'Paris'" | alf show
577
-
578
- +------+-------+---------+-------+
579
- | :sid | :name | :status | :city |
580
- +------+-------+---------+-------+
581
- | S2 | Jones | 10 | Paris |
582
- | S3 | Blake | 30 | Paris |
583
- +------+-------+---------+-------+
584
-
585
- Other formats can be obtained (see 'alf help show'). For example, you can generate
586
- a .yaml file, as follows:
587
-
588
- % alf restrict suppliers -- "city == 'Paris'" | alf show --yaml
589
-
590
- ### Executing .alf files
591
-
592
- You'll also find .alf files in the examples folder, that contain more complex
593
- examples in the Ruby functional syntax (see section below).
594
-
595
- % cat examples/operators/group.alf
596
- #!/usr/bin/env alf
597
- (group :supplies, [:pid, :qty], :supplying)
598
-
599
- You can simply execute these files with alf directly as follows:
600
-
601
- # the following works, as well as the shortcut 'alf show group'
602
- % alf examples/group.alf | alf show
603
-
604
- +------+-----------------+
605
- | :sid | :supplying |
606
- +------+-----------------+
607
- | S1 | +------+------+ |
608
- | | | :pid | :qty | |
609
- | | +------+------+ |
610
- | | | P1 | 300 | |
611
- | | | P2 | 200 | |
612
- ...
613
-
614
- Also, mimicing the ruby executable, the following invocation is also possible:
615
-
616
- % alf -e "(restrict :suppliers, lambda{ city == 'Paris' })"
617
-
618
- where the argument is a relational expression in Alf's Lispy dialect, which
619
- is detailed in the next section.
620
-
621
- ## More about Alf in Ruby
622
-
623
- ### Calling commands 'ala' shell
624
-
625
- For simple cases, the easiest way of using Alf in ruby is probably to mimic
626
- what you have in shell:
627
-
628
- % alf restrict suppliers -- "city == 'Paris'"
629
-
630
- Then, in ruby
631
-
632
- #
633
- # 1. create an engine on an environment (see section about environments later)
634
- # 2. run a command
635
- # 3. op is a thread-safe enumerable of tuples, see the Lispy section below)
636
- #
637
- lispy = Alf.lispy(Alf::Environment.examples)
638
- op = lispy.run(['restrict', 'suppliers', '--', "city == 'Paris'"])
639
-
640
- If this kind of API is not sufficiently expressive for you, you'll have to learn
641
- the APIs deeper, and use the Lispy functional style that Alf provides, which can
642
- be compiled and used as explained in the next section.
643
-
644
- ### Compiler vs. Relation data structure
645
-
646
- The compilers allow you to manipulate algebra expressions. Just obtain a Lispy
647
- instance on an environment and you're ready:
648
-
649
- #
650
- # Expressions can simply be compiled as illustrated below. We use the
651
- # examples environment here, see the dedicated section later about other
652
- # available environments.
653
- #
654
- lispy = Alf.lispy(Alf::Environment.examples)
655
- london_suppliers = lispy.compile do
656
- (restrict :suppliers, lambda{ city == 'London' })
657
- end
658
-
659
- #
660
- # Returned operator is an enumerable of ruby hashes. Provided that datasets
661
- # offered by the environment (:suppliers here) can be enumerated more than
662
- # once, the operator may be used multiple times and is even thread safe!
663
- #
664
- london_suppliers.each do |tuple|
665
- # tuple is a ruby Hash
666
- end
667
-
668
- #
669
- # Now, maybe you want to reuse op in a larger query, for example
670
- # by projecting on the city attribute... Here is how this can be
671
- # done:
672
- #
673
- projection = (project london_suppliers, [:city])
674
-
675
- Note that the examples above manipulate algebra operators, not relations per se.
676
- This means that equality and other such operators, that operate on relation
677
- _values_, do not operate correctly here:
678
-
679
- projection == Alf::Relation[{:city => 'London'}]
680
- # => nil
681
-
682
- In contrast, you can use such operators when operating on true relation values:
683
-
684
- projection.to_rel == Alf::Relation[{:city => 'London'}]
685
- # => true
686
-
687
- ### Using/Implementing other Environments
688
-
689
- An Environment instance if passed as first argument of <code>Alf.lispy</code>
690
- and is responsible of resolving named datasets. A base class Environment::Folder
691
- is provided with the Alf distribution, with a factory method on the Environment
692
- class itself.
693
-
694
- env = Alf::Environment.folder("path/to/a/folder")
695
-
696
- An environment built that way will look for .rash and .alf files in the specified
697
- folder and sub-folders. I'll of course strongly consider any contribution
698
- implementing the Environment contract on top of SQL or NoSQL databases or anything
699
- that can be useful to manipulate with relational algebra. Such contributions can
700
- be added to the project directly. A base template would look like:
701
-
702
- class Foo < Alf::Environment
703
-
704
- #
705
- # You should at least implement the _dataset_ method that resolves a
706
- # name (a Symbol instance) to an Enumerable of tuples (typically a
707
- # Reader). See Alf::Environment for exact contract details.
708
- #
709
- def dataset(name)
710
- end
711
-
712
- end
713
-
714
- Read more about Environment's API so as to let your environment be recognized
715
- in shell (--env=...) on rubydoc.info
716
-
717
- ### Adding file decoders, aka Readers
718
-
719
- Environments should not be confused with Readers (see Reader class and its
720
- subclasses). While the former resolve named datasets, the latter decode files
721
- and/or other resources as tuple enumerables. Environments typically serve Reader
722
- instances in response to dataset resolving.
723
-
724
- Reader implementations decoding .rash and .alf files are provided in the main
725
- alf.rb file. It's relatively easy to implement the Reader contract by extending
726
- the Reader class and implementing an each method. Once again, contributions are
727
- very welcome in lib/alf/reader (.csv files, .log files, and so on). A basic
728
- template for this is as follows:
729
-
730
- class Bar < Alf::Reader
731
-
732
- #
733
- # You should at least implement each, see Alf::Reader which provides a
734
- # base implementation and a few tools
735
- #
736
- def each
737
- # [...]
738
- end
739
-
740
- # By registering it, the Folder environment will automatically
741
- # recognize and decode .bar files correctly!
742
- Alf::Reader.register(:bar, [".bar"], self)
743
-
744
- end
745
-
746
- ### Adding outputters, aka Renderers
747
-
748
- Similarly, you can contribute renderers to output relations in html, or whatever
749
- format you would consider interesting. See the Renderer class, and consider the
750
- following template for contributions in lib/alf/renderer
751
-
752
- class Glim < Alf::Renderer
753
-
754
- #
755
- # You should at least implement the execute method that renders tuples
756
- # given in _input_ (an Enumerable of tuples) on the output buffer
757
- # and returns the latter. See Alf::Renderer for the exact contract
758
- # details.
759
- #
760
- def execute(output = $stdout)
761
- # [...]
762
- output
763
- end
764
-
765
-
766
- # By registering it, the output options of 'alf show' will
767
- # automatically provide your --glim contribution
768
- Alf::Renderer.register(:glim, "as a .glim file", self)
769
-
770
- end
35
+ % alf --examples group suppliers -- size name status -- in_that_city
36
+
37
+ +--------+----------------------------+
38
+ | :city | :in_that_city |
39
+ +--------+----------------------------+
40
+ | London | +------+-------+---------+ |
41
+ | | | :sid | :name | :status | |
42
+ | | +------+-------+---------+ |
43
+ | | | S1 | Smith | 20 | |
44
+ | | | S4 | Clark | 20 | |
45
+ | | +------+-------+---------+ |
46
+ | Paris | +------+-------+---------+ |
47
+ | | | :sid | :name | :status | |
48
+ | | +------+-------+---------+ |
49
+ | | | S2 | Jones | 10 | |
50
+ | | | S3 | Blake | 30 | |
51
+ | | +------+-------+---------+ |
52
+ | Athens | +------+-------+---------+ |
53
+ | | | :sid | :name | :status | |
54
+ | | +------+-------+---------+ |
55
+ | | | S5 | Adams | 30 | |
56
+ | | +------+-------+---------+ |
57
+ +--------+----------------------------+
58
+
59
+ ## Ruby Example
60
+
61
+ # Let get the same database in ruby
62
+ db = Alf.examples
63
+
64
+ # Group suppliers by city
65
+ grouped = db.query{
66
+ group(:suppliers, [:sid, :name, :status], :in_that_city)
67
+ }
68
+ # => same result as in shell
69
+
70
+ # Let make some computations on the sub-relations
71
+ db.query{
72
+ extend(grouped, how_many: ->{ in_that_city.count },
73
+ avg_status: ->{ in_that_city.avg{ status } })
74
+ }
75
+ # +--------+----------------------------+-----------+-------------+
76
+ # | :city | :in_that_city | :how_many | :avg_status |
77
+ # +--------+----------------------------+-----------+-------------+
78
+ # | London | +------+-------+---------+ | 2 | 20.000 |
79
+ # | | | :sid | :name | :status | | | |
80
+ # | | +------+-------+---------+ | | |
81
+ # | | | S1 | Smith | 20 | | | |
82
+ # | | | S4 | Clark | 20 | | | |
83
+ # | | +------+-------+---------+ | | |
84
+ # | Paris | +------+-------+---------+ | 2 | 20.000 |
85
+ # | | | :sid | :name | :status | | | |
86
+ # | | +------+-------+---------+ | | |
87
+ # | | | S2 | Jones | 10 | | | |
88
+ # | | | S3 | Blake | 30 | | | |
89
+ # | | +------+-------+---------+ | | |
90
+ # | Athens | +------+-------+---------+ | 1 | 30.000 |
91
+ # | | | :sid | :name | :status | | | |
92
+ # | | +------+-------+---------+ | | |
93
+ # | | | S5 | Adams | 30 | | | |
94
+ # | | +------+-------+---------+ | | |
95
+ # +--------+----------------------------+-----------+-------------+
96
+
97
+ # Now observe that the same result can also be expressed as follows (and can be
98
+ # optimized more easily)
99
+ summarized = db.query{
100
+ summary = summarize(:suppliers, [ :city ], how_many: count, avg_status: avg{ status })
101
+ join(grouped, summary)
102
+ }
103
+
104
+ # Oh, and of course...
105
+ require 'json'
106
+ puts summarized.to_json
107
+ # [{"city":"London","in_that_city":[{"sid":"S1","name":"Smith","status":20},{"sid":"S4"...
108
+
109
+ ## Install, bundler, require
110
+
111
+ % [sudo] gem install alf [fastercsv, ...]
112
+ % alf --help
113
+
114
+ # API is not considered stable enough for now, please use
115
+ gem "alf", "= 0.13.0"
116
+
117
+ # The following should not break your code, but is a bit less safe,
118
+ # until 1.0.0 has been reached
119
+ gem "alf", "~> 0.13.0"
771
120
 
772
121
  ## Related Work & Tools
773
122
 
774
- - You should certainly have a look at the Third Manifesto website: {http://www.thethirdmanifesto.com/}
775
- - Why not reading the {http://www.dcs.warwick.ac.uk/~hugh/TTM/DBE-Chapter01.pdf
776
- third manifesto paper} itself?
777
- - Also have a look at {http://www.dcs.warwick.ac.uk/~hugh/TTM/Projects.html other
778
- implementation projects}, especially {http://dbappbuilder.sourceforge.net/Rel.php Rel}
779
- which provides an implementation of the **Tutorial D** language.
780
- - {https://github.com/dkubb/veritas Dan Kubb's Veritas} project is worth considering
123
+ - You should certainly have a look at the
124
+ [Third Manifesto website](http://www.thethirdmanifesto.com/):
125
+ - Why not reading the
126
+ [third manifesto](http://www.dcs.warwick.ac.uk/~hugh/TTM/DBE-Chapter01.pdf) ?
127
+ - Also have a look at
128
+ [other implementation projects](http://www.dcs.warwick.ac.uk/~hugh/TTM/Projects.html)
129
+ especially [Rel](http://dbappbuilder.sourceforge.net/Rel.php) which provides an
130
+ implementation of the **Tutorial D** language.
131
+ - [Dan Kubb's Veritas](https://github.com/dkubb/veritas) project is worth considering
781
132
  also in the Ruby community. While very similar to Alf in providing a pure ruby
782
133
  algebra implementation, Veritas mostly provides a framework for manipulating
783
- and statically analyzing algebra expressions so as to be able to
784
- {https://github.com/dkubb/veritas-optimizer optimize them} and
785
- {https://github.com/dkubb/veritas-sql-generator compile them to SQL}. We are
786
- working together with Dan Kubb to see how Alf and Veritas could be closer from
787
- each other in the future, if not in their codebase, at least in using the very
788
- same terminology for the same concepts.
789
-
790
- ## Contributing
134
+ and statically analyzing algebra expressions so as to be able to
135
+ [optimize them](https://github.com/dkubb/veritas-optimizer) and
136
+ [compile them to SQL](https://github.com/dkubb/veritas-sql-generator).
791
137
 
792
- ### Alf is open source
138
+ ## Contributing
793
139
 
794
- You know the rules:
140
+ You know the rules:
795
141
 
796
142
  * The code is on github https://github.com/blambeau/alf
797
143
  * Please report any problem or bug in the issue tracker on github
@@ -800,67 +146,51 @@ You know the rules:
800
146
  Alf is distributed under a MIT licence. Please let me know if it does not fit
801
147
  your needs and I'll see what I can do!
802
148
 
803
- ### Internals -- Tribute to Sinatra
804
-
805
- Alf's code style is very inspired from what I've found in Sinatra when looking
806
- at its internals a few months ago. Alf, as Sinatra, is mostly implemented in a
807
- single file, lib/alf.rb. Everything is there except specific third-party contributions
808
- (in lib/alf/...). You'll need an editor or IDE that supports code folding/unfolding.
809
- Then, follow the guide:
810
-
811
- 1. Fold everything but the Alf module.
812
- 2. Main concepts, first level of abstraction, should fit on the screen
813
- 3. Unfold the concept you're interested in, and return to the previous bullet
814
-
815
- ### Roadmap
149
+ ## Roadmap
816
150
 
817
151
  Below is what I've imagined about Alf's future. However, this is to be interpreted
818
152
  as my own wish list, while I would love hearing yours instead.
819
153
 
820
- - Towards 1.0.0, I would like to stabilize and document Alf public APIs as well
154
+ - Towards 1.0.0, I would like to stabilize and document Alf public APIs as well
821
155
  as internals (a few concepts are still unstable there). Alf also has a certain
822
156
  number of limitations that are worth overcoming for version 1.0.0. The latter
823
- include the semantically wrong way of applying joins on sub-relations, the
157
+ include the semantically wrong way of applying joins on sub-relations, the
824
158
  impossibility to use Lispy expressions on sub-relations in extend, and the error
825
159
  management which is unspecific and unfriendly so far.
826
- - I also would like starting collecting Reader, Renderer and Environment
827
- contributions for common data sources (SQL, NoSQL, CSV, LOGS) and output
828
- formats (HTML, XML, JSON). Contributions could be either developped as different
829
- gem projects or distributed with Alf's gem and source code, I still need to
160
+ - I also would like starting collecting Reader, Renderer and Connection
161
+ contributions for common data sources (SQL, NoSQL, CSV, LOGS) and output
162
+ formats (HTML, XML, JSON). Contributions could be either developped as different
163
+ gem projects or distributed with Alf's gem and source code, I still need to
830
164
  decide the exact policy (suggestions are more than welcome here)
831
165
  - Alf will remain a practical tool before everything else. In the middle term,
832
166
  I would like to complete the set of available operators (relational and non-
833
- relational ones). Some of them will be operators described in D & D books
834
- while others will be new suggestions of mine.
835
- - In the long term Alf should be able to avoid loading tuples in memory (under
836
- a certain number of conditions on datasources) for almost all queries.
837
- - Without targetting a fast tool at all, I also would like Alf to provide a basic
838
- optimizer that would be able to push equality restrictions down and materialize
839
- sub-expressions used more than once in with expressions.
167
+ relational ones). Some of them will be operators described in D & D books
168
+ while others will be new suggestions of mine.
169
+ - In the long term Alf should be able to avoid loading tuples in memory (under
170
+ a certain number of conditions on datasources) for almost all queries.
171
+ - Without targetting a fast tool at all, I also would like Alf to provide a basic
172
+ optimizer that would be able to push equality restrictions down and materialize
173
+ sub-expressions used more than once in with expressions.
840
174
 
841
- ### Versioning policy
175
+ ## Versioning policy
842
176
 
843
- Alf respects {http://semver.org/ semantic versioning}, which means that it has
177
+ Alf respects [semantic versioning](http://semver.org/), which means that it has
844
178
  a X.Y.Z version number and follows a few rules.
845
179
 
846
- - The public API is made of the commandline tool, the Lispy dialect and the
847
- Relation datastructure. This API will become stable with version 1.0.0 in a
180
+ - The public API is made of the commandline tool, the Lispy dialect and the
181
+ Relation datastructure. This API will become stable with version 1.0.0 in a
848
182
  near future.
849
- - Currently, version 1.0.0 **has not been reached**. It means that **anything
850
- may change at any time**. Best effort will be done to upgrade Y when backward
183
+ - Currently, version 1.0.0 **has not been reached**. It means that **anything
184
+ may change at any time**. Best effort will be done to upgrade Y when backward
851
185
  incompatible changes occur.
852
186
  - Once 1.0.0 will be reached, the following rules will be followed:
853
- - Backward compatible bug fixes will increase Z.
854
- - New features and enhancements that do not break backward compatibility of
187
+ - Backward compatible bug fixes will increase Z.
188
+ - New features and enhancements that do not break backward compatibility of
855
189
  the public API will increase the Y number.
856
- - Non backward compatible changes of the public API will increase the X
190
+ - Non backward compatible changes of the public API will increase the X
857
191
  number.
858
192
 
859
- All classes and modules but Alf module, the Lispy DSL and Alf::Relation are part
193
+ All classes and modules but Alf module, the Lispy DSL and Alf::Relation are part
860
194
  of the private API and may change at any time. A best-effort strategy is followed
861
195
  to avoid breaking internals on tiny (Z) version increases, especially extension
862
- points like Reader and Renderer.
863
-
864
- ## Enjoy Alf!
865
-
866
- - No problem dude!
196
+ points like Reader and Renderer.