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,27 @@
1
+ module DbAgile
2
+ module Restful
3
+ class Middleware
4
+ module Get
5
+
6
+ # Implements GET access of the restful interface
7
+ def get(env)
8
+ request = Rack::Request.new(env)
9
+ decode(env) do |connection, table, format|
10
+ # Compute the projection on query string
11
+ heading = connection.heading(table)
12
+ projection = params_to_tuple(request.GET, heading)
13
+
14
+ # Retrieve dataset
15
+ columns = connection.column_names(table)
16
+ dataset = connection.dataset(table, projection)
17
+
18
+ # Make output now
19
+ format ||= :json
20
+ [format, to_xxx_enumerable(format, dataset, columns)]
21
+ end
22
+ end
23
+
24
+ end # module Get
25
+ end # class Middleware
26
+ end # module Restful
27
+ end # module Facts
@@ -0,0 +1,82 @@
1
+ module DbAgile
2
+ module Restful
3
+ class Middleware
4
+ #
5
+ # Rack middleware that provide access to a database using a database
6
+ # instance (DbAgile::Core::Database)
7
+ #
8
+ class OneDatabase
9
+ include Middleware::Utils
10
+ include Middleware::Get
11
+ include Middleware::Post
12
+ include Middleware::Delete
13
+
14
+ # Database instance
15
+ attr_reader :database
16
+
17
+ # Creates a middleware instance
18
+ def initialize(database)
19
+ raise ArgumentError unless database.kind_of?(DbAgile::Core::Database)
20
+ @database = database
21
+ end
22
+
23
+ # Decodes a path and yield the block with a connection and the
24
+ # requested format
25
+ def decode(env)
26
+ case env['PATH_INFO'].strip[1..-1]
27
+ when ''
28
+ _copyright_(env)
29
+ when /(\w+)(\.(\w+))?$/
30
+ table = $1.to_sym
31
+
32
+ # Handle format
33
+ format = nil
34
+ if $2
35
+ format = known_extension?($2)
36
+ return _404_(env) unless format
37
+ end
38
+
39
+ format, body = database.with_connection do |connection|
40
+ yield(connection, table, format)
41
+ end
42
+
43
+ content_type = DbAgile::IO::FORMAT_TO_CONTENT_TYPE[format]
44
+ _200_(env, content_type, body)
45
+ else
46
+ _404_(env)
47
+ end
48
+ rescue DbAgile::InvalidDatabaseName,
49
+ DbAgile::NoSuchDatabaseError,
50
+ DbAgile::NoSuchTableError => ex
51
+ _404_(env, ex)
52
+ rescue DbAgile::Error, Sequel::Error => ex
53
+ if ex.message =~ /exist/
54
+ _404_(env)
55
+ else
56
+ raise
57
+ end
58
+ end
59
+
60
+ # Rack handler
61
+ def call(env)
62
+ method = env['REQUEST_METHOD'].downcase.to_sym
63
+ if self.respond_to?(method)
64
+ result = self.send(method, env)
65
+ else
66
+ puts "Unsupported restful method #{env['REQUEST_METHOD']}"
67
+ [
68
+ 500,
69
+ {'Content-Type' => 'text/plain'},
70
+ ["Unsupported restful method #{env['REQUEST_METHOD']}"]
71
+ ]
72
+ end
73
+ rescue Exception => ex
74
+ puts ex.message
75
+ puts ex.backtrace.join("\n")
76
+ [500, {'Content-Type' => 'text/plain'}, [ex.message]]
77
+ end
78
+
79
+ end # class OneDatabase
80
+ end # class Middleware
81
+ end # module Restful
82
+ end # module DbAgile
@@ -0,0 +1,23 @@
1
+ module DbAgile
2
+ module Restful
3
+ class Middleware
4
+ module Post
5
+
6
+ # Implements POST access of the restful interface
7
+ def post(env)
8
+ request = Rack::Request.new(env)
9
+ decode(env) do |connection, table, format|
10
+ format = :json if format.nil?
11
+ heading = connection.heading(table)
12
+ tuple = params_to_tuple(request.POST, heading)
13
+ inserted = connection.transaction do |t|
14
+ t.insert(table, tuple)
15
+ end
16
+ [format, to_xxx_enumerable(format, [ inserted ], tuple.keys)]
17
+ end
18
+ end
19
+
20
+ end # module Get
21
+ end # class Middleware
22
+ end # module Restful
23
+ end # module Facts
@@ -0,0 +1,65 @@
1
+ module DbAgile
2
+ module Restful
3
+ class Middleware
4
+ module Utils
5
+ include ::DbAgile::IO
6
+
7
+ # Converts get parameters to a tuple for projection
8
+ def params_to_tuple(params, heading)
9
+ copy = {}
10
+ params.each_pair{|k, v|
11
+ k = k.to_sym
12
+ next unless heading.key?(k)
13
+ copy[k] = SByC::TypeSystem::Ruby::coerce(v, heading[k])
14
+ }
15
+ copy
16
+ end
17
+
18
+ # Returns a copyright response
19
+ def _copyright_(env)
20
+ [
21
+ 200,
22
+ {'Content-Type' => 'text/plain'},
23
+ [ "dba #{DbAgile::VERSION} (c) 2010, Bernard Lambeau" ]
24
+ ]
25
+ end
26
+
27
+ # Returns a 404 response
28
+ def _404_(env, ex = nil)
29
+ [
30
+ 404,
31
+ {'Content-Type' => 'text/plain'},
32
+ [ "Not found #{env['PATH_INFO']}: " ] + (ex.nil? ? [] : [ ex.message ])
33
+ ]
34
+ end
35
+
36
+ # Returns a 200 response for a given format
37
+ def _200_(env, type, result)
38
+ [
39
+ 200,
40
+ {'Content-Type' => type},
41
+ result
42
+ ]
43
+ end
44
+
45
+ # Returns a 500 response
46
+ def _500_(env, message)
47
+ [
48
+ 500,
49
+ {'Content-Type' => 'text/plain'},
50
+ [ message ]
51
+ ]
52
+ end
53
+
54
+ # Converts a dataset-like object to an enumerable rack result
55
+ def to_xxx_enumerable(format, dataset, columns)
56
+ buffer = StringIO.new
57
+ method = "to_#{format}".to_sym
58
+ DbAgile::IO.send(method, dataset, columns, buffer)
59
+ [ buffer.string ]
60
+ end
61
+
62
+ end # module Utils
63
+ end # class Middleware
64
+ end # module Restful
65
+ end # module DbAgile
@@ -0,0 +1,54 @@
1
+ require 'stringio'
2
+ require 'json'
3
+ require 'dbagile'
4
+ require 'dbagile/restful/middleware/utils'
5
+ require 'dbagile/restful/middleware/get'
6
+ require 'dbagile/restful/middleware/post'
7
+ require 'dbagile/restful/middleware/delete'
8
+ require 'dbagile/restful/middleware/one_database'
9
+ module DbAgile
10
+ module Restful
11
+ class Middleware
12
+ include Middleware::Utils
13
+
14
+ # Environment
15
+ attr_reader :environment
16
+
17
+ # OneDatabase delegates
18
+ attr_reader :delegates
19
+
20
+ # Creates a Restful handler
21
+ def initialize(environment = DbAgile::default_environment, &block)
22
+ raise "Environment may not be nil" if environment.nil?
23
+ block.call(environment) if block
24
+ @environment = environment
25
+ _install
26
+ end
27
+
28
+ # Installs the delegates
29
+ def _install
30
+ @delegates = {}
31
+ environment.repository.each{|db|
32
+ @delegates[db.name] = Middleware::OneDatabase.new(db)
33
+ }
34
+ end
35
+
36
+ # Delegated according to the path
37
+ def call(env)
38
+ env['PATH_INFO'] =~ /^\/(\w+)(.*)$/
39
+ if $1
40
+ if delegates.key?($1.to_sym)
41
+ env['PATH_INFO'] = $2
42
+ delegates[$1.to_sym].call(env)
43
+ else
44
+ _404_(env)
45
+ end
46
+ else
47
+ _copyright_(env)
48
+ end
49
+ end
50
+
51
+ private :_install
52
+ end # class Middleware
53
+ end # module Restful
54
+ end # module DbAgile
@@ -0,0 +1,65 @@
1
+ if RUBY_VERSION == "1.8.6"
2
+ gem 'rack', "= 1.1.0"
3
+ require 'rack'
4
+ else
5
+ gem 'rack', ">= 1.1.0"
6
+ require 'rack'
7
+ end
8
+ require 'dbagile/restful/middleware'
9
+ require 'uri'
10
+ require "net/http"
11
+ require 'webrick'
12
+ module DbAgile
13
+ module Restful
14
+ class Server
15
+
16
+ # Default Rack options for restful server and client
17
+ DEFAULT_RACK_OPTIONS = {:Port => 8711, :Host => "127.0.0.1", :AccessLog => []}
18
+
19
+ # Server options
20
+ attr_reader :options
21
+
22
+ # Creates a server instance
23
+ def initialize(environment, options = DEFAULT_RACK_OPTIONS)
24
+ raise "Environment may not be nil" if environment.nil?
25
+ @environment = environment
26
+ @options = options
27
+ end
28
+
29
+ # Returns the server uri given by options
30
+ def uri
31
+ URI::parse("http://#{options[:Host]}:#{options[:Port]}/")
32
+ end
33
+
34
+ # Starts the server inside a thread
35
+ def start
36
+ myself, env = self, @environment
37
+ rack_server = ::Rack::Handler::default
38
+ rack_app = ::Rack::Builder.new{ run DbAgile::Restful::Middleware.new(env) }
39
+ thread = Thread.new(rack_server, rack_app, options.dup){|s,a,o|
40
+ s.run(a, o){|server| @server = server}
41
+ }
42
+
43
+ # Wait until the server is loaded
44
+ try, ok, res = 0, false, nil
45
+ begin
46
+ res = Net::HTTP.get(uri)
47
+ ok = true
48
+ rescue Errno::ECONNREFUSED => ex
49
+ sleep 0.3
50
+ end until (ok or (try += 1)>10)
51
+ raise "Unable to connect to server" if try >= 10
52
+
53
+ @environment.say("Have a look at #{uri}")
54
+ thread
55
+ end
56
+
57
+ # Stops the server
58
+ def stop
59
+ @server.shutdown if @server.respond_to?(:shutdown)
60
+ @server = nil
61
+ end
62
+
63
+ end # class Server
64
+ end # module Restful
65
+ end # module DbAgile
@@ -0,0 +1,9 @@
1
+ module DbAgile
2
+ #
3
+ # Marker module for the Restful interface.
4
+ #
5
+ # @see http://blambeau.github.com/dbagile/restful
6
+ #
7
+ module Restful
8
+ end # module Restful
9
+ end # module DbAgile
@@ -0,0 +1,36 @@
1
+ module DbAgile
2
+ module Robustness
3
+ module Dependencies
4
+
5
+ # Raises when a dependency is missing
6
+ class ::DbAgile::DependencyError < ::DbAgile::Error; end
7
+
8
+ # Asserts that a standard library
9
+ def has_stdlib!(util_name, msg = nil)
10
+ require util_name
11
+ rescue StandardError => ex
12
+ if msg.nil?
13
+ msg = "DbAgile requires #{util_name} but failed to load it"
14
+ end
15
+ msg = "#{msg}\n#{ex.message}"
16
+ raise DbAgile::DependencyError, msg, ex.backtrace
17
+ end
18
+
19
+ # Asserts that a gem exists and is loaded
20
+ def has_gem!(gem_name, gem_version = nil, msg = nil)
21
+ require 'rubygems'
22
+ gem gem_name, gem_version
23
+ require gem_name
24
+ rescue StandardError => ex
25
+ if msg.nil?
26
+ msg = gem_version.nil? ? gem_name : "#{gem_name} (#{gem_version})"
27
+ msg = "DbAgile requires #{msg} but failed to load it"
28
+ end
29
+ msg = "#{msg}\n#{ex.message}"
30
+ raise DbAgile::DependencyError, msg, ex.backtrace
31
+ end
32
+
33
+ end # module Dependencies
34
+ extend(Dependencies)
35
+ end # module Robustness
36
+ end # module DbAgile
@@ -0,0 +1,53 @@
1
+ module DbAgile
2
+ module Robustness
3
+ module FileSystem
4
+
5
+ # Asserts that a directory exists, is readable and writable
6
+ def valid_rw_directory!(dir,
7
+ msg = "Unable to access #{dir} in read/write",
8
+ error_class = IOError)
9
+ unless File.directory?(dir) &&
10
+ File.readable?(dir) &&
11
+ File.writable?(dir)
12
+ raise error_class, msg, caller
13
+ end
14
+ dir
15
+ end
16
+
17
+ # Asserts that a file exists, is readable and writable
18
+ def valid_rw_file!(file,
19
+ msg = "Unable to access #{file} in read/write",
20
+ error_class = IOError)
21
+ unless File.file?(file) &&
22
+ File.readable?(file) &&
23
+ File.writable?(file)
24
+ raise error_class, msg, caller
25
+ end
26
+ file
27
+ end
28
+
29
+ # Asserts that a file exists and is readable.
30
+ def valid_r_file!(file,
31
+ msg = "Unable to access #{file} in read",
32
+ error_class = IOError)
33
+ unless File.file?(file) &&
34
+ File.readable?(file)
35
+ raise error_class, msg, caller
36
+ end
37
+ file
38
+ end
39
+
40
+ # Asserts that a directory does not exists
41
+ def unexisting_directory!(dir,
42
+ msg = "Directory #{dir} already exists, use --force",
43
+ error_class = IOError)
44
+ if File.exists?(dir)
45
+ raise error_class, msg, caller
46
+ end
47
+ dir
48
+ end
49
+
50
+ end # module FileSystem
51
+ extend(FileSystem)
52
+ end # module Robustness
53
+ end # module DbAgile
@@ -0,0 +1,14 @@
1
+ module DbAgile
2
+
3
+ # Main class of all DbAgile errors
4
+ class Error < StandardError; end
5
+
6
+ # Raised when something goes really wrong (a bug, typically)
7
+ class InternalError < DbAgile::Error; end
8
+
9
+ # Some internal assumption failed
10
+ class AssumptionFailedError < DbAgile::InternalError; end
11
+
12
+ end
13
+ require 'dbagile/robustness/file_system'
14
+ require 'dbagile/robustness/dependencies'
@@ -0,0 +1,24 @@
1
+ module DbAgile
2
+ module FileSystemTools
3
+
4
+ # Returns a friendly path for display
5
+ def friendly_path(path, from)
6
+ from, path = Pathname.new(from), Pathname.new(path)
7
+ if path.to_s[0...from.to_s.length] == from.to_s
8
+ "~/#{path.relative_path_from(from)}"
9
+ else
10
+ nil
11
+ end
12
+ end
13
+
14
+ # Returns a friendly path, no matter what happens
15
+ def friendly_path!(path)
16
+ friendly_path(path, ENV['HOME']) or
17
+ friendly_path(path, File.expand_path('.')) or
18
+ path
19
+ end
20
+
21
+ extend(FileSystemTools)
22
+ end # module FileSystemTools
23
+ end # module DbAgile
24
+
@@ -0,0 +1,11 @@
1
+ module DbAgile
2
+ module MathTools
3
+
4
+ # Returns x if x > y, y otherwise
5
+ def max(x, y)
6
+ x > y ? x : y
7
+ end
8
+
9
+ extend(MathTools)
10
+ end # module StringTools
11
+ end # module DbAgile
@@ -0,0 +1,39 @@
1
+ module DbAgile
2
+ module Tools
3
+ class OrderedHash
4
+
5
+ # Decorates a hash as an ordered hash
6
+ def initialize(hash = {})
7
+ @hash = hash
8
+ @keys = hash.keys
9
+ end
10
+
11
+ # Delegated to hash
12
+ def method_missing(name, *args, &block)
13
+ @hash.send(name, *args, &block)
14
+ @keys = (@keys & @hash.keys)
15
+ end
16
+
17
+ # Sets a (name,value) pair
18
+ def []=(name, value)
19
+ @hash[name] = value
20
+ unless @keys.include?(name)
21
+ @keys << name
22
+ end
23
+ value
24
+ end
25
+
26
+ # Puts as YAML, maintaining order
27
+ def to_yaml(opts = {})
28
+ YAML::quick_emit(self, opts){|out|
29
+ out.map("tag:yaml.org,2002:map") do |map|
30
+ @keys.each{|key|
31
+ map.add(key.to_s, @hash[key])
32
+ }
33
+ end
34
+ }
35
+ end
36
+
37
+ end # class OrderedHash
38
+ end # module Tools
39
+ end # module DbAgile
@@ -0,0 +1,78 @@
1
+ module DbAgile
2
+ module RubyTools
3
+
4
+ # Returns the parent module of a class
5
+ def parent_module(clazz)
6
+ name = clazz.name
7
+ if name =~ /^(.*?)::([^:]+)$/
8
+ Kernel.eval($1)
9
+ else
10
+ nil
11
+ end
12
+ end
13
+
14
+ # Returns the unqualified name of a class
15
+ def class_unqualified_name(clazz)
16
+ name = clazz.name
17
+ if name =~ /::([^:]+)$/
18
+ $1
19
+ else
20
+ name
21
+ end
22
+ end
23
+ alias :unqualified_class_name :class_unqualified_name
24
+
25
+ # Makes a call to a block that accepts optional arguments
26
+ def optional_args_block_call(block, args)
27
+ if RUBY_VERSION >= "1.9.0"
28
+ if block.arity == 0
29
+ block.call
30
+ else
31
+ block.call(*args)
32
+ end
33
+ else
34
+ block.call(*args)
35
+ end
36
+ end
37
+
38
+ # Extracts the rdoc of a given ruby file source
39
+ def extract_file_rdoc(file)
40
+ source, doc, started = File.read(file), "", false
41
+ source.each_line{|line|
42
+ if /^\s*[#]/ =~ line
43
+ doc << line
44
+ started = true
45
+ elsif started
46
+ break
47
+ end
48
+ }
49
+ doc.gsub(/^\s*[#] ?/, "")
50
+ end
51
+
52
+ # Splits a text obtained through extract_file_rdoc into paragraphs
53
+ def rdoc_paragraphs(rdoc_text)
54
+ paragraphs, current = [], ""
55
+ rdoc_text.each_line do |s|
56
+ if s.strip.empty?
57
+ unless current.strip.empty?
58
+ paragraphs << current
59
+ end
60
+ current = ""
61
+ else
62
+ current << s
63
+ end
64
+ end
65
+ unless current.strip.empty?
66
+ paragraphs << current
67
+ end
68
+ paragraphs
69
+ end
70
+
71
+ # Convenient method for <code>rdoc_paragraphs(extract_file_rdoc(file))</code>
72
+ def rdoc_file_paragraphs(file)
73
+ rdoc_paragraphs(extract_file_rdoc(file))
74
+ end
75
+
76
+ extend(RubyTools)
77
+ end # module RubyTools
78
+ end # module DbAgile
@@ -0,0 +1,6 @@
1
+ module DbAgile
2
+ module StringTools
3
+
4
+
5
+ end # module StringTools
6
+ end # module DbAgile
@@ -0,0 +1,49 @@
1
+ module DbAgile
2
+ module Tools
3
+ module Tuple
4
+
5
+ # Returns the heading of a given tuple
6
+ def tuple_heading(tuple)
7
+ heading = {}
8
+ tuple.each_pair{|name, value| heading[name] = value.class}
9
+ heading
10
+ end
11
+
12
+ # Checks a tuple heading, displaying a warning message on the
13
+ # environment if something goes bad...
14
+ def check_tuple_heading(heading, environment)
15
+ heading.each_pair{|k,v|
16
+ if NilClass == v
17
+ environment.say("WARNING: NilClass in heading (type inference failure), using String")
18
+ heading[k] = String
19
+ elsif !DbAgile::RECOGNIZED_DOMAINS.include?(v)
20
+ environment.say("WARNING: Unrecognized domain #{v} in heading, using String")
21
+ heading[k] = String
22
+ end
23
+ }
24
+ heading
25
+ end
26
+
27
+ # Projects a tuple over some columns
28
+ def tuple_project(tuple, columns)
29
+ proj = {}
30
+ columns.collect{|col| proj[col] = tuple[col]}
31
+ proj
32
+ end
33
+
34
+ # Extract the key/value pairs that form a key on a tuple, given
35
+ # keys information. Returns tuple if no such better tuple can be found.
36
+ def tuple_key(tuple, keys)
37
+ return tuple if keys.nil?
38
+ key = keys.find{|k| k.all?{|a| !tuple[a].nil? }}
39
+ key.nil? ? tuple : tuple_project(tuple, key)
40
+ end
41
+
42
+ # Converts a tuple to a query string
43
+ def tuple_to_querystring(tuple)
44
+ tuple.collect{|k,v| "#{CGI::escape(k.to_s)}=#{CGI::escape(v.to_s)}"}.reverse.join('&')
45
+ end
46
+
47
+ end # module Tools
48
+ end # class Adapter
49
+ end # module DbAgile
@@ -0,0 +1,6 @@
1
+ require 'dbagile/tools/ruby'
2
+ require 'dbagile/tools/math'
3
+ require 'dbagile/tools/string'
4
+ require 'dbagile/tools/tuple'
5
+ require 'dbagile/tools/ordered_hash'
6
+ require 'dbagile/tools/file_system'