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,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