dbagile 0.0.1

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 (305) hide show
  1. data/LICENCE.textile +12 -0
  2. data/README.textile +89 -0
  3. data/bin/dba +22 -0
  4. data/lib/dbagile/adapter/sequel/class_methods.rb +18 -0
  5. data/lib/dbagile/adapter/sequel/connection.rb +38 -0
  6. data/lib/dbagile/adapter/sequel/data/table_driven.rb +30 -0
  7. data/lib/dbagile/adapter/sequel/data/transaction_driven.rb +43 -0
  8. data/lib/dbagile/adapter/sequel/schema/concrete_script.rb +135 -0
  9. data/lib/dbagile/adapter/sequel/schema/physical_dump.rb +106 -0
  10. data/lib/dbagile/adapter/sequel/schema/schema2sequel_args.rb +71 -0
  11. data/lib/dbagile/adapter/sequel/schema/table_driven.rb +52 -0
  12. data/lib/dbagile/adapter/sequel/schema/transaction_driven.rb +46 -0
  13. data/lib/dbagile/adapter/sequel/sequel_tracer.rb +144 -0
  14. data/lib/dbagile/adapter/sequel.rb +46 -0
  15. data/lib/dbagile/adapter.rb +15 -0
  16. data/lib/dbagile/command/api.rb +49 -0
  17. data/lib/dbagile/command/bulk/commons.rb +130 -0
  18. data/lib/dbagile/command/bulk/export.rb +99 -0
  19. data/lib/dbagile/command/bulk/import.rb +147 -0
  20. data/lib/dbagile/command/bulk.rb +3 -0
  21. data/lib/dbagile/command/class_methods.rb +103 -0
  22. data/lib/dbagile/command/db/add.rb +94 -0
  23. data/lib/dbagile/command/db/list.rb +40 -0
  24. data/lib/dbagile/command/db/ping.rb +49 -0
  25. data/lib/dbagile/command/db/rm.rb +52 -0
  26. data/lib/dbagile/command/db/stage.rb +81 -0
  27. data/lib/dbagile/command/db/use.rb +48 -0
  28. data/lib/dbagile/command/db.rb +6 -0
  29. data/lib/dbagile/command/dba.rb +121 -0
  30. data/lib/dbagile/command/help.rb +50 -0
  31. data/lib/dbagile/command/repo/create.rb +54 -0
  32. data/lib/dbagile/command/repo.rb +1 -0
  33. data/lib/dbagile/command/robust.rb +86 -0
  34. data/lib/dbagile/command/schema/check.rb +59 -0
  35. data/lib/dbagile/command/schema/commons.rb +118 -0
  36. data/lib/dbagile/command/schema/diff.rb +101 -0
  37. data/lib/dbagile/command/schema/dump.rb +48 -0
  38. data/lib/dbagile/command/schema/merge.rb +55 -0
  39. data/lib/dbagile/command/schema/sql_script.rb +124 -0
  40. data/lib/dbagile/command/schema.rb +6 -0
  41. data/lib/dbagile/command/sql/drop.rb +40 -0
  42. data/lib/dbagile/command/sql/heading.rb +34 -0
  43. data/lib/dbagile/command/sql/send.rb +67 -0
  44. data/lib/dbagile/command/sql/show.rb +42 -0
  45. data/lib/dbagile/command/sql.rb +4 -0
  46. data/lib/dbagile/command/web/tools.rb +23 -0
  47. data/lib/dbagile/command/web.rb +1 -0
  48. data/lib/dbagile/command.rb +158 -0
  49. data/lib/dbagile/contract/connection.rb +66 -0
  50. data/lib/dbagile/contract/data/dataset.rb +69 -0
  51. data/lib/dbagile/contract/data/table_driven.rb +49 -0
  52. data/lib/dbagile/contract/data/transaction_driven.rb +74 -0
  53. data/lib/dbagile/contract/data.rb +3 -0
  54. data/lib/dbagile/contract/robust/helpers.rb +19 -0
  55. data/lib/dbagile/contract/robust/optimistic/data/table_driven.rb +31 -0
  56. data/lib/dbagile/contract/robust/optimistic/data/transaction_driven.rb +45 -0
  57. data/lib/dbagile/contract/robust/optimistic/schema/table_driven.rb +53 -0
  58. data/lib/dbagile/contract/robust/optimistic/schema/transaction_driven.rb +45 -0
  59. data/lib/dbagile/contract/robust/optimistic.rb +18 -0
  60. data/lib/dbagile/contract/robust.rb +20 -0
  61. data/lib/dbagile/contract/schema/table_driven.rb +89 -0
  62. data/lib/dbagile/contract/schema/transaction_driven.rb +68 -0
  63. data/lib/dbagile/contract/schema.rb +2 -0
  64. data/lib/dbagile/contract/utils/delegate.rb +17 -0
  65. data/lib/dbagile/contract/utils/full.rb +13 -0
  66. data/lib/dbagile/contract/utils.rb +2 -0
  67. data/lib/dbagile/contract.rb +5 -0
  68. data/lib/dbagile/core/chain.rb +92 -0
  69. data/lib/dbagile/core/connection.rb +51 -0
  70. data/lib/dbagile/core/database.rb +221 -0
  71. data/lib/dbagile/core/io/dsl.rb +95 -0
  72. data/lib/dbagile/core/io/robustness.rb +82 -0
  73. data/lib/dbagile/core/io.rb +2 -0
  74. data/lib/dbagile/core/repository/builder.rb +67 -0
  75. data/lib/dbagile/core/repository/yaml_methods.rb +82 -0
  76. data/lib/dbagile/core/repository.rb +211 -0
  77. data/lib/dbagile/core/schema/builder/coercion.rb +210 -0
  78. data/lib/dbagile/core/schema/builder/concept_factory.rb +61 -0
  79. data/lib/dbagile/core/schema/builder.rb +187 -0
  80. data/lib/dbagile/core/schema/composite.rb +239 -0
  81. data/lib/dbagile/core/schema/computations/filter.rb +40 -0
  82. data/lib/dbagile/core/schema/computations/merge.rb +55 -0
  83. data/lib/dbagile/core/schema/computations/minus.rb +44 -0
  84. data/lib/dbagile/core/schema/computations/split.rb +37 -0
  85. data/lib/dbagile/core/schema/computations.rb +4 -0
  86. data/lib/dbagile/core/schema/database_schema.rb +129 -0
  87. data/lib/dbagile/core/schema/errors.rb +173 -0
  88. data/lib/dbagile/core/schema/logical/attribute.rb +68 -0
  89. data/lib/dbagile/core/schema/logical/constraint/candidate_key.rb +70 -0
  90. data/lib/dbagile/core/schema/logical/constraint/foreign_key.rb +121 -0
  91. data/lib/dbagile/core/schema/logical/constraint.rb +58 -0
  92. data/lib/dbagile/core/schema/logical/constraints.rb +28 -0
  93. data/lib/dbagile/core/schema/logical/heading.rb +47 -0
  94. data/lib/dbagile/core/schema/logical/relvar.rb +81 -0
  95. data/lib/dbagile/core/schema/logical.rb +24 -0
  96. data/lib/dbagile/core/schema/migrate/abstract_script.rb +35 -0
  97. data/lib/dbagile/core/schema/migrate/collapse_table.rb +15 -0
  98. data/lib/dbagile/core/schema/migrate/create_table.rb +15 -0
  99. data/lib/dbagile/core/schema/migrate/drop_table.rb +15 -0
  100. data/lib/dbagile/core/schema/migrate/expand_table.rb +15 -0
  101. data/lib/dbagile/core/schema/migrate/operation.rb +141 -0
  102. data/lib/dbagile/core/schema/migrate/stager.rb +282 -0
  103. data/lib/dbagile/core/schema/migrate.rb +2 -0
  104. data/lib/dbagile/core/schema/part.rb +114 -0
  105. data/lib/dbagile/core/schema/physical/index.rb +64 -0
  106. data/lib/dbagile/core/schema/physical/indexes.rb +12 -0
  107. data/lib/dbagile/core/schema/physical.rb +26 -0
  108. data/lib/dbagile/core/schema/robustness.rb +39 -0
  109. data/lib/dbagile/core/schema/schema_object.rb +94 -0
  110. data/lib/dbagile/core/schema.rb +254 -0
  111. data/lib/dbagile/core/transaction.rb +74 -0
  112. data/lib/dbagile/core.rb +7 -0
  113. data/lib/dbagile/environment/buffering.rb +45 -0
  114. data/lib/dbagile/environment/delegator.rb +59 -0
  115. data/lib/dbagile/environment/interactions.rb +208 -0
  116. data/lib/dbagile/environment/on_error.rb +47 -0
  117. data/lib/dbagile/environment/repository.rb +161 -0
  118. data/lib/dbagile/environment/robustness.rb +7 -0
  119. data/lib/dbagile/environment/testing.rb +23 -0
  120. data/lib/dbagile/environment.rb +122 -0
  121. data/lib/dbagile/errors.rb +30 -0
  122. data/lib/dbagile/io/csv.rb +99 -0
  123. data/lib/dbagile/io/json.rb +41 -0
  124. data/lib/dbagile/io/pretty_table.rb +128 -0
  125. data/lib/dbagile/io/ruby.rb +62 -0
  126. data/lib/dbagile/io/text.rb +18 -0
  127. data/lib/dbagile/io/type_safe.rb +65 -0
  128. data/lib/dbagile/io/xml.rb +35 -0
  129. data/lib/dbagile/io/yaml.rb +30 -0
  130. data/lib/dbagile/io.rb +94 -0
  131. data/lib/dbagile/loader.rb +16 -0
  132. data/lib/dbagile/plugin.rb +29 -0
  133. data/lib/dbagile/restful/client/delete.rb +22 -0
  134. data/lib/dbagile/restful/client/get.rb +24 -0
  135. data/lib/dbagile/restful/client/post.rb +22 -0
  136. data/lib/dbagile/restful/client/utils.rb +16 -0
  137. data/lib/dbagile/restful/client.rb +41 -0
  138. data/lib/dbagile/restful/middleware/delete.rb +22 -0
  139. data/lib/dbagile/restful/middleware/get.rb +27 -0
  140. data/lib/dbagile/restful/middleware/one_database.rb +82 -0
  141. data/lib/dbagile/restful/middleware/post.rb +23 -0
  142. data/lib/dbagile/restful/middleware/utils.rb +65 -0
  143. data/lib/dbagile/restful/middleware.rb +54 -0
  144. data/lib/dbagile/restful/server.rb +65 -0
  145. data/lib/dbagile/restful.rb +9 -0
  146. data/lib/dbagile/robustness/dependencies.rb +36 -0
  147. data/lib/dbagile/robustness/file_system.rb +53 -0
  148. data/lib/dbagile/robustness.rb +14 -0
  149. data/lib/dbagile/tools/file_system.rb +24 -0
  150. data/lib/dbagile/tools/math.rb +11 -0
  151. data/lib/dbagile/tools/ordered_hash.rb +39 -0
  152. data/lib/dbagile/tools/ruby.rb +78 -0
  153. data/lib/dbagile/tools/string.rb +6 -0
  154. data/lib/dbagile/tools/tuple.rb +49 -0
  155. data/lib/dbagile/tools.rb +6 -0
  156. data/lib/dbagile.rb +66 -0
  157. data/test/assumptions/equality.spec +11 -0
  158. data/test/assumptions/fixtures.rb +39 -0
  159. data/test/assumptions/inheritance.spec +17 -0
  160. data/test/assumptions/sequel/autonumber.spec +19 -0
  161. data/test/assumptions/sequel/connect.spec +29 -0
  162. data/test/assumptions/sequel/test.db +0 -0
  163. data/test/assumptions/stdlib/pathname.spec +13 -0
  164. data/test/assumptions/yaml/fixtures.rb +25 -0
  165. data/test/assumptions/yaml/to_yaml.spec +10 -0
  166. data/test/assumptions.spec +2 -0
  167. data/test/commands/bulk/export.spec +100 -0
  168. data/test/commands/bulk/import.spec +49 -0
  169. data/test/commands/db/add.spec +31 -0
  170. data/test/commands/db/list.spec +29 -0
  171. data/test/commands/db/ping.spec +21 -0
  172. data/test/commands/db/rm.spec +18 -0
  173. data/test/commands/db/use.spec +18 -0
  174. data/test/commands/dba.spec +54 -0
  175. data/test/commands/repo/create.spec +30 -0
  176. data/test/commands/schema/check.spec +25 -0
  177. data/test/commands/schema/diff.spec +30 -0
  178. data/test/commands/schema/dump.spec +23 -0
  179. data/test/commands/schema/fixtures/add_constraint.yaml +30 -0
  180. data/test/commands/schema/fixtures/announced.yaml +28 -0
  181. data/test/commands/schema/fixtures/effective.yaml +20 -0
  182. data/test/commands/schema/fixtures/invalid.yaml +6 -0
  183. data/test/commands/schema/sql_script.spec +56 -0
  184. data/test/commands/sql/drop.spec +25 -0
  185. data/test/commands/sql/heading.spec +7 -0
  186. data/test/commands/sql/scripts/delete.sql +1 -0
  187. data/test/commands/sql/scripts/insert.sql +2 -0
  188. data/test/commands/sql/send.spec +29 -0
  189. data/test/commands/sql/show.spec +17 -0
  190. data/test/commands.spec +138 -0
  191. data/test/contract/connection/transaction.ex +11 -0
  192. data/test/contract/connection.spec +9 -0
  193. data/test/contract/data/dataset/columns.ex +5 -0
  194. data/test/contract/data/dataset/count.ex +5 -0
  195. data/test/contract/data/dataset.spec +9 -0
  196. data/test/contract/data/table_driven/dataset.ex +31 -0
  197. data/test/contract/data/table_driven/exists_q.ex +27 -0
  198. data/test/contract/data/table_driven.spec +9 -0
  199. data/test/contract/data/transaction_driven/delete.ex +29 -0
  200. data/test/contract/data/transaction_driven/direct_sql.ex +19 -0
  201. data/test/contract/data/transaction_driven/insert.ex +8 -0
  202. data/test/contract/data/transaction_driven/update.ex +19 -0
  203. data/test/contract/data/transaction_driven.spec +18 -0
  204. data/test/contract/robust/data/table_driven.spec +15 -0
  205. data/test/contract/robust/data/transaction_driven.spec +21 -0
  206. data/test/contract/robust/schema/table_driven.spec +21 -0
  207. data/test/contract/robust/schema/transaction_driven.spec +19 -0
  208. data/test/contract/schema/table_driven/column_names.ex +5 -0
  209. data/test/contract/schema/table_driven/has_column_q.ex +13 -0
  210. data/test/contract/schema/table_driven/has_table_q.ex +11 -0
  211. data/test/contract/schema/table_driven/heading.ex +5 -0
  212. data/test/contract/schema/table_driven.spec +9 -0
  213. data/test/contract/schema/transaction_driven/create_table.ex +10 -0
  214. data/test/contract/schema/transaction_driven/drop_table.ex +10 -0
  215. data/test/contract/schema/transaction_driven.spec +18 -0
  216. data/test/contract.spec +66 -0
  217. data/test/fixtures/basics/data/basic_values.rb +13 -0
  218. data/test/fixtures/basics/data/empty_table.rb +3 -0
  219. data/test/fixtures/basics/data/non_empty_table.rb +4 -0
  220. data/test/fixtures/basics/data/parts.rb +8 -0
  221. data/test/fixtures/basics/data/suppliers.rb +7 -0
  222. data/test/fixtures/basics/data/supplies.rb +14 -0
  223. data/test/fixtures/basics/dbagile.idx +20 -0
  224. data/test/fixtures/basics/fixtures.yaml +28 -0
  225. data/test/fixtures/basics/robust.db +0 -0
  226. data/test/fixtures/basics/suppliers.yaml +30 -0
  227. data/test/fixtures/basics/test.db +0 -0
  228. data/test/fixtures/empty/dbagile.idx +5 -0
  229. data/test/fixtures.rb +152 -0
  230. data/test/restful/delete/no_format.ex +32 -0
  231. data/test/restful/delete.spec +8 -0
  232. data/test/restful/get/csv_format.ex +12 -0
  233. data/test/restful/get/json_format.ex +19 -0
  234. data/test/restful/get/query_string.ex +11 -0
  235. data/test/restful/get/text_format.ex +12 -0
  236. data/test/restful/get/yaml_format.ex +14 -0
  237. data/test/restful/get.spec +5 -0
  238. data/test/restful/post/no_format.ex +22 -0
  239. data/test/restful/post.spec +8 -0
  240. data/test/restful.spec +32 -0
  241. data/test/run_all_suite.rb +51 -0
  242. data/test/spec_helper.rb +26 -0
  243. data/test/support/be_a_valid_json_string.rb +19 -0
  244. data/test/support/be_a_valid_yaml_string.rb +18 -0
  245. data/test/unit/adapter/factor.spec +13 -0
  246. data/test/unit/adapter/sequel/new.spec +19 -0
  247. data/test/unit/command/api.spec +12 -0
  248. data/test/unit/command/command_for.spec +36 -0
  249. data/test/unit/command/command_name_of.spec +21 -0
  250. data/test/unit/command/ruby_method_for.spec +21 -0
  251. data/test/unit/command/sanity.spec +34 -0
  252. data/test/unit/contract/utils/delegate/delegate.spec +23 -0
  253. data/test/unit/core/chain/chain.spec +57 -0
  254. data/test/unit/core/chain/connect.spec +22 -0
  255. data/test/unit/core/chain/delegate_chain.spec +16 -0
  256. data/test/unit/core/chain/initialize.spec +19 -0
  257. data/test/unit/core/chain/plug.spec +31 -0
  258. data/test/unit/core/io/dsl/scope.spec +9 -0
  259. data/test/unit/core/repository/create_bang.spec +31 -0
  260. data/test/unit/core/repository/current.spec +31 -0
  261. data/test/unit/core/repository/database.spec +47 -0
  262. data/test/unit/core/repository/fixtures/corrupted/dbagile.idx +1 -0
  263. data/test/unit/core/repository/fixtures/test_and_prod/dbagile.idx +21 -0
  264. data/test/unit/core/repository/fixtures.rb +25 -0
  265. data/test/unit/core/repository/has_database_q.spec +16 -0
  266. data/test/unit/core/repository/load.spec +51 -0
  267. data/test/unit/core/repository/to_yaml.spec +17 -0
  268. data/test/unit/core/schema/check.spec +32 -0
  269. data/test/unit/core/schema/empty_q.spec +18 -0
  270. data/test/unit/core/schema/filter.spec +42 -0
  271. data/test/unit/core/schema/fixtures/dbagile.yaml +7 -0
  272. data/test/unit/core/schema/fixtures/empty.yaml +11 -0
  273. data/test/unit/core/schema/fixtures/invalid.yaml +54 -0
  274. data/test/unit/core/schema/fixtures/left.yaml +46 -0
  275. data/test/unit/core/schema/fixtures/left_minus_right.yaml +31 -0
  276. data/test/unit/core/schema/fixtures/right.yaml +46 -0
  277. data/test/unit/core/schema/fixtures/right_minus_left.yaml +31 -0
  278. data/test/unit/core/schema/fixtures/suppliers_and_parts.yaml +30 -0
  279. data/test/unit/core/schema/fixtures.rb +32 -0
  280. data/test/unit/core/schema/merge.spec +72 -0
  281. data/test/unit/core/schema/minus.spec +26 -0
  282. data/test/unit/core/schema/sanity.spec +39 -0
  283. data/test/unit/core/schema/split.spec +58 -0
  284. data/test/unit/core/schema/stage_script.spec +26 -0
  285. data/test/unit/core/schema/to_yaml.spec +13 -0
  286. data/test/unit/core/schema/yaml_display.spec +14 -0
  287. data/test/unit/core/schema/yaml_load.spec +20 -0
  288. data/test/unit/core/transaction/transaction.spec +10 -0
  289. data/test/unit/fixtures.rb +67 -0
  290. data/test/unit/io/to_xxx.spec +52 -0
  291. data/test/unit/plugin/options.spec +21 -0
  292. data/test/unit/plugin/tuple_heading.spec +11 -0
  293. data/test/unit/plugin/with_options.spec +12 -0
  294. data/test/unit/tools/ruby/class_unqualified_name.spec +26 -0
  295. data/test/unit/tools/ruby/extract_file_rdoc.spec +10 -0
  296. data/test/unit/tools/ruby/fixtures/rdoc.txt +12 -0
  297. data/test/unit/tools/ruby/fixtures.rb +19 -0
  298. data/test/unit/tools/ruby/optional_args_block_call.spec +35 -0
  299. data/test/unit/tools/ruby/parent_module.spec +21 -0
  300. data/test/unit/tools/ruby/rdoc_file_paragraphs.spec +13 -0
  301. data/test/unit/tools/tuple/tuple_heading.spec +11 -0
  302. data/test/unit/tools/tuple/tuple_key.spec +27 -0
  303. data/test/unit/tools/tuple/tuple_project.spec +23 -0
  304. data/test/unit.spec +3 -0
  305. metadata +422 -0
@@ -0,0 +1 @@
1
+ require 'dbagile/command/repo/create.rb'
@@ -0,0 +1,86 @@
1
+ module DbAgile
2
+ class Command
3
+ module Robust
4
+ include DbAgile::Core::IO::Robustness
5
+
6
+ # Raises an OptionParser::InvalidArgument
7
+ def bad_argument_list!(rest, expected_name = nil)
8
+ if rest.empty?
9
+ raise OptionParser::MissingArgument, "#{expected_name}"
10
+ else
11
+ raise OptionParser::InvalidArgument, "#{rest.join(' ')}"
12
+ end
13
+ end
14
+
15
+ # Raises an OptionParser::AmbiguousArgument
16
+ def ambigous_argument_list!
17
+ raise OptionParser::AmbiguousArgument, "Ambiguous options"
18
+ end
19
+
20
+ # Parses pending arguments, assert that it contains exactly
21
+ # types.size arguments, and convert them to types.
22
+ def valid_argument_list!(rest, *types)
23
+ if rest.size == types.size
24
+ result = rest.zip(types).collect do |arg, type|
25
+ if String == type
26
+ arg.to_s
27
+ elsif Symbol == type
28
+ arg.to_sym
29
+ elsif Integer
30
+ arg.to_i
31
+ else
32
+ raise OptionParser::InvalidArgument, arg
33
+ end
34
+ end
35
+ result.size == 1 ? result[0] : result
36
+ elsif rest.size < types.size
37
+ raise OptionParser::MissingArgument
38
+ else
39
+ raise OptionParser::NeedlessArgument, rest
40
+ end
41
+ end
42
+
43
+ # Asserts that an argument matches some candidates or
44
+ # raises a OptionParser::InvalidArgument error.
45
+ def is_in!(name, value, candidates)
46
+ value = valid_argument_list!([ value ], candidates.first.class)
47
+ unless candidates.include?(value)
48
+ raise OptionParser::InvalidArgument, "Expected one of #{candidates.inspect} for #{name}"
49
+ end
50
+ value
51
+ end
52
+
53
+ # Checks that a file exists and can be read or raises an IO error
54
+ def valid_read_file!(file)
55
+ raise IOError, "Unable to read #{file}" unless File.file?(file) and File.readable?(file)
56
+ file
57
+ end
58
+
59
+ #
60
+ # Asserts that a command exists or raises a NoSuchCommandError.
61
+ #
62
+ # @return [DbAgile::Command] the command instance
63
+ #
64
+ def has_command!(name, env)
65
+ cmd = DbAgile::Command.command_for(name, env)
66
+ if cmd.nil?
67
+ DbAgile::Command::CATEGORIES.each{|c|
68
+ cmd = DbAgile::Command.command_for("#{c}:#{name}", env)
69
+ return cmd if cmd
70
+ }
71
+ raise DbAgile::NoSuchCommandError, "No such command #{name.inspect}"
72
+ else
73
+ cmd
74
+ end
75
+ end
76
+
77
+ #
78
+ # Raises a DbAgile::AssumptionFailedError with a specific message
79
+ #
80
+ def assumption_error!(msg)
81
+ raise DbAgile::AssumptionFailedError, msg
82
+ end
83
+
84
+ end # module Robust
85
+ end # class Command
86
+ end # module DbAgile
@@ -0,0 +1,59 @@
1
+ module DbAgile
2
+ class Command
3
+ module Schema
4
+ #
5
+ # Check a database schema
6
+ #
7
+ # Usage: dba #{command_name} [SCHEMA.yaml|announced|effective|physical]
8
+ #
9
+ # This command informs you about bad smells and good practices with relational
10
+ # schemas (i.e. forgetting to create keys, not providing unique constraint
11
+ # names, and so on).
12
+ #
13
+ # dba #{command_name} SCHEMA.yaml
14
+ #
15
+ # Load the schema from file and check it, printing advices and errors on the
16
+ # message console. The command does not connect any database in this mode.
17
+ #
18
+ # dba #{command_name} [announced|effective|physical]
19
+ #
20
+ # Checks a schema of the current database. Announced schema is implicit without
21
+ # any argument. This command uses a fallback chain (announced -> effective ->
22
+ # physical) and has no side-effect on the database itself (read-only).
23
+ #
24
+ class Check < Command
25
+ include Schema::Commons
26
+ Command::build_me(self, __FILE__)
27
+
28
+ # Returns :single
29
+ def kind_of_schema_arguments
30
+ :single
31
+ end
32
+
33
+ # Contribute to options
34
+ def add_options(opt)
35
+ self.check_schemas = false
36
+ end
37
+
38
+ # Executes the command
39
+ def execute_command
40
+ with_schema do |schema|
41
+ errors = schema.check!(false)
42
+ say("\n")
43
+ if errors.empty?
44
+ say("Valid schema (#{schema.schema_identifier.inspect})!", :green)
45
+ say("\n")
46
+ [ schema, errors ]
47
+ else
48
+ say("Invalid schema (#{schema.schema_identifier.inspect}):", :red)
49
+ errors.error_messages.each{|m| say(" * #{m}")}
50
+ say("\n")
51
+ [ schema, errors ]
52
+ end
53
+ end
54
+ end
55
+
56
+ end # class Check
57
+ end # module Schema
58
+ end # class Command
59
+ end # module DbAgile
@@ -0,0 +1,118 @@
1
+ module DbAgile
2
+ class Command
3
+ module Schema
4
+ module Commons
5
+
6
+ # Checks schema(s) first?
7
+ attr_accessor :check_schemas
8
+
9
+ # Schema arguments
10
+ attr_accessor :schema_arguments
11
+
12
+ # Adds --[no-]check option
13
+ def add_check_options(opt)
14
+ self.check_schemas = true
15
+ opt.on('--[no-]check', "Perform/Bypass schema checking") do |value|
16
+ self.check_schemas = value
17
+ end
18
+ end
19
+
20
+ # Normalizes a schema argument
21
+ def normalize_schema_argument(argument)
22
+ if File.exists?(argument) and File.file?(argument)
23
+ argument
24
+ else
25
+ is_in!("schema", argument, [:announced, :effective, :physical])
26
+ end
27
+ end
28
+
29
+ # Normalizes the pending arguments
30
+ def normalize_schema_arguments(arguments)
31
+ @schema_arguments = case kind_of_schema_arguments
32
+ when :single
33
+ if arguments.empty?
34
+ [ :announced ]
35
+ elsif arguments.size == 1
36
+ arguments.collect{|arg| normalize_schema_argument(arg) }
37
+ else
38
+ bad_argument_list!(arguments)
39
+ end
40
+ when :double
41
+ if arguments.empty?
42
+ [ :effective, :announced ]
43
+ elsif arguments.size == 2
44
+ arguments.collect{|arg| normalize_schema_argument(arg) }
45
+ else
46
+ bad_argument_list!(arguments)
47
+ end
48
+ when :multiple
49
+ if arguments.size >= 2
50
+ arguments.collect{|arg| normalize_schema_argument(arg) }
51
+ else
52
+ bad_argument_list!(arguments)
53
+ end
54
+ else
55
+ assumption_error!("Unexpected kind of schema argument #{kind_of_schema_arguments}")
56
+ end
57
+ end
58
+
59
+ # Normalizes the pending arguments
60
+ def normalize_pending_arguments(arguments)
61
+ normalize_schema_arguments(arguments)
62
+ end
63
+
64
+ # Loads a given schema from a schema argument
65
+ def load_schema(schema_argument, check = self.check_schemas)
66
+ schema = case schema_argument
67
+ when Symbol
68
+ with_current_database do |database|
69
+ case schema_argument
70
+ when :announced
71
+ database.announced_schema(true)
72
+ when :effective
73
+ database.effective_schema(true)
74
+ when :physical
75
+ database.physical_schema
76
+ end
77
+ end
78
+ when String
79
+ s = DbAgile::Core::Schema::yaml_file_load(schema_argument)
80
+ s.schema_identifier = schema_argument
81
+ s
82
+ end
83
+
84
+ # A small check, to be sure
85
+ if schema.nil?
86
+ assumption_error!("Unexpected schema argument kind #{schema_argument}")
87
+ end
88
+
89
+ # Check schema if requested
90
+ if check
91
+ schema.check!
92
+ end
93
+
94
+ # Return schema now
95
+ schema
96
+ end
97
+
98
+ # Yields the block, passing schemas as an array, according to
99
+ # kind_of_schema_arguments
100
+ def with_schemas(check = self.check_schemas)
101
+ schemas = schema_arguments.collect{|arg| load_schema(arg, check)}
102
+ case kind_of_schema_arguments
103
+ when :single
104
+ yield(schemas.first)
105
+ when :double
106
+ yield(schemas[0], schemas[1])
107
+ when :multiple
108
+ yield(schemas)
109
+ else
110
+ assumption_error!("Unexpected kind of schema argument #{kind_of_schema_arguments}")
111
+ end
112
+ end
113
+ alias :with_schema :with_schemas
114
+
115
+ end # module Commons
116
+ end # module Schema
117
+ end # class Command
118
+ end # module DbAgile
@@ -0,0 +1,101 @@
1
+ module DbAgile
2
+ class Command
3
+ module Schema
4
+ #
5
+ # Show differences between database schemas
6
+ #
7
+ # Usage: dba #{command_name} [schema1 schema2]
8
+ #
9
+ # This command is a diff for database schemas, helping database staging
10
+ # and migrations by showing objects to create/drop/alter.
11
+ #
12
+ # dba #{command_name}
13
+ #
14
+ # Shortcut for 'dba schema:diff announced effective'
15
+ #
16
+ # dba #{command_name} schema1 schema2
17
+ #
18
+ # Show differences between two particular schemas, being either installed
19
+ # schemas [announced|effective|physical] or schema files. This command
20
+ # uses a fallback chain (announced -> effective -> physical) and has no
21
+ # side-effect on the database itself (read-only).
22
+ #
23
+ # NOTE: Schema-checking is on by default, which may lead to checking errors,
24
+ # typically when reverse engineering poorly designed databases. Doing so
25
+ # immediately informs you about a potential problem.
26
+ #
27
+ # Use --no-check to bypass schema checking. See also schema:check.
28
+ #
29
+ class Diff < Command
30
+ include Schema::Commons
31
+ Command::build_me(self, __FILE__)
32
+
33
+ # Output options
34
+ attr_reader :output_options
35
+
36
+ # Sets the default options
37
+ def set_default_options
38
+ @output_options = {:skip_unchanged => false}
39
+ end
40
+
41
+ # Contribute to options
42
+ def add_options(opt)
43
+ opt.separator nil
44
+ opt.separator "Options:"
45
+ add_check_options(opt)
46
+ opt.on("--[no-]skip-unchanged", "-u",
47
+ "Don't show objects that did'nt change") do |value|
48
+ self.output_options[:skip_unchanged] = value
49
+ end
50
+ end
51
+
52
+ # Returns :single
53
+ def kind_of_schema_arguments
54
+ :double
55
+ end
56
+
57
+ # Executes the command
58
+ def execute_command
59
+ with_schemas do |left, right|
60
+ merged = DbAgile::Core::Schema::merge(left, right)
61
+ show_diff(left, right, merged, environment, output_options)
62
+ merged
63
+ end
64
+ end
65
+
66
+ # Shows difference between left and right
67
+ def show_diff(left, right, merged, environment, output_options)
68
+ # Validity
69
+ if left.looks_valid?
70
+ lv = environment.color("(valid!)", :green)
71
+ else
72
+ lv = environment.color("(INVALID, you'd better run 'dba schema:check --effective')", HighLine::RED + HighLine::BOLD)
73
+ end
74
+ if right.looks_valid?
75
+ rv = environment.color("(valid!)", :green)
76
+ else
77
+ rv = environment.color("(INVALID, you'd better run 'dba schema:check')", HighLine::RED + HighLine::BOLD)
78
+ end
79
+
80
+ # Debug
81
+ ld, rd = left.schema_identifier.inspect, right.schema_identifier.inspect
82
+ ld, rd = "#{ld} #{lv}", "#{rd} #{rv}"
83
+
84
+ # Say
85
+ environment.say '###'
86
+ environment.say "### LEFT: #{ld}"
87
+ environment.say "### RIGHT: #{rd}"
88
+ environment.say '###'
89
+ environment.say "### " + environment.color('Objects to add on LEFT', :green)
90
+ environment.say '### ' + environment.color('Objects to remove on LEFT', :red)
91
+ environment.say '### ' + environment.color('Objects to alter on LEFT', :cyan)
92
+ environment.say '###'
93
+ environment.say "\n"
94
+ merged.yaml_display(environment, output_options)
95
+ environment.say "\n"
96
+ end
97
+
98
+ end # class SchemaDump
99
+ end # module Schema
100
+ end # class Command
101
+ end # module DbAgile
@@ -0,0 +1,48 @@
1
+ module DbAgile
2
+ class Command
3
+ module Schema
4
+ #
5
+ # Dump a schema of the current database
6
+ #
7
+ # Usage: dba #{command_name} [announced|effective|physical]
8
+ #
9
+ # This command dumps the schema of the current database on the output console.
10
+ # Without argument, the announced schema is implicit. This command uses the
11
+ # fallback chain (announced -> effective -> physical) and has no side-effect
12
+ # on the database itself (read-only).
13
+ #
14
+ # NOTE: Schema-checking is on by default, which may lead to checking errors,
15
+ # typically when reverse engineering poorly designed databases. Doing so
16
+ # immediately informs you about a potential problem.
17
+ #
18
+ # Use --no-check to bypass schema checking. See also schema:check.
19
+ #
20
+ class Dump < Command
21
+ include Schema::Commons
22
+ Command::build_me(self, __FILE__)
23
+
24
+ # Contribute to options
25
+ def add_options(opt)
26
+ opt.separator nil
27
+ opt.separator "Options:"
28
+ add_check_options(opt)
29
+ end
30
+
31
+ # Returns :single
32
+ def kind_of_schema_arguments
33
+ :single
34
+ end
35
+
36
+ # Executes the command
37
+ def execute_command
38
+ with_schema do |schema|
39
+ say("# Schema of #{schema.schema_identifier.inspect}", :magenta)
40
+ flush(schema.to_yaml)
41
+ schema
42
+ end
43
+ end
44
+
45
+ end # class SchemaDump
46
+ end # module Schema
47
+ end # class Command
48
+ end # module DbAgile
@@ -0,0 +1,55 @@
1
+ module DbAgile
2
+ class Command
3
+ module Schema
4
+ #
5
+ # Merge a list of schemas
6
+ #
7
+ # Usage: dba #{command_name} SCHEMA_ARG, ...
8
+ #
9
+ # This command merges all schema in arguments into a single schema and dumps the
10
+ # result in YAML on the output console. Schema arguments may be schema files or
11
+ # schemas installed on the current database [announced|effective|physical]. This
12
+ # command uses the fallback chain (announced -> effective -> physical) and has no
13
+ # side-effect on the database itself (read-only).
14
+ #
15
+ # NOTE: Schema-checking is on by default and applied on the resulting schema.
16
+ # This which may lead to checking errors when reverse engineering poorly
17
+ # designed databases. Doing so immediately informs you about a potential
18
+ # problem.
19
+ #
20
+ # Use --no-check to bypass schema checking. See also schema:check.
21
+ #
22
+ class Merge < Command
23
+ include Schema::Commons
24
+ Command::build_me(self, __FILE__)
25
+
26
+ # Contribute to options
27
+ def add_options(opt)
28
+ opt.separator nil
29
+ opt.separator "Options:"
30
+ add_check_options(opt)
31
+ end
32
+
33
+ # Returns :single
34
+ def kind_of_schema_arguments
35
+ :multiple
36
+ end
37
+
38
+ # Executes the command
39
+ def execute_command
40
+ with_schemas(false) do |schemas|
41
+ empty = DbAgile::Core::Schema::EMPTY_SCHEMA
42
+ result = schemas.inject(empty){|memo,schema| memo + schema}
43
+ if self.check_schemas
44
+ result.check!
45
+ say("# And the result is valid!", :green)
46
+ end
47
+ flush(result.to_yaml)
48
+ result
49
+ end
50
+ end
51
+
52
+ end # class SchemaDump
53
+ end # module Schema
54
+ end # class Command
55
+ end # module DbAgile
@@ -0,0 +1,124 @@
1
+ module DbAgile
2
+ class Command
3
+ module Schema
4
+ #
5
+ # Flush a SQL script for a creating/dropping/staging a schema
6
+ #
7
+ # Usage: dba #{command_name} {create, drop, stage} [SCHEMA_ARG, ...]
8
+ #
9
+ # dba #{command_name} create [announced|effective|physical|FILE.yaml]
10
+ #
11
+ # Flush a SQL script for creating a SQL database from a schema. Announced
12
+ # schema of the database is the default. This command uses the fallback chain
13
+ # (announced -> effective -> physical) and has no side-effect on the database
14
+ # itself (read-only).
15
+ #
16
+ # dba #{command_name} drop [announced|effective|physical|FILE.yaml]
17
+ #
18
+ # Flush a SQL script for dropping all objects of a SQL database. Announced
19
+ # schema of the database is the default. This command uses the fallback chain
20
+ # (announced -> effective -> physical) and has no side-effect on the database
21
+ # itself (read-only).
22
+ #
23
+ # dba #{command_name} stage [schema1 schema2]
24
+ #
25
+ # Flush a SQL script for staging a database from schema1 to schema2. Arguments
26
+ # can be installed schemas of the current database or schema files. Effective
27
+ # and announced schema of the current database are respectively used by default.
28
+ # The command uses the fallback chain (announced -> effective -> physical) and
29
+ # has no side-effect on the current database itself (read-only).
30
+ #
31
+ # Schema-checking is on by default, which may lead to checking errors, typically
32
+ # when reverse engineering poorly designed databases. Doing so immediately informs
33
+ # you about a potential problem.
34
+ #
35
+ # Use --no-check to bypass schema checking. See also schema:check.
36
+ #
37
+ class SqlScript < Command
38
+ include Schema::Commons
39
+ Command::build_me(self, __FILE__)
40
+
41
+ # Kinds of script
42
+ SCRIPT_KIND = [:create, :drop, :stage]
43
+
44
+ # Kind of script [:create, :drop, :stage]
45
+ attr_accessor :script_kind
46
+
47
+ # Contribute to options
48
+ def add_options(opt)
49
+ opt.separator nil
50
+ opt.separator "Options:"
51
+ add_check_options(opt)
52
+ end
53
+
54
+ # Returns :single
55
+ def kind_of_schema_arguments
56
+ if script_kind == :stage
57
+ :double
58
+ else
59
+ :single
60
+ end
61
+ end
62
+
63
+ # Normalizes the pending arguments
64
+ def normalize_pending_arguments(arguments)
65
+ case arguments.size
66
+ when 0
67
+ bad_argument_list!(arguments, "script kind")
68
+ else
69
+ self.script_kind = is_in!("script kind", arguments.shift, SCRIPT_KIND)
70
+ normalize_schema_arguments(arguments)
71
+ end
72
+ end
73
+
74
+ # Executes the command
75
+ def execute_command
76
+ case kind_of_schema_arguments
77
+ when :single
78
+ execute_single_command
79
+ when :double
80
+ execute_double_command
81
+ end
82
+ end
83
+
84
+ # Execution for :create and :drop
85
+ def execute_single_command
86
+ script = with_schema{|schema|
87
+ case self.script_kind
88
+ when :create
89
+ DbAgile::Core::Schema::create_script(schema)
90
+ when :drop
91
+ DbAgile::Core::Schema::drop_script(schema)
92
+ else
93
+ raise DbAgile::AssumptionFailedError, "Unknown script kind #{self.script_kind}"
94
+ end
95
+ }
96
+ with_current_connection{|conn|
97
+ conn.script2sql(script, environment.output_buffer)
98
+ }
99
+ end
100
+
101
+ # Execution for :stage
102
+ def execute_double_command
103
+ script = with_schemas{|left, right|
104
+ case self.script_kind
105
+ when :stage
106
+ merged = left + right
107
+ script = DbAgile::Core::Schema::stage_script(merged)
108
+ if merged.status == DbAgile::Core::Schema::NO_CHANGE
109
+ say("Nothing to stage", :magenta)
110
+ end
111
+ script
112
+ else
113
+ raise DbAgile::AssumptionFailedError, "Unknown script kind #{self.script_kind}"
114
+ end
115
+ }
116
+ with_current_connection{|conn|
117
+ conn.script2sql(script, environment.output_buffer)
118
+ }
119
+ end
120
+
121
+ end # class CreateScript
122
+ end # module Schema
123
+ end # class Command
124
+ end # module DbAgile
@@ -0,0 +1,6 @@
1
+ require 'dbagile/command/schema/commons'
2
+ require 'dbagile/command/schema/dump'
3
+ require 'dbagile/command/schema/check'
4
+ require 'dbagile/command/schema/diff'
5
+ require 'dbagile/command/schema/merge'
6
+ require 'dbagile/command/schema/sql_script'
@@ -0,0 +1,40 @@
1
+ module DbAgile
2
+ class Command
3
+ module SQL
4
+ #
5
+ # Drop a table from a SQL database
6
+ #
7
+ # Usage: dba #{command_name} TABLE
8
+ #
9
+ # This command issues a "DROP TABLE ..." in the DbAgile's command chain, therefore
10
+ # targetting the schema of the physical SQL database and bypassing other schemas if
11
+ # present (announced and effectice schemas in particular).
12
+ #
13
+ # As it may lead to divergences between schemas, and between effective and physical
14
+ # schemas in particular, you should consider using schema:* commands instead, when
15
+ # possible.
16
+ #
17
+ class Drop < Command
18
+ Command::build_me(self, __FILE__)
19
+
20
+ # Table which must be dropped
21
+ attr_accessor :table
22
+
23
+ # Normalizes the pending arguments
24
+ def normalize_pending_arguments(arguments)
25
+ self.table = valid_argument_list!(arguments, Symbol)
26
+ end
27
+
28
+ # Executes the command
29
+ def execute_command
30
+ with_current_connection do |connection|
31
+ connection.transaction do |t|
32
+ t.drop_table(self.table)
33
+ end
34
+ end
35
+ end
36
+
37
+ end # class Drop
38
+ end # module SQL
39
+ end # class Command
40
+ end # module DbAgile
@@ -0,0 +1,34 @@
1
+ module DbAgile
2
+ class Command
3
+ module SQL
4
+ #
5
+ # Show the heading of a table
6
+ #
7
+ # Usage: dba #{command_name} TABLE
8
+ #
9
+ # This commands shows a list with columns names and types for a given table
10
+ # of the current SQL database.
11
+ #
12
+ class Heading < Command
13
+ Command::build_me(self, __FILE__)
14
+
15
+ # Table whose heading must be displayed
16
+ attr_accessor :dataset
17
+
18
+ # Normalizes the pending arguments
19
+ def normalize_pending_arguments(arguments)
20
+ self.dataset = valid_argument_list!(arguments, Symbol)
21
+ end
22
+
23
+ # Executes the command
24
+ def execute_command
25
+ with_current_connection do |connection|
26
+ heading = connection.heading(self.dataset)
27
+ flush("{\n" + heading.collect{|pair| " #{pair[0]}: #{pair[1]}"}.join(",\n") + "\n}\n")
28
+ heading
29
+ end
30
+ end
31
+ end # class Heading
32
+ end # # module SQL
33
+ end # class Command
34
+ end # module DbAgile