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,16 @@
1
+ require File.expand_path('../fixtures', __FILE__)
2
+ describe "DbAgile::Core::Repository#has_database?" do
3
+
4
+ let(:repository){ DbAgile::Fixtures::Core::Repository::repository(:test_and_prod) }
5
+
6
+ describe("When called with an unexisting database") do
7
+ subject{ repository.has_database?(:test) }
8
+ it{ should == true }
9
+ end
10
+
11
+ describe("When called with an missing database") do
12
+ subject{ repository.has_database?(:nosuchone) }
13
+ it{ should == false }
14
+ end
15
+
16
+ end
@@ -0,0 +1,51 @@
1
+ require File.expand_path('../fixtures', __FILE__)
2
+ describe "DbAgile::Core::Repository::load /" do
3
+
4
+ let(:loader){ lambda{ DbAgile::Core::Repository::load(path) } }
5
+
6
+ describe "on a valid repository /" do
7
+ let(:path){ DbAgile::Fixtures::Core::Repository::repository_path(:test_and_prod) }
8
+ let(:loaded){ loader.call }
9
+
10
+ it "should not raise any error" do
11
+ loader.should_not raise_error
12
+ end
13
+
14
+ it "should return a Repository instance" do
15
+ loaded.should be_kind_of(DbAgile::Core::Repository)
16
+ end
17
+
18
+ it "should have a version number" do
19
+ loaded.version.should_not be_nil
20
+ end
21
+
22
+ end # valid
23
+
24
+ describe "on an unexisting repository /" do
25
+ let(:path){ DbAgile::Fixtures::Core::Repository::repository_path(:unexisting) }
26
+
27
+ it "should raise an IOError" do
28
+ loader.should raise_error(IOError)
29
+ end
30
+
31
+ end # unexisting
32
+
33
+ describe "on an invalid repository /" do
34
+ let(:path){ DbAgile::Fixtures::Core::Repository::repository_path(:invalid) }
35
+
36
+ it "should raise an IOError" do
37
+ loader.should raise_error(IOError)
38
+ end
39
+
40
+ end # invalid
41
+
42
+ describe "on an corrupted repository /" do
43
+ let(:path){ DbAgile::Fixtures::Core::Repository::repository_path(:corrupted) }
44
+
45
+ it "should raise a CorruptedRepositoryError" do
46
+ loader.should raise_error(DbAgile::CorruptedRepositoryError)
47
+ end
48
+
49
+ end # corrupted
50
+
51
+ end
@@ -0,0 +1,17 @@
1
+ require File.expand_path('../fixtures', __FILE__)
2
+ describe "DbAgile::Core::Repository#to_yaml /" do
3
+
4
+ let(:path){ DbAgile::Fixtures::Core::Repository::repository_path(:test_and_prod) }
5
+ let(:repo){ DbAgile::Core::Repository::load(path) }
6
+
7
+ it "should return a valid yaml string" do
8
+ repo.to_yaml.should be_a_valid_yaml_string
9
+ end
10
+
11
+ it "should be such that a repository could be created" do
12
+ got = DbAgile::Core::Repository.send(:from_yaml, repo.to_yaml, path)
13
+ got.should be_kind_of(DbAgile::Core::Repository)
14
+ end
15
+
16
+ end
17
+
@@ -0,0 +1,32 @@
1
+ require File.expand_path('../fixtures', __FILE__)
2
+ describe "DbAgile::Core::Schema checking" do
3
+
4
+ subject{ lambda{ schema.check! } }
5
+
6
+ [:dbagile,
7
+ :left, :right,
8
+ :suppliers_and_parts].each{|k|
9
+ it "should be ok on #{k}" do
10
+ schema = DbAgile::Fixtures::Core::Schema::schema(k)
11
+ lambda{ schema.check! }.should_not raise_error
12
+ end
13
+ }
14
+
15
+ describe "when called on an invalid schema" do
16
+ let(:schema){ DbAgile::Fixtures::Core::Schema::schema(:invalid) }
17
+ specify{
18
+ subject.should raise_error(DbAgile::SchemaSemanticsError)
19
+
20
+ # each relvar has exactly one error except:
21
+ # - VALID, which is valid -> -1
22
+ # - EMPTY (no pkey, empty heading) -> +1
23
+ expected_size = schema.logical.size - 1 + 1
24
+
25
+ # each index has exactly one error
26
+ expected_size += schema.physical.indexes.size
27
+
28
+ schema.check!(false).size.should == expected_size
29
+ }
30
+ end
31
+
32
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path('../fixtures', __FILE__)
2
+ describe "DbAgile::Core::Schema#empty?" do
3
+
4
+ it "should not be empty on a non empty schema" do
5
+ [:left, :right].each{|n|
6
+ schema = DbAgile::Fixtures::Core::Schema::schema(n)
7
+ schema.empty?.should be_false
8
+ }
9
+ end
10
+
11
+ it "should be empty on a empty schema" do
12
+ [:empty].each{|n|
13
+ schema = DbAgile::Fixtures::Core::Schema::schema(n)
14
+ schema.empty?.should be_true
15
+ }
16
+ end
17
+
18
+ end
@@ -0,0 +1,42 @@
1
+ require File.expand_path('../fixtures', __FILE__)
2
+ describe "DbAgile::Core::Schema#filter" do
3
+
4
+ let(:schema) { DbAgile::Fixtures::Core::Schema::schema(:suppliers_and_parts) }
5
+
6
+ it "should filter correctly through constraint/not constraint separation" do
7
+ constraints = schema.filter{|k| k.constraint?}
8
+ others = schema.filter{|k| !k.constraint?}
9
+ constraints.visit{|o, parent|
10
+ unless o.composite?
11
+ o.should be_kind_of(DbAgile::Core::Schema::Logical::Constraint)
12
+ end
13
+ }
14
+ others.visit{|o, parent|
15
+ unless o.composite?
16
+ o.should_not be_kind_of(DbAgile::Core::Schema::Logical::Constraint)
17
+ end
18
+ }
19
+ # puts constraints.to_yaml
20
+ # puts others.to_yaml
21
+ (constraints + others).look_same_as?(schema).should be_true
22
+ end
23
+
24
+ it "should filter correctly through logical/physical separation" do
25
+ logical = schema.filter{|k| k.logical?}
26
+ physical = schema.filter{|k| k.physical?}
27
+ logical.visit{|o, parent|
28
+ unless o.composite?
29
+ o.logical?.should be_true
30
+ end
31
+ }
32
+ physical.visit{|o, parent|
33
+ unless o.composite?
34
+ o.physical?.should be_true
35
+ end
36
+ }
37
+ # puts logical.to_yaml
38
+ # puts physical.to_yaml
39
+ (logical + physical).look_same_as?(schema).should be_true
40
+ end
41
+
42
+ end
@@ -0,0 +1,7 @@
1
+ ---
2
+ logical:
3
+ DBAGILE_INFO:
4
+ heading:
5
+ VERSION: { domain: String, mandatory: true }
6
+ constraints:
7
+ pk: { type: :primary_key, attributes: [ 'VERSION' ] }
@@ -0,0 +1,11 @@
1
+ # This is a comment
2
+ ---
3
+ logical:
4
+ # Here also
5
+ EMPTY_RELVAR:
6
+ heading: {}
7
+ constraints: {}
8
+ ---
9
+ physical:
10
+ indexes: {}
11
+
@@ -0,0 +1,54 @@
1
+ ---
2
+ logical:
3
+ VALID_WITH_SINGLE_PK:
4
+ heading:
5
+ ID: { domain: Integer, mandatory: true }
6
+ constraints:
7
+ pk: { type: primary_key, attributes: [ 'ID' ]}
8
+ EMPTY:
9
+ heading: {}
10
+ constraints: {}
11
+ MISSING_PRIMARY_KEY:
12
+ heading:
13
+ ID: { domain: Integer, mandatory: true }
14
+ BAD_CANDIDATE_KEY_NOSUCH_ATTRIBUTES:
15
+ heading:
16
+ ID: { domain: Integer, mandatory: true }
17
+ constraints:
18
+ pk: { type: primary_key, attributes: [ 'NOT_EXISTS' ] }
19
+ BAD_FOREIGN_KEY_NO_SUCH_REFERENCED_RELVAR:
20
+ heading:
21
+ ID: { domain: Integer, mandatory: true }
22
+ constraints:
23
+ pk: { type: primary_key, attributes: [ 'ID' ]}
24
+ fk: { type: foreign_key, attributes: [ 'ID' ], references: 'NO' }
25
+ BAD_FOREIGN_KEY_NO_SUCH_SOURCE_ATTRIBUTES:
26
+ heading:
27
+ ID: { domain: Integer, mandatory: true }
28
+ constraints:
29
+ pk: { type: primary_key, attributes: [ 'ID' ]}
30
+ fk: { type: foreign_key, attributes: [ 'NONE' ], references: 'VALID_WITH_SINGLE_PK' }
31
+ BAD_FOREIGN_KEY_NO_SUCH_TARGET_KEY:
32
+ heading:
33
+ ID: { domain: Integer, mandatory: true }
34
+ constraints:
35
+ pk: { type: primary_key, attributes: [ 'ID' ]}
36
+ fk: { type: foreign_key, attributes: [ 'ID' ], references: 'VALID_WITH_SINGLE_PK', key: no_suck_pk }
37
+ BAD_FOREIGN_KEY_TARGET_KEY_SIZE_MISMATCH:
38
+ heading:
39
+ ID: { domain: Integer, mandatory: true }
40
+ NAME: { domain: String, mandatory: true }
41
+ constraints:
42
+ pk: { type: primary_key, attributes: [ 'ID' ]}
43
+ fk: { type: foreign_key, attributes: [ 'ID', 'NAME' ], references: 'VALID_WITH_SINGLE_PK' }
44
+ BAD_FOREIGN_KEY_TARGET_KEY_MISMATCH:
45
+ heading:
46
+ ID: { domain: String, mandatory: true }
47
+ constraints:
48
+ pk: { type: primary_key, attributes: [ 'ID' ]}
49
+ fk: { type: foreign_key, attributes: [ 'ID' ], references: 'VALID_WITH_SINGLE_PK' }
50
+ ---
51
+ physical:
52
+ indexes:
53
+ INVALID_INDEX_NO_SUCH_RELVAR: { relvar: NOSUCH_RELVAR, attributes: ['ID'] }
54
+ INVALID_INDEX_NO_SUCH_ATTR: { relvar: VALID_WITH_SINGLE_PK, attributes: ['NOSUCH_ATTR'] }
@@ -0,0 +1,46 @@
1
+ ---
2
+ logical:
3
+ ADDED_COLUMNS_ON_LEFT:
4
+ heading:
5
+ ID: { domain: Integer, mandatory: true }
6
+ ADDED: { domain: String, mandatory: true }
7
+ constraints:
8
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
9
+ ADDED_CONSTRAINT_ON_LEFT:
10
+ heading:
11
+ ID: { domain: Integer, mandatory: true }
12
+ constraints:
13
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
14
+ added_constraint: { type: :foreign_key, attributes: [ 'ID' ], references: ADDED_COLUMNS_ON_LEFT}
15
+ CONFLICTING_HEADING:
16
+ heading:
17
+ NO_CONFLICT: { domain: Float, mandatory: true }
18
+ CONFLICT: { domain: Integer, mandatory: true }
19
+ constraints:
20
+ pk: { type: :primary_key, attributes: [ 'NO_CONFLICT' ] }
21
+ DROPPED_COLUMNS_ON_LEFT:
22
+ heading:
23
+ ID: { domain: Integer, mandatory: true }
24
+ constraints:
25
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
26
+ DROPPED_CONSTRAINT_ON_LEFT:
27
+ heading:
28
+ ID: { domain: Integer, mandatory: true }
29
+ constraints:
30
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
31
+ ONLY_ON_LEFT_RELVAR:
32
+ heading:
33
+ ID: { domain: Integer, mandatory: true }
34
+ constraints:
35
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
36
+ SAME:
37
+ heading:
38
+ ID: { domain: Integer, mandatory: true }
39
+ constraints:
40
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
41
+ ---
42
+ physical:
43
+ indexes:
44
+ COMMON_INDEX: { relvar: ADDED_COLUMNS_ON_LEFT, attributes: [ 'ID' ] }
45
+ ONLY_ON_LEFT_INDEX: { relvar: ONLY_ON_LEFT_RELVAR, attributes: [ 'ID' ] }
46
+
@@ -0,0 +1,31 @@
1
+ ---
2
+ logical:
3
+ ADDED_COLUMNS_ON_LEFT:
4
+ heading:
5
+ ADDED: { domain: String, mandatory: true }
6
+ constraints: {}
7
+ ADDED_CONSTRAINT_ON_LEFT:
8
+ heading: {}
9
+ constraints:
10
+ added_constraint: { type: :foreign_key, attributes: [ 'ID' ], references: ADDED_COLUMNS_ON_LEFT}
11
+ CONFLICTING_HEADING:
12
+ heading:
13
+ CONFLICT: { domain: Integer, mandatory: true }
14
+ constraints: {}
15
+ DROPPED_COLUMNS_ON_LEFT:
16
+ heading: {}
17
+ constraints: {}
18
+ DROPPED_CONSTRAINT_ON_LEFT:
19
+ heading: {}
20
+ constraints: {}
21
+ ONLY_ON_LEFT_RELVAR:
22
+ heading:
23
+ ID: { domain: Integer, mandatory: true }
24
+ constraints:
25
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
26
+ SAME: {}
27
+ ---
28
+ physical:
29
+ indexes:
30
+ ONLY_ON_LEFT_INDEX: { relvar: ONLY_ON_LEFT_RELVAR, attributes: [ 'ID' ] }
31
+
@@ -0,0 +1,46 @@
1
+ ---
2
+ logical:
3
+ ADDED_COLUMNS_ON_LEFT:
4
+ heading:
5
+ ID: { domain: Integer, mandatory: true }
6
+ constraints:
7
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
8
+ ADDED_CONSTRAINT_ON_LEFT:
9
+ heading:
10
+ ID: { domain: Integer, mandatory: true }
11
+ constraints:
12
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
13
+ CONFLICTING_HEADING:
14
+ heading:
15
+ NO_CONFLICT: { domain: Float, mandatory: true }
16
+ CONFLICT: { domain: String, mandatory: false }
17
+ constraints:
18
+ pk: { type: :primary_key, attributes: [ 'NO_CONFLICT' ] }
19
+ DROPPED_COLUMNS_ON_LEFT:
20
+ heading:
21
+ ID: { domain: Integer, mandatory: true }
22
+ DROPPED: { domain: String, mandatory: true }
23
+ constraints:
24
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
25
+ DROPPED_CONSTRAINT_ON_LEFT:
26
+ heading:
27
+ ID: { domain: Integer, mandatory: true }
28
+ constraints:
29
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
30
+ dropped_constraint: { type: :foreign_key, references: ADDED_COLUMNS_ON_LEFT, attributes: [ 'ID' ] }
31
+ ONLY_ON_RIGHT_RELVAR:
32
+ heading:
33
+ ID: { domain: Integer, mandatory: true }
34
+ constraints:
35
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
36
+ SAME:
37
+ heading:
38
+ ID: { domain: Integer, mandatory: true }
39
+ constraints:
40
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
41
+ ---
42
+ physical:
43
+ indexes:
44
+ ONLY_ON_RIGHT_INDEX: { relvar: ONLY_ON_RIGHT_RELVAR, attributes: [ 'ID' ] }
45
+ COMMON_INDEX: { relvar: ADDED_COLUMNS_ON_LEFT, attributes: [ 'ID' ] }
46
+
@@ -0,0 +1,31 @@
1
+ ---
2
+ logical:
3
+ ADDED_COLUMNS_ON_LEFT:
4
+ heading: {}
5
+ constraints: {}
6
+ ADDED_CONSTRAINT_ON_LEFT:
7
+ heading: {}
8
+ constraints: {}
9
+ CONFLICTING_HEADING:
10
+ heading:
11
+ CONFLICT: { domain: String, mandatory: false }
12
+ constraints: {}
13
+ DROPPED_COLUMNS_ON_LEFT:
14
+ heading:
15
+ DROPPED: { domain: String, mandatory: true }
16
+ constraints: {}
17
+ DROPPED_CONSTRAINT_ON_LEFT:
18
+ heading: {}
19
+ constraints:
20
+ dropped_constraint: { type: :foreign_key, attributes: [ 'ID' ], references: ADDED_COLUMNS_ON_LEFT }
21
+ ONLY_ON_RIGHT_RELVAR:
22
+ heading:
23
+ ID: { domain: Integer, mandatory: true }
24
+ constraints:
25
+ pk: { type: :primary_key, attributes: [ 'ID' ] }
26
+ SAME: {}
27
+ ---
28
+ physical:
29
+ indexes:
30
+ ONLY_ON_RIGHT_INDEX: { relvar: ONLY_ON_RIGHT_RELVAR, attributes: [ 'ID' ] }
31
+
@@ -0,0 +1,30 @@
1
+ ---
2
+ logical:
3
+ SUPPLIERS:
4
+ heading:
5
+ S#: { domain: Integer, mandatory: true }
6
+ NAME: { domain: String, mandatory: true }
7
+ CITY: { domain: String, mandatory: true }
8
+ constraints:
9
+ pk: { type: :primary_key, attributes: [ 'S#' ] }
10
+ PARTS:
11
+ heading:
12
+ P#: { domain: Integer, mandatory: true }
13
+ NAME: { domain: String, mandatory: true }
14
+ COLOR: { domain: String, mandatory: true }
15
+ constraints:
16
+ pk: { type: :primary_key, attributes: [ 'P#' ] }
17
+ SUPPLIES:
18
+ heading:
19
+ S#: { domain: Integer, mandatory: true }
20
+ P#: { domain: Integer, mandatory: true }
21
+ QTY: { domain: Integer, mandatory: true }
22
+ constraints:
23
+ pk: { type: :primary_key, attributes: [ 'S#', 'P#' ] }
24
+ is_a_known_supplier: { type: :foreign_key, attributes: [ 'S#' ], references: :SUPPLIERS }
25
+ is_a_known_part: { type: :foreign_key, attributes: [ 'P#' ], references: :PARTS }
26
+ ---
27
+ physical:
28
+ indexes:
29
+ SUPPLIER_NAMES: { relvar: SUPPLIERS, attributes: [ 'NAME' ] }
30
+
@@ -0,0 +1,32 @@
1
+ require File.expand_path('../../../fixtures', __FILE__)
2
+ module DbAgile
3
+ module Fixtures
4
+ module Core
5
+ module Schema
6
+
7
+ # Returns a schema file
8
+ def schema_file(name_or_file)
9
+ if name_or_file.kind_of?(Symbol)
10
+ name_or_file = schema_file("#{name_or_file}.yaml")
11
+ end
12
+ unless name_or_file[0, 1] == '/'
13
+ name_or_file = File.expand_path("../fixtures/#{name_or_file}", __FILE__)
14
+ end
15
+ name_or_file
16
+ end
17
+
18
+ # Yields block for each schema file
19
+ def each_schema_file(&block)
20
+ Dir[File.expand_path("../fixtures/*.yaml", __FILE__)].each(&block)
21
+ end
22
+
23
+ # Returns a Schema instance for a given name
24
+ def schema(name_or_file)
25
+ DbAgile::Core::Schema::yaml_file_load(schema_file(name_or_file))
26
+ end
27
+
28
+ extend(Schema)
29
+ end # module Schema
30
+ end # module Core
31
+ end # module Fixtures
32
+ end # module DbAgile
@@ -0,0 +1,72 @@
1
+ require File.expand_path('../fixtures', __FILE__)
2
+ describe "DbAgile::Core::Schema#merge" do
3
+
4
+ let(:left) { DbAgile::Fixtures::Core::Schema::schema(:left) }
5
+ let(:right) { DbAgile::Fixtures::Core::Schema::schema(:right) }
6
+ let(:empty) { DbAgile::Fixtures::Core::Schema::schema(:empty) }
7
+ let(:sap) { DbAgile::Fixtures::Core::Schema::schema(:suppliers_and_parts) }
8
+
9
+ it "should correctly label all nodes without conflict resolver" do
10
+ status = DbAgile::Core::Schema
11
+ schema = DbAgile::Core::Schema::merge(left, right){|l,r| nil}
12
+ schema.visit{|p, parent|
13
+ s = case p
14
+ when DbAgile::Core::Schema::Logical::Relvar
15
+ case p.name
16
+ when :ADDED_COLUMNS_ON_LEFT,
17
+ :ADDED_CONSTRAINT_ON_LEFT,
18
+ :DROPPED_COLUMNS_ON_LEFT,
19
+ :DROPPED_CONSTRAINT_ON_LEFT,
20
+ status::TO_ALTER
21
+ when :ONLY_ON_LEFT_RELVAR,
22
+ status::TO_DROP
23
+ when :ONLY_ON_RIGHT_RELVAR
24
+ status::TO_CREATE
25
+ when :SAME
26
+ status::NO_CHANGE
27
+ end
28
+ when DbAgile::Core::Schema::Logical::Attribute
29
+ case p.name
30
+ when :ADDED
31
+ status::TO_DROP
32
+ when :DROPPED
33
+ status::TO_CREATE
34
+ end
35
+ when DbAgile::Core::Schema::Physical::Index
36
+ case p.name
37
+ when :ONLY_ON_LEFT_INDEX
38
+ status::TO_DROP
39
+ when :ONLY_ON_RIGHT_INDEX
40
+ status::TO_CREATE
41
+ when :COMMON_INDEX
42
+ status::NO_CHANGE
43
+ end
44
+ when DbAgile::Core::Schema::Logical::Constraint
45
+ case p.name
46
+ when :added_constraint
47
+ status::TO_DROP
48
+ when :dropped_constraint
49
+ status::TO_CREATE
50
+ end
51
+ end
52
+ p.status.should == s unless s.nil?
53
+ }
54
+ end
55
+
56
+ it "should raise a conflict error with a resolver" do
57
+ lambda{ left + right }.should raise_error(DbAgile::SchemaConflictError)
58
+ lambda{ DbAgile::Core::Schema::merge(left, right) }.should raise_error(DbAgile::SchemaConflictError)
59
+ end
60
+
61
+ it "should be robust enough when merging not similar things" do
62
+ lambda{ left + empty }.should_not raise_error
63
+ lambda{ right + empty }.should_not raise_error
64
+ lambda{ empty + right }.should_not raise_error
65
+ lambda{ empty + left }.should_not raise_error
66
+ lambda{ empty + empty }.should_not raise_error
67
+ lambda{ sap + empty }.should_not raise_error
68
+ lambda{ sap + left }.should_not raise_error
69
+ lambda{ sap + right }.should_not raise_error
70
+ end
71
+
72
+ end
@@ -0,0 +1,26 @@
1
+ require File.expand_path('../fixtures', __FILE__)
2
+ describe "DbAgile::Core::Schema#minus" do
3
+
4
+ let(:left) { DbAgile::Fixtures::Core::Schema::schema(:left) }
5
+ let(:left_minus_right) { DbAgile::Fixtures::Core::Schema::schema(:left_minus_right) }
6
+ let(:right) { DbAgile::Fixtures::Core::Schema::schema(:right) }
7
+ let(:right_minus_left) { DbAgile::Fixtures::Core::Schema::schema(:right_minus_left) }
8
+
9
+ it "should be a valid Schema" do
10
+ (left - right).should be_kind_of(DbAgile::Core::Schema::DatabaseSchema)
11
+ (left - left).should be_kind_of(DbAgile::Core::Schema::DatabaseSchema)
12
+ end
13
+
14
+ it "should be as expected" do
15
+ (left - right).should_not be_empty
16
+ (left - right).look_same_as?(left_minus_right).should be_true
17
+ (right - left).should_not be_empty
18
+ (right - left).look_same_as?(right_minus_left).should be_true
19
+ end
20
+
21
+ it "should be clean when comparing equal schema" do
22
+ (left - left).should be_empty
23
+ (right - right).should be_empty
24
+ end
25
+
26
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path('../fixtures', __FILE__)
2
+ describe "DbAgile::Core::Schema's sanity /" do
3
+
4
+ let(:schema){ DbAgile::Fixtures::Core::Schema::schema(:suppliers_and_parts) }
5
+
6
+ it "all objects should looking same as their duplicated" do
7
+ schema.each{|p,parent|
8
+ p.dup.look_same_as?(p).should == true
9
+ }
10
+ end
11
+
12
+ it "no object be the same object when duplicated" do
13
+ schema.each{|p,parent| p.dup.object_id.should_not == p.object_id}
14
+ end
15
+
16
+ it "no object should be equal as its duplicated" do
17
+ schema.each{|p,parent| p.dup.should_not == p}
18
+ end
19
+
20
+ it "should be sane when loaded" do
21
+ lambda{ schema.send(:_sanity_check, schema) }.should_not raise_error
22
+ end
23
+
24
+ it "should stay sane after dup" do
25
+ lambda{
26
+ duplicated = schema.dup
27
+ duplicated.send(:_sanity_check, duplicated)
28
+ schema.send(:_sanity_check, schema)
29
+ }.should_not raise_error
30
+ end
31
+
32
+ it "should not share objects when duplicated" do
33
+ ids = schema.collect{|p, parent| p.object_id}
34
+ dups = schema.dup.collect{|p, parent| p.object_id}
35
+ ids.size.should == dups.size
36
+ (ids & dups).should be_empty
37
+ end
38
+
39
+ end
@@ -0,0 +1,58 @@
1
+ require File.expand_path('../fixtures', __FILE__)
2
+ describe "DbAgile::Core::Schema#split" do
3
+
4
+ let(:schema) { DbAgile::Fixtures::Core::Schema::schema(:suppliers_and_parts) }
5
+
6
+ it "should split correctly through a logical/physical separation" do
7
+ splitted = schema.split{|obj| obj.logical? ? :logical : :physical}
8
+ logical, physical = splitted[:logical], splitted[:physical]
9
+ logical.visit{|o, parent|
10
+ unless o.composite?
11
+ o.logical?.should be_true
12
+ end
13
+ }
14
+ physical.visit{|o, parent|
15
+ unless o.composite?
16
+ o.physical?.should be_true
17
+ end
18
+ }
19
+ (logical + physical).look_same_as?(schema).should be_true
20
+ end
21
+
22
+ it "should split correctly through a logical/physical/constraint separation" do
23
+ splitted = schema.split{|obj|
24
+ if obj.logical?
25
+ if obj.constraint?
26
+ :constraint
27
+ else
28
+ :logical
29
+ end
30
+ else
31
+ :physical
32
+ end
33
+ }
34
+ logical, constraints, physical = splitted[:logical], splitted[:constraint], splitted[:physical]
35
+ logical.schema_identifier.should == :logical
36
+ constraints.schema_identifier.should == :constraint
37
+ physical.schema_identifier.should == :physical
38
+ logical.visit{|o, parent|
39
+ unless o.composite?
40
+ o.logical?.should be_true
41
+ o.constraint?.should be_false
42
+ end
43
+ }
44
+ constraints.visit{|o, parent|
45
+ unless o.composite?
46
+ o.logical?.should be_true
47
+ o.constraint?.should be_true
48
+ end
49
+ }
50
+ physical.visit{|o, parent|
51
+ unless o.composite?
52
+ o.physical?.should be_true
53
+ end
54
+ }
55
+ (logical + physical + constraints).look_same_as?(schema).should be_true
56
+ end
57
+
58
+ end