dbagile 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,221 @@
1
+ module DbAgile
2
+ module Core
3
+ #
4
+ # Encapsulates a database handler.
5
+ #
6
+ class Database
7
+
8
+ # Database name
9
+ attr_reader :name
10
+
11
+ # Database uri
12
+ attr_accessor :uri
13
+
14
+ # Array of files for the announced schema
15
+ attr_accessor :announced_files
16
+ alias :announced_schema= :announced_files=
17
+
18
+ # Array of files for the effective schema
19
+ attr_accessor :effective_files
20
+ alias :effective_schema= :effective_files=
21
+
22
+ # Resolves relative files
23
+ attr_accessor :file_resolver
24
+
25
+ # Plugs as arrays of arrays
26
+ attr_reader :plugs
27
+
28
+ # Creates a database instance
29
+ def initialize(name, uri = nil, &block)
30
+ raise ArgumentError, "Database name is mandatory" unless name.kind_of?(Symbol)
31
+ raise ArgumentError, "Database DSL is deprecated" unless block.nil?
32
+ @name = name
33
+ @uri = uri
34
+ @announced_files = []
35
+ @effective_files = []
36
+ @file_resolver = lambda{|f| ::File.expand_path(f) }
37
+ @chain = ::DbAgile::Core::Chain.new
38
+ end
39
+
40
+
41
+
42
+ ##############################################################################
43
+ ### About connector
44
+ ##############################################################################
45
+
46
+ # @see Chain#plug
47
+ def plug(*args)
48
+ (@plugs ||= []).push(*args)
49
+ @chain.plug(*args)
50
+ end
51
+
52
+ # Installs plugins
53
+ def plugins=(plugins)
54
+ plugins = plugins.collect{|p| Kernel.eval(p)}
55
+ plug(*plugins)
56
+ end
57
+
58
+
59
+ ##############################################################################
60
+ ### About connection
61
+ ##############################################################################
62
+
63
+ # Checks if the connection pings correctly.
64
+ def ping?
65
+ connect.ping?
66
+ end
67
+
68
+ # Connects and returns a Connection object
69
+ def connect(options = {})
70
+ raise ArgumentError, "Options should be a Hash" unless options.kind_of?(Hash)
71
+ raise DbAgile::Error, "Database has no uri" if uri.nil?
72
+ if uri =~ /:\/\//
73
+ adapter = DbAgile::Adapter::factor(uri, options)
74
+ elsif file_resolver
75
+ file = file_resolver.call(uri)
76
+ adapter = DbAgile::Adapter::factor("sqlite://#{file}", options)
77
+ else
78
+ raise DbAgile::Error, "A file resolver is required for using #{uri} as database uri"
79
+ end
80
+ connector = @chain.connect(adapter)
81
+ Connection.new(connector)
82
+ end
83
+
84
+ #
85
+ # Yields the block with a connection; disconnect after that.
86
+ #
87
+ # @raise ArgumentError if no block is provided
88
+ # @return block execution result
89
+ #
90
+ def with_connection(conn_options = {})
91
+ raise ArgumentError, "Missing block" unless block_given?
92
+ begin
93
+ connection = connect(conn_options)
94
+ result = yield(connection)
95
+ result
96
+ ensure
97
+ connection.disconnect if connection
98
+ end
99
+ end
100
+
101
+ ##############################################################################
102
+ ### About schema
103
+ ##############################################################################
104
+
105
+ # Does this database has announced schema files?
106
+ def has_announced_schema?
107
+ !(@announced_files.nil? or @announced_files.empty?)
108
+ end
109
+
110
+ # Does this database has effective schema files?
111
+ def has_effective_schema?
112
+ !(@effective_files.nil? or @effective_files.empty?)
113
+ end
114
+
115
+ # Loads a schema from schema files
116
+ def load_schema_from_files(files)
117
+ builder = DbAgile::Core::Schema::builder
118
+ builder.schema(files){
119
+ files.collect{|f| file_resolver.call(f)}.each{|f|
120
+ DbAgile::Core::Schema::yaml_file_load(f, builder)
121
+ }
122
+ }
123
+ builder._dump
124
+ end
125
+
126
+ # Returns the schema of highest level (announced -> effective -> physical).
127
+ def schema
128
+ announced_schema(true)
129
+ end
130
+
131
+ # Returns the announced schema. If no announce schema files are installed
132
+ # and unstage is true, returns the effective schema. Returns nil otherwise.
133
+ def announced_schema(unstage = false)
134
+ if has_announced_schema?
135
+ load_schema_from_files(announced_files)
136
+ elsif unstage
137
+ effective_schema(unstage)
138
+ else
139
+ nil
140
+ end
141
+ end
142
+
143
+ # Overrides announced schema with a given schema
144
+ def set_announced_schema(schema)
145
+ # Set announced files
146
+ self.announced_files ||= []
147
+ case announced_files.size
148
+ when 0
149
+ FileUtils.mkdir_p(file_resolver.call(name))
150
+ self.announced_files = [ "#{name}/announced.yaml" ]
151
+ when 1
152
+ else
153
+ raise "Unable to set announced schema with multiple effective files"
154
+ end
155
+ ::File.open(file_resolver.call(announced_files[0]), 'w') do |io|
156
+ io << schema.to_yaml
157
+ end
158
+ end
159
+
160
+ # Returns the effective schema. If no effective files are installed and
161
+ # unstage is true, returns the physical schema. Returns nil otherwise.
162
+ def effective_schema(unstage = false)
163
+ if has_effective_schema?
164
+ load_schema_from_files(effective_files)
165
+ elsif unstage
166
+ physical_schema
167
+ else
168
+ nil
169
+ end
170
+ end
171
+
172
+ # Overrides effective schema with a given schema
173
+ def set_effective_schema(schema)
174
+ # Set effective files
175
+ self.effective_files ||= []
176
+ case effective_files.size
177
+ when 0
178
+ FileUtils.mkdir_p(file_resolver.call(name.to_s))
179
+ self.effective_files = [ "#{name}/effective.yaml" ]
180
+ when 1
181
+ else
182
+ raise "Unable to set effective schema with multiple effective files"
183
+ end
184
+ ::File.open(file_resolver.call(effective_files[0]), 'w') do |io|
185
+ io << schema.to_yaml
186
+ end
187
+ end
188
+
189
+ # Returns the database physical schema
190
+ def physical_schema
191
+ with_connection{|c| c.physical_schema}
192
+ end
193
+
194
+ private :load_schema_from_files
195
+
196
+ ##############################################################################
197
+ ### About io
198
+ ##############################################################################
199
+
200
+ # Converts this database to a yaml string
201
+ def to_yaml(opts = {})
202
+ YAML::quick_emit(self, opts){|out|
203
+ out.map("tag:yaml.org,2002:map") do |map|
204
+ map.add('uri', self.uri)
205
+ if has_announced_schema?
206
+ map.add('announced_schema', self.announced_files || [])
207
+ end
208
+ if has_effective_schema?
209
+ map.add('effective_schema', self.effective_files || [])
210
+ end
211
+ if plugs and not(plugs.empty?)
212
+ ps = plugs.collect{|p| SByC::TypeSystem::Ruby::to_literal(p)}
213
+ map.add('plugins', ps)
214
+ end
215
+ end
216
+ }
217
+ end
218
+
219
+ end # class Database
220
+ end # module Core
221
+ end # module DbAgile
@@ -0,0 +1,95 @@
1
+ module DbAgile
2
+ module Core
3
+ module IO
4
+ class DSL
5
+ include DbAgile::Core::IO::Robustness
6
+
7
+ # The Repository instance passed at construction
8
+ attr_reader :repository
9
+
10
+ # The current Database instance
11
+ attr_reader :current_database
12
+
13
+ # Creates a DSL instance
14
+ def initialize(repository = nil, database = nil, &block)
15
+ @repository = repository
16
+ @current_database = database
17
+ self.instance_eval(&block) unless block.nil?
18
+ end
19
+
20
+ # Adds a database under a given name
21
+ def database(name, &block)
22
+ valid_database_name!(name)
23
+ created = with_database(Core::Database.new(name)){|cfg|
24
+ self.instance_eval(&block)
25
+ cfg
26
+ }
27
+ unless repository.nil?
28
+ repository << created
29
+ end
30
+ created
31
+ end
32
+
33
+ # Sets the uri on the current database
34
+ def uri(str)
35
+ dsl_has_database!
36
+ valid_database_uri!(str)
37
+ current_database.uri = str
38
+ end
39
+
40
+ # Sets the announced schema files
41
+ def announced_schema(*files)
42
+ dsl_has_database!
43
+ current_database.announced_files = valid_schema_files!(files)
44
+ end
45
+
46
+ # Sets the effective schema files
47
+ def effective_schema(*files)
48
+ dsl_has_database!
49
+ current_database.effective_files = valid_schema_files!(files)
50
+ end
51
+
52
+ # @see DbAgile::Core::Database#plug
53
+ def plug(*args)
54
+ dsl_has_database!
55
+ current_database.plug(*args)
56
+ end
57
+
58
+ # Sets the current database
59
+ def current_db(name)
60
+ dsl_has_repository!
61
+ repository.current_db_name = name
62
+ end
63
+
64
+ ###
65
+
66
+ private
67
+
68
+ # Yields the block with a database
69
+ def with_database(db)
70
+ if db.kind_of?(DbAgile::Core::Database)
71
+ @current_database = db
72
+ result = yield(db)
73
+ @current_database = nil
74
+ result
75
+ elsif db.kind_of?(Symbol) or db.nil?
76
+ dsl_has_repository!
77
+ has_database!(repository, cfg)
78
+ with_database(repository.database(cfg), &block)
79
+ end
80
+ end
81
+
82
+ # Asserts that there is a current database
83
+ def dsl_has_database!
84
+ raise DbAgile::Error, "Invalid Core::IO::DSL usage, no current database" if current_database.nil?
85
+ end
86
+
87
+ # Asserts that there is a current repository
88
+ def dsl_has_repository!
89
+ raise DbAgile::Error, "Invalid Core::IO::DSL usage, no current repository" if repository.nil?
90
+ end
91
+
92
+ end # class DSL
93
+ end # module IO
94
+ end # module Core
95
+ end # module DbAgile
@@ -0,0 +1,82 @@
1
+ module DbAgile
2
+ module Core
3
+ module IO
4
+ module Robustness
5
+
6
+ #
7
+ # Asserts that a database name is valid or raises a InvalidDatabaseName
8
+ # error. A valid database name is a Symbol that matches /[a-z][a-z0-9_]*/.
9
+ #
10
+ # @returns [Symbol] name
11
+ # @raise DbAgile::InvalidDatabaseName if assertion fails
12
+ #
13
+ def valid_database_name!(name)
14
+ raise DbAgile::InvalidDatabaseName, "Invalid database name #{name}"\
15
+ unless name.kind_of?(Symbol) and /[a-z][a-z0-9_]*/ =~ name.to_s
16
+ name
17
+ end
18
+
19
+ #
20
+ # Asserts that a database uri is valid or raises a InvalidDatabaseUri error.
21
+ #
22
+ # A valid database uri is any valid absolute URI (for now, will be restricted
23
+ # to known adapters in the future).
24
+ #
25
+ # @return [String] uri
26
+ # @raise DbAgile::InvalidDatabaseUri if assertion fails
27
+ #
28
+ def valid_database_uri!(uri)
29
+ require 'uri'
30
+ got = URI::parse(uri)
31
+ if got.scheme or (uri =~ /\.db$/)
32
+ uri
33
+ else
34
+ raise DbAgile::InvalidDatabaseUri, "Invalid database uri: #{uri}"
35
+ end
36
+ rescue URI::InvalidURIError
37
+ raise DbAgile::InvalidDatabaseUri, "Invalid database uri: #{uri}"
38
+ end
39
+
40
+ #
41
+ # Asserts that a database exists inside a Repository instance.
42
+ # When db_name is nil, asserts that a default database is set.
43
+ #
44
+ # @param [DbAgile::Core::Repository] a repository
45
+ # @return [DbAgile::Core::Database] the database instance when found.
46
+ # @raise ArgumentError if repository is not a Repository instance
47
+ # @raise DbAgile::NoSuchDatabaseError if the database cannot be found.
48
+ # @raise DbAgile::NoDefaultDatabaseError if db_name is nil and no
49
+ # current database is set on the repository.
50
+ #
51
+ def has_database!(repository, db_name = nil)
52
+ raise ArgumentError, "Repository expected, got #{repository}"\
53
+ unless repository.kind_of?(DbAgile::Core::Repository)
54
+ db = if db_name.nil?
55
+ repository.current_database
56
+ else
57
+ repository.database(db_name)
58
+ end
59
+ if db.nil?
60
+ raise DbAgile::NoSuchDatabaseError, "Unknown database #{db_name}" if db_name
61
+ raise DbAgile::NoDefaultDatabaseError, "No default database set (try 'dba use ...' first)"
62
+ else
63
+ db
64
+ end
65
+ end
66
+
67
+ #
68
+ # Coerces and asserts that schema files arguments are correct.
69
+ # Returns normalized version.
70
+ #
71
+ def valid_schema_files!(*files)
72
+ files = files.flatten
73
+ unless files.all?{|f| f.kind_of?(String)}
74
+ raise DbAgile::CorruptedRepositoryError, "Invalid schema files #{files.inspect}"
75
+ end
76
+ files
77
+ end
78
+
79
+ end # module Robustness
80
+ end # module IO
81
+ end # module Core
82
+ end # module DbAgile
@@ -0,0 +1,2 @@
1
+ require 'dbagile/core/io/robustness'
2
+ require 'dbagile/core/io/dsl'
@@ -0,0 +1,67 @@
1
+ module DbAgile
2
+ module Core
3
+ class Repository
4
+ class Builder
5
+ include DbAgile::Environment::Delegator
6
+
7
+ # Environment to use
8
+ attr_reader :environment
9
+
10
+ # Creates a builder instance
11
+ def initialize(env)
12
+ @environment = env
13
+ end
14
+
15
+ #
16
+ # Ensures that the repository exists. If not, ask the user about creating
17
+ # one in interactive mode; raises an error otherwise. Continues execution
18
+ # with the provided block if required.
19
+ #
20
+ def ensure_repository(&block)
21
+ env = self.environment
22
+ if env.repository_exists?
23
+ block.call if block
24
+ elsif env.interactive?
25
+ where = env.friendly_repository_path
26
+ msg = <<-EOF.gsub(/^\s*\| ?/, '')
27
+ | DbAgile's repository #{where} does not exist. Maybe it's the first time you
28
+ | lauch dba. Do you want to create a fresh repository now?
29
+ EOF
30
+ confirm(msg, "Have a look at 'dba help repo:create'"){
31
+ # create it!
32
+ say("Creating repository #{where}...")
33
+ DbAgile::Core::Repository::create!(env.repository_path)
34
+ say("Repository has been successfully created.")
35
+
36
+ # continue?
37
+ if block
38
+ msg = "Do you want to continue with previous command execution?"
39
+ confirm(msg, &block)
40
+ end
41
+ }
42
+ else
43
+ # to force an error
44
+ environment.repository
45
+ end
46
+ end
47
+
48
+ # Yields the block if the user confirms something and returns block
49
+ # execution. Returns nil otherwise
50
+ #
51
+ def confirm(msg, on_no_msg = nil)
52
+ say("\n")
53
+ say(msg, :magenta)
54
+ answer = environment.ask(""){|q| q.validate = /^y(es)?|n(o)?|q(uit)?/i}
55
+ case answer.strip
56
+ when /^n/i, /^q/i
57
+ say("\n")
58
+ say(on_no_msg, :magenta) unless on_no_msg.nil?
59
+ when /^y/i
60
+ yield
61
+ end
62
+ end
63
+
64
+ end # class Builder
65
+ end # class Repository
66
+ end # module Core
67
+ end # module DbAgile
@@ -0,0 +1,82 @@
1
+ module DbAgile
2
+ module Core
3
+ class Repository
4
+
5
+ module YAMLInstanceMethods
6
+
7
+ # Dumps the repository to YAML
8
+ def to_yaml(opts = {})
9
+ YAML::quick_emit(self, opts){|out|
10
+ dbmap = DbAgile::Tools::OrderedHash.new
11
+ databases.each{|db| dbmap[db.name.to_s] = db}
12
+ out.map("tag:yaml.org,2002:map") do |map|
13
+ map.add('version', self.version)
14
+ map.add('databases', dbmap)
15
+ map.add('current', self.current_db_name.to_s)
16
+ end
17
+ }
18
+ end
19
+
20
+ end # module YAMLInstanceMethods
21
+
22
+ module YAMLClassMethods
23
+
24
+ #
25
+ # Loads a repository from a YAML file and returns a Core::Repository instance.
26
+ #
27
+ # This method is not robust at all and re-raises any error that occurs. It
28
+ # should be protected upstream.
29
+ #
30
+ # @param [String] file path to a repository index (exist, readable)
31
+ # @param [String] root_path path of the repository itself (exist, readable)
32
+ # @raise DbAgile::CorruptedRepositoryError if anything goes wrong.
33
+ #
34
+ def from_yaml_file(file, root_path)
35
+ from_yaml(File.read(file), root_path)
36
+ end
37
+
38
+ #
39
+ # Loads a repository from a YAML file and returns a Core::Repository instance.
40
+ #
41
+ # This method is not robust at all and re-raises any error that occurs. It
42
+ # should be protected upstream.
43
+ #
44
+ # @param [String] str a YAML source
45
+ # @param [String] root_path root path to set on the repository
46
+ #
47
+ def from_yaml(str, root_path)
48
+ # Load the hash
49
+ hash = YAML::load(str)
50
+
51
+ # Load the repository version
52
+ version = hash['version'].to_s.strip
53
+ if version.nil? or version.empty?
54
+ raise "missing version number"
55
+ end
56
+
57
+ # create the repository instance
58
+ repo = Repository.new(root_path, version)
59
+
60
+ # load databases
61
+ hash['databases'].each_pair{|dbname, dbconfig|
62
+ db = Core::Database.new(dbname.to_s.to_sym)
63
+ dbconfig.each_pair{|key, value|
64
+ db.send(:"#{key}=", value)
65
+ }
66
+ repo << db
67
+ }
68
+
69
+ # Set current database
70
+ current = hash['current'].to_s.strip
71
+ unless current.empty?
72
+ repo.current_db_name = current.to_sym
73
+ end
74
+
75
+ repo
76
+ end
77
+
78
+ end # module YAMLClassMethods
79
+
80
+ end # class Repository
81
+ end # module Core
82
+ end # module DbAgile