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,35 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ module Migrate
5
+ class AbstractScript
6
+ include Enumerable
7
+
8
+ # Operations in this abstract script
9
+ attr_reader :operations
10
+
11
+ # Creates an abstract script instance
12
+ def initialize
13
+ @operations = []
14
+ end
15
+
16
+ # Yields the block with each operation in turn
17
+ def each(&block)
18
+ operations.each(&block)
19
+ end
20
+
21
+ # Pushes operations in this abstract script
22
+ def <<(*ops)
23
+ self.operations.push(*ops)
24
+ end
25
+
26
+ end # class AbstractScript
27
+ end # module Migrate
28
+ end # module Schema
29
+ end # module Core
30
+ end # module DbAgile
31
+ require 'dbagile/core/schema/migrate/operation'
32
+ require 'dbagile/core/schema/migrate/create_table'
33
+ require 'dbagile/core/schema/migrate/drop_table'
34
+ require 'dbagile/core/schema/migrate/expand_table'
35
+ require 'dbagile/core/schema/migrate/collapse_table'
@@ -0,0 +1,15 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ module Migrate
5
+ class CollapseTable < Migrate::Operation
6
+
7
+ def to_sql92
8
+ "ALTER TABLE DROP #{ops_to_sql92(operations)}"
9
+ end
10
+
11
+ end # class CollapseTable
12
+ end # module Migrate
13
+ end # module Schema
14
+ end # module Core
15
+ end # module DbAgile
@@ -0,0 +1,15 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ module Migrate
5
+ class CreateTable < Migrate::Operation
6
+
7
+ def to_sql92
8
+ "CREATE TABLE (#{ops_to_sql92(operations)})"
9
+ end
10
+
11
+ end # class CreateTable
12
+ end # module Migrate
13
+ end # module Schema
14
+ end # module Core
15
+ end # module DbAgile
@@ -0,0 +1,15 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ module Migrate
5
+ class DropTable < Migrate::Operation
6
+
7
+ def to_sql92
8
+ "DROP TABLE #{table_name}"
9
+ end
10
+
11
+ end # class DropTable
12
+ end # module Migrate
13
+ end # module Schema
14
+ end # module Core
15
+ end # module DbAgile
@@ -0,0 +1,15 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ module Migrate
5
+ class ExpandTable < Migrate::Operation
6
+
7
+ def to_sql92
8
+ "ALTER TABLE ADD #{ops_to_sql92(operations)}"
9
+ end
10
+
11
+ end # class ExpandTable
12
+ end # module Migrate
13
+ end # module Schema
14
+ end # module Core
15
+ end # module DbAgile
@@ -0,0 +1,141 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ module Migrate
5
+ class Operation
6
+
7
+ # The sub operations
8
+ attr_reader :operations
9
+
10
+ # Targetted relation variable
11
+ attr_reader :relvar
12
+
13
+ # Returns table name
14
+ def table_name
15
+ relvar.name
16
+ end
17
+
18
+ def initialize(relvar)
19
+ unless relvar.kind_of?(DbAgile::Core::Schema::Logical::Relvar)
20
+ raise ArgumentError, "Relvar expected for relvar, got #{relvar.class}"
21
+ end
22
+ @relvar = relvar
23
+ @operations = []
24
+ end
25
+
26
+ # Returns kind of this operation
27
+ def kind
28
+ unqualified = DbAgile::RubyTools::class_unqualified_name(self.class).to_s
29
+ unqualified.gsub(/[A-Z]/){|x| "_#{x.downcase}"}[1..-1].to_sym
30
+ end
31
+
32
+ ##########################################################################
33
+ ### Execution feedback
34
+ ##########################################################################
35
+
36
+ # Mark an object as upgraded
37
+ def staged!(obj = relvar)
38
+ obj.status = case obj.status
39
+ when Schema::TO_CREATE, Schema::CREATED
40
+ Schema::CREATED
41
+ when Schema::TO_ALTER, Schema::ALTERED
42
+ Schema::ALTERED
43
+ when Schema::TO_DROP, Schema::DROPPED
44
+ Schema::DROPPED
45
+ when Schema::NO_CHANGE
46
+ Schema::NO_CHANGE
47
+ else
48
+ status_str = obj.status.to_s.upcase
49
+ raise DbAgile::AssumptionFailedError, "Unexpected staged! source status #{status_str} on #{obj}"
50
+ end
51
+ end
52
+
53
+ # Mark an object as not being staged
54
+ def not_staged!(obj = relvar)
55
+ obj.status = case obj.status
56
+ when Schema::TO_CREATE
57
+ Schema::DEFERED
58
+ when Schema::TO_ALTER
59
+ Schema::DEFERED
60
+ when Schema::TO_DROP
61
+ Schema::DEFERED
62
+ when Schema::DEFERED
63
+ Schema::DEFERED
64
+ when Schema::NO_CHANGE
65
+ Schema::NO_CHANGE
66
+ else
67
+ status_str = obj.status.to_s.upcase
68
+ raise DbAgile::AssumptionFailedError, "Unexpected staged! source status #{status_str} on #{obj}"
69
+ end
70
+ end
71
+
72
+ ##########################################################################
73
+ ### About sub operations
74
+ ##########################################################################
75
+
76
+ # Asserts that this operation supports sub operations
77
+ def supports_sub_operation?(name = nil)
78
+ !self.kind_of?(Migrate::DropTable)
79
+ end
80
+
81
+ # Asserts that this operation supports sub operations
82
+ def supports_sub_operation!(name)
83
+ unless supports_sub_operation?(name)
84
+ raise DbAgile::AssumptionFailedError, "#{self.class} does not support sub operation #{name}"
85
+ end
86
+ end
87
+
88
+ # Yields the block with each (subop_kind, operand) pair
89
+ def each_sub_operation(&block)
90
+ supports_sub_operation!(nil)
91
+ operations.each{|op| block.call(op[0], op[1])}
92
+ end
93
+
94
+ # Create/alter an attribute
95
+ def attribute(attribute)
96
+ supports_sub_operation!(:attribute)
97
+ operations << [:attribute, attribute]
98
+ end
99
+
100
+ # Create/alter a candidate key
101
+ def candidate_key(ckey)
102
+ supports_sub_operation!(:candidate_key)
103
+ operations << [:candidate_key, ckey]
104
+ end
105
+
106
+ # Create/alter a foreign key
107
+ def foreign_key(fkey)
108
+ supports_sub_operation!(:foreign_key)
109
+ operations << [:foreign_key, fkey]
110
+ end
111
+
112
+ # Create/alter an index
113
+ def index(index)
114
+ supports_sub_operation!(:index)
115
+ operations << [:index, index]
116
+ end
117
+
118
+ # Converts operations to simili SQL
119
+ def ops_to_sql92(ops)
120
+ ops.collect{|op|
121
+ kind, operand = op
122
+ case kind
123
+ when :attribute
124
+ "COLUMN #{operand.name} #{operand.domain}"
125
+ when :candidate_key
126
+ "CANDIDATE KEY #{operand.name})"
127
+ when :foreign_key
128
+ "FOREIGN KEY #{operand.name}"
129
+ when :index
130
+ "INDEX #{operand.name}"
131
+ else
132
+ raise DbAgile::AssumptionFailedError, "Unexpected operation kin #{kind}"
133
+ end
134
+ }.join(';')
135
+ end
136
+
137
+ end # class Operation
138
+ end # module Migrate
139
+ end # module Schema
140
+ end # module Core
141
+ end # module DbAgile
@@ -0,0 +1,282 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ module Migrate
5
+ class Stager
6
+
7
+ # List of status
8
+ Status = ::DbAgile::Core::Schema
9
+
10
+ # Default stager options
11
+ DEFAULT_OPTIONS = {:expand => true, :collapse => true}
12
+
13
+ # The abstract script we build
14
+ attr_reader :script
15
+
16
+ # Helper for each relation variable
17
+ attr_reader :helpers
18
+
19
+ # Status of each object
20
+ attr_reader :status
21
+
22
+ ############################################################################
23
+ ### Schema info helpers need
24
+ ############################################################################
25
+
26
+ # Checks if table already exists
27
+ def relvar_exists?(rv)
28
+ (rv.status == Status::NO_CHANGE) or
29
+ (rv.status == Status::TO_ALTER) or
30
+ (status[rv] == Status::CREATED)
31
+ end
32
+
33
+ # Asserts that a table exists
34
+ def relvar_exists!(rv)
35
+ status[rv] = Status::CREATED
36
+ end
37
+
38
+ ############################################################################
39
+ ### Public interface
40
+ ############################################################################
41
+
42
+ #
43
+ # Runs the staging algorithm on an annotated schema (result of a merge)
44
+ # and options.
45
+ #
46
+ def run(schema, options)
47
+ @helpers = {}
48
+ @status = {}
49
+ @script = Migrate::AbstractScript.new
50
+
51
+ # Take all objects and mark them as :to_ensure
52
+ all_objects = schema.collect{|o, parent| o}
53
+ all_objects.each{|o| @status[o] = o.status}
54
+
55
+ # Collapse first
56
+ if options[:collapse]
57
+ collapse_objects(all_objects.select{|obj| @status[obj] == Status::TO_DROP})
58
+ end
59
+
60
+ # Expand then
61
+ if options[:expand]
62
+ expand_objects(all_objects.select{|obj| @status[obj] == Status::TO_CREATE})
63
+ end
64
+
65
+ # clean
66
+ raise AssumptionFailedError, "Helpers should be empty" unless @helpers.empty?
67
+ to_return = @script
68
+ @script = nil
69
+ @helpers = nil
70
+ @status = nil
71
+ to_return
72
+ end
73
+
74
+ ############################################################################
75
+ ### Collapse algorithms (for drop)
76
+ ############################################################################
77
+
78
+ # Yields the block with an helper to collapse a relation
79
+ # variable, creating it if required.
80
+ def with_collapse_helper(rv)
81
+ if h = helpers[rv]
82
+ yield(h)
83
+ else
84
+ h = helpers[rv] = Migrate::CollapseTable.new(rv)
85
+ yield(h)
86
+ script << h
87
+ helpers.delete(rv)
88
+ end
89
+ end
90
+
91
+ # Ensures inexistence of a list of schema objects
92
+ def collapse_objects(schema_objects)
93
+ schema_objects.each do |object|
94
+ case s = status[object]
95
+ when Status::TO_DROP, Status::TO_ALTER
96
+ collapse_object(object)
97
+ when Status::NO_CHANGE, Status::DROPPED
98
+ # nothing to do
99
+ else
100
+ msg = "Unexpected status #{s} for #{object} for schema collapsing"
101
+ raise AssumptionFailedError, msg
102
+ end
103
+ end
104
+ end
105
+
106
+ # Ensures inexistence of a single schema object
107
+ def collapse_object(object)
108
+ parent = object.parent
109
+
110
+ case status[parent]
111
+ when Status::DROPPED
112
+ # nothing do do, parent has certainly removed me
113
+ status[object] = Status::DROPPED
114
+ when Status::TO_DROP
115
+ #
116
+ # Delegate to parent if it needs to be collapsed itself
117
+ #
118
+ # Making this helps issuing a single DROP TABLE and avoiding
119
+ # many ALTER TABLE that will eventually fail (the last column)
120
+ #
121
+ collapse_object(parent)
122
+ status[object] = Status::DROPPED
123
+ else
124
+ status[object] = Status::PENDING
125
+
126
+ object.outside_dependents.each{|dep|
127
+ collapse_objects([ dep ])
128
+ }
129
+
130
+ collapse_call = :"collapse_#{object.builder_handler}"
131
+ self.send(collapse_call, object)
132
+
133
+ status[object] = Status::DROPPED
134
+ end
135
+ end
136
+
137
+ # Collapses a relation variable
138
+ def collapse_relvar(relvar)
139
+ script << Migrate::DropTable.new(relvar)
140
+ end
141
+
142
+ # Collapses a candidate key
143
+ def collapse_candidate_key(ckey)
144
+ with_collapse_helper(ckey.relation_variable){|h| h.candidate_key(ckey)}
145
+ end
146
+
147
+ # Collapses a foreign key
148
+ def collapse_foreign_key(fkey)
149
+ with_collapse_helper(fkey.relation_variable){|h| h.foreign_key(fkey)}
150
+ end
151
+
152
+ # Collapses an attribute
153
+ def collapse_attribute(attribute)
154
+ with_collapse_helper(attribute.relation_variable){|h| h.attribute(attribute)}
155
+ end
156
+
157
+ # Collapses an index
158
+ def collapse_index(index)
159
+ with_collapse_helper(index.indexed_relvar){|h| h.index(index)}
160
+ end
161
+
162
+ ############################################################################
163
+ ### Expand algorithms (for alter/create)
164
+ ############################################################################
165
+
166
+ # Yields the block with an helper to expand a relation
167
+ # variable, creating it if required
168
+ def with_expand_helper(rv)
169
+ if h = helpers[rv]
170
+ yield(h)
171
+ else
172
+ # create the operation
173
+ exists = relvar_exists?(rv)
174
+ h = exists ? Migrate::ExpandTable.new(rv) : Migrate::CreateTable.new(rv)
175
+
176
+ # execute sub operations and save
177
+ yield(helpers[rv] = h)
178
+ script << h
179
+
180
+ # assert that the table now exists
181
+ unless exists
182
+ relvar_exists!(rv)
183
+ end
184
+
185
+ # remove helper now
186
+ helpers.delete(rv)
187
+ end
188
+ end
189
+
190
+ # Ensures existence of a list of schema objects.
191
+ def expand_objects(schema_objects)
192
+ schema_objects.each do |object|
193
+ case s = status[object]
194
+ when Status::TO_CREATE, Status::TO_ALTER
195
+ expand_object(object)
196
+ when Status::NO_CHANGE, Status::CREATED
197
+ # nothing do to
198
+ else
199
+ msg = "Unexpected status #{s} for #{object} for schema expansion"
200
+ raise AssumptionFailedError, msg
201
+ end
202
+ end
203
+ end
204
+
205
+ # Ensures existence of a single schema object
206
+ def expand_object(object)
207
+ parent = object.parent
208
+
209
+ if status[parent] == Status::TO_CREATE
210
+ #
211
+ # Delegate to parent if it needs to be ensured itself
212
+ #
213
+ # Making this helps issuing a single CREATE TABLE instead of
214
+ # many ALTER TABLE statements, which are not always supported
215
+ # by adapters.
216
+ #
217
+ expand_object(parent)
218
+ else
219
+ # Mark the object as being currently created
220
+ status[object] = Status::PENDING
221
+
222
+ # ensure dependencies
223
+ expand_objects(object.outside_dependencies)
224
+
225
+ # ensure itself and recurse on children
226
+ expand_call = :"expand_#{object.builder_handler}"
227
+ if object.composite?
228
+ # ensure composite objects
229
+ if self.respond_to?(expand_call)
230
+ self.send(expand_call, object){ expand_objects(object.parts) }
231
+ else
232
+ expand_objects(object.parts)
233
+ end
234
+ else
235
+ # ensure part objects
236
+ self.send(expand_call, object)
237
+ end
238
+
239
+ # mark object as ensured!
240
+ status[object] = Status::CREATED
241
+ end
242
+ end
243
+
244
+ ### Composites
245
+
246
+ def expand_relvar_xxx(xxx)
247
+ with_expand_helper(rv = xxx.relation_variable){|helper| yield}
248
+ end
249
+ alias :expand_relvar :expand_relvar_xxx
250
+ alias :expand_heading :expand_relvar_xxx
251
+
252
+ ### Parts
253
+
254
+ def expand_attribute(attribute)
255
+ with_expand_helper(rv = attribute.relation_variable){|helper|
256
+ helper.attribute(attribute)
257
+ }
258
+ end
259
+
260
+ def expand_candidate_key(ckey)
261
+ with_expand_helper(rv = ckey.relation_variable){|helper|
262
+ helper.candidate_key(ckey)
263
+ }
264
+ end
265
+
266
+ def expand_foreign_key(fkey)
267
+ with_expand_helper(rv = fkey.relation_variable){|helper|
268
+ helper.foreign_key(fkey)
269
+ }
270
+ end
271
+
272
+ def expand_index(index)
273
+ with_expand_helper(rv = index.indexed_relvar){|helper|
274
+ helper.index(index)
275
+ }
276
+ end
277
+
278
+ end # class Stager
279
+ end # module Migrate
280
+ end # module Schema
281
+ end # module Core
282
+ end # module DbAgile
@@ -0,0 +1,2 @@
1
+ require 'dbagile/core/schema/migrate/abstract_script'
2
+ require 'dbagile/core/schema/migrate/stager'
@@ -0,0 +1,114 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ class Part < SchemaObject
5
+
6
+ # Object name
7
+ attr_reader :name
8
+
9
+ # Object definition
10
+ attr_reader :definition
11
+
12
+ # Creates a part instance
13
+ def initialize(name, definition)
14
+ @name = name
15
+ @definition = definition
16
+ end
17
+
18
+ # Makes a sanity check on the part
19
+ def _sanity_check(schema)
20
+ raise SchemaInternalError, "No name provided on #{self}" if name.nil?
21
+ raise SchemaInternalError, "No definition provided on #{self}" if definition.nil?
22
+ end
23
+
24
+ # Checks this composite's semantics and collect errors
25
+ def _semantics_check(clazz, buffer)
26
+ end
27
+
28
+ ############################################################################
29
+ ### Schema typing
30
+ ############################################################################
31
+
32
+ # Returns true if this object is a logical object, false otherwise
33
+ def logical?
34
+ relvar? or attribute? or constraint?
35
+ end
36
+
37
+ # Returns true if this object is a relation variable, false otherwise
38
+ def relvar?
39
+ self.kind_of?(Schema::Logical::Relvar)
40
+ end
41
+
42
+ # Returns true if this object is an attribute, false otherwise
43
+ def attribute?
44
+ self.kind_of?(Schema::Logical::Attribute)
45
+ end
46
+
47
+ # Returns true if this object is a constraint, false otherwise
48
+ def constraint?
49
+ self.kind_of?(Schema::Logical::Constraint)
50
+ end
51
+
52
+ # Returns true if this object is a candidate key, false otherwise
53
+ def candidate_key?
54
+ self.kind_of?(Schema::Logical::Constraint::CandidateKey)
55
+ end
56
+
57
+ # Returns true if this object is a primary key, false otherwise
58
+ def primary_key?
59
+ self.candidate_key? and self.primary?
60
+ end
61
+
62
+ # Returns true if this object is a foreign key, false otherwise
63
+ def foreign_key?
64
+ self.kind_of?(Schema::Logical::Constraint::ForeignKey)
65
+ end
66
+
67
+ # Returns true if this object is a physical object, false otherwise
68
+ def physical?
69
+ index?
70
+ end
71
+
72
+ # Returns true if this object is an index, false otherwise
73
+ def index?
74
+ self.kind_of?(Schema::Physical::Index)
75
+ end
76
+
77
+ ############################################################################
78
+ ### Schema::SchemaObject
79
+ ############################################################################
80
+
81
+ # Returns an array with part dependencies
82
+ def dependencies(include_parent = false)
83
+ include_parent ? [ parent ] : []
84
+ end
85
+
86
+ # @see DbAgile::Core::Schema
87
+ def visit(&block)
88
+ block.call(self, parent)
89
+ end
90
+
91
+ ############################################################################
92
+ ### Equality and hash code
93
+ ############################################################################
94
+
95
+ # Compares with another part
96
+ def look_same_as?(other)
97
+ return nil unless other.kind_of?(self.class)
98
+ (name == other.name) and (definition == other.definition)
99
+ end
100
+
101
+ # Duplicates this part
102
+ def dup
103
+ self.class.new(name, definition.dup)
104
+ end
105
+
106
+ # Returns a string representation
107
+ def to_s
108
+ "#{DbAgile::RubyTools::unqualified_class_name(self.class)}: #{name} #{definition.inspect}"
109
+ end
110
+
111
+ end # class Part
112
+ end # module Schema
113
+ end # module Core
114
+ end # module DbAgile