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,173 @@
1
+ module DbAgile
2
+
3
+ class Error < StandardError; end
4
+
5
+ # Raised when something goes wrong with a schema
6
+ class SchemaError < DbAgile::Error; end
7
+
8
+ #
9
+ # Raised when something goes really wrong with a schema. This certainly
10
+ # indicates a bug inside DbAgile, please report!
11
+ #
12
+ # Something wrong happened in DbAgile when using your schema. Please report
13
+ # the error to developers:
14
+ # #{cause.message}
15
+ # #{cause.backtrace}
16
+ #
17
+ class SchemaInternalError < DbAgile::SchemaError; end
18
+
19
+ #
20
+ # Raised when an operation on schemas fails because of conflicts (typically
21
+ # a merge operation without resolver block)
22
+ #
23
+ # Database schema conflict between #{left} and #{right}
24
+ #
25
+ class SchemaConflictError < DbAgile::SchemaError
26
+
27
+ # Left schema object
28
+ attr_reader :left
29
+
30
+ # Right schema object
31
+ attr_reader :right
32
+
33
+ # Part name
34
+ attr_reader :part_name
35
+
36
+ # Creates an error instance
37
+ def initialize(left, right, part_name = nil)
38
+ @left, @right = left, right
39
+ @part_name = part_name
40
+ super(left.parent)
41
+ end
42
+
43
+ def message
44
+ "Schema conflict occured on #{left} : #{part_name}"
45
+ end
46
+
47
+ end # class SchemaConflictError
48
+
49
+ #
50
+ # Raised when something goes wrong with a schema during a builder
51
+ # execution.
52
+ #
53
+ # As schema parsing is often made on YAML files, any error at builder
54
+ # stage is considered a syntax error. However, it includes schema
55
+ # type checking, which is not that syntactic!
56
+ #
57
+ # Syntax error when parsing #{schema_file}: #{cause.message}
58
+ #
59
+ class SchemaSyntaxError < DbAgile::SchemaError; end
60
+
61
+ #
62
+ # Raised when a schema is semantically not correct.
63
+ #
64
+ class SchemaSemanticsError < DbAgile::SchemaError
65
+
66
+ # Object-specific error tree
67
+ InvalidLogicalSchema = 0x1000000 #
68
+ InvalidRelvar = InvalidLogicalSchema | 0x0100000 #
69
+ InvalidHeading = InvalidRelvar | 0x0010000 #
70
+ UnsupportedEmptyHeading = InvalidHeading | 0x0001000 # schema_object=Heading
71
+ InvalidAttribute = InvalidHeading | 0x0002000 #
72
+ InvalidDefaultValue = InvalidAttribute | 0x0000100 # schema_object=Attribute
73
+ InvalidConstraints = InvalidRelvar | 0x0020000 #
74
+ MissingPrimaryKey = InvalidConstraints | 0x0001000 # schema_object=Relvar
75
+ InvalidConstraint = InvalidConstraints | 0x0002000 # schema_object=Constraint
76
+ InvalidCandidateKey = InvalidConstraint | 0x0000100 # schema_object=CandidateKey
77
+ InvalidForeignKey = InvalidConstraint | 0x0000200 # schema_object=ForeignKey
78
+ InvalidPhysicalSchema = 0x2000000
79
+ InvalidIndexes = InvalidPhysicalSchema | 0x0100000 #
80
+ InvalidIndex = InvalidIndexes | 0x0010000 #
81
+
82
+ # General flags
83
+ NoSuchRelvar = 0x0000001 # :relvar_name
84
+ NoSuchRelvarAttributes = 0x0000002 # :relvar_name, :attributes
85
+ NoSuchCandidateKey = 0x0000004 # :constraint_name
86
+ AttributeMismatch = 0x0000008 #
87
+ TargetKeyMismatch = 0x0000010 #
88
+
89
+ # User-defined messages
90
+ MESSAGE_KEYS = [
91
+ InvalidDefaultValue,
92
+ UnsupportedEmptyHeading,
93
+ MissingPrimaryKey,
94
+ InvalidConstraint,
95
+
96
+ InvalidIndex,
97
+
98
+ NoSuchRelvar,
99
+ NoSuchRelvarAttributes,
100
+ NoSuchCandidateKey,
101
+ AttributeMismatch,
102
+ TargetKeyMismatch
103
+ ]
104
+ MESSAGE_VALUES = [
105
+ 'invalid default value on attribute #{schema_object.name}',
106
+ 'relvar #{schema_object.relation_variable.name} has an empty heading (unsupported so far)',
107
+ 'relvar #{schema_object.name} has no primary key',
108
+ 'invalid constraint #{schema_object.name} on #{schema_object.relation_variable.name}',
109
+
110
+ 'invalid index #{schema_object.name}',
111
+
112
+ 'no such relvar #{args[:relvar_name]}',
113
+ 'no such attributes #{args[:attributes].join(\',\')}',
114
+ 'no such candidate key #{args[:constraint_name]}',
115
+ 'attribute mismatch',
116
+ 'target key mismatch'
117
+ ]
118
+
119
+ # Involved schema object
120
+ attr_reader :schema
121
+
122
+ # Collected semantical errors
123
+ attr_reader :errors
124
+
125
+ # Creates an error instance
126
+ def initialize(schema)
127
+ @schema = schema
128
+ @errors = []
129
+ end
130
+
131
+ # Converts an error to a message
132
+ def error_to_message(schema_object, error_code, args = {})
133
+ buffer = []
134
+ MESSAGE_KEYS.each_with_index{|msg_key, index|
135
+ next unless msg_key & error_code == msg_key
136
+ buffer << Kernel.eval('"' + MESSAGE_VALUES[index] + '"', binding)
137
+ }
138
+ buffer.join(', ')
139
+ end
140
+
141
+ # Returns a friendly message
142
+ def message(long = false)
143
+ buffer = "Schema #{schema.schema_identifier} contains errors"
144
+ if long
145
+ buffer << ":\n"
146
+ error_messages.each{|m| buffer << " * " << m << "\n"}
147
+ end
148
+ buffer
149
+ end
150
+
151
+ # Returns an arry of error messages
152
+ def error_messages
153
+ errors.collect{|e|error_to_message(*e)}
154
+ end
155
+
156
+ # Returns number of sub errors
157
+ def size
158
+ errors.size
159
+ end
160
+
161
+ # Is this error empty (no semantics error, then)
162
+ def empty?
163
+ @errors.empty?
164
+ end
165
+
166
+ # Adds a semantics error
167
+ def add_error(object, error_code, args = {})
168
+ @errors << [object, error_code, args]
169
+ end
170
+
171
+ end # class SchemaSemanticsError
172
+
173
+ end # module DbAgile
@@ -0,0 +1,68 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ class Logical
5
+ class Attribute < Schema::Part
6
+
7
+ ############################################################################
8
+ ### Attribute
9
+ ############################################################################
10
+
11
+ # Returns attribute domain
12
+ def domain
13
+ definition[:domain]
14
+ end
15
+
16
+ # Returns default value
17
+ def default_value
18
+ definition[:default]
19
+ end
20
+
21
+ # Returns default value
22
+ def mandatory?
23
+ !(definition[:mandatory] == false)
24
+ end
25
+
26
+ ############################################################################
27
+ ### Dependency control
28
+ ############################################################################
29
+
30
+ # @see DbAgile::Core::Schema::SchemaObject
31
+ def dependencies(include_parent = false)
32
+ include_parent ? [ parent ] : []
33
+ end
34
+
35
+ ############################################################################
36
+ ### Check interface
37
+ ############################################################################
38
+
39
+ # @see DbAgile::Core::Schema::SchemaObject
40
+ def _semantics_check(clazz, buffer)
41
+ unless default_value.nil? or default_value.kind_of?(domain)
42
+ buffer.add_error(self, clazz::InvalidDefaultValue)
43
+ end
44
+ end
45
+
46
+ ############################################################################
47
+ ### About IO
48
+ ############################################################################
49
+
50
+ # Delegation pattern on YAML flushing
51
+ def to_yaml(opts = {})
52
+ YAML::quick_emit(self, opts){|out|
53
+ defn = definition
54
+ out.map("tag:yaml.org,2002:map", :inline ) do |map|
55
+ map.add('domain', defn[:domain].to_s)
56
+ map.add('mandatory', false) unless defn[:mandatory]
57
+ if defn[:default]
58
+ map.add('default', defn[:default])
59
+ end
60
+ end
61
+ }
62
+ end
63
+
64
+ end # class Attribute
65
+ end # module Logical
66
+ end # module Schema
67
+ end # module Core
68
+ end # module DbAgile
@@ -0,0 +1,70 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ class Logical
5
+ class CandidateKey < Constraint
6
+
7
+ ############################################################################
8
+ ### Candidate key
9
+ ############################################################################
10
+
11
+ # Is it a primary key?
12
+ def primary?
13
+ definition[:type] == :primary_key
14
+ end
15
+
16
+ # Returns attribute names
17
+ def attribute_names
18
+ definition[:attributes]
19
+ end
20
+
21
+ # Returns key attributes
22
+ def key_attributes
23
+ rv = relation_variable
24
+ definition[:attributes].collect{|k| rv.heading[k]}
25
+ end
26
+
27
+ ############################################################################
28
+ ### Dependency control
29
+ ############################################################################
30
+
31
+ # @see DbAgile::Core::Schema::SchemaObject
32
+ def dependencies(include_parent = false)
33
+ include_parent ? [ parent ] + key_attributes : key_attributes
34
+ end
35
+
36
+ ############################################################################
37
+ ### Check interface
38
+ ############################################################################
39
+
40
+ # @see DbAgile::Core::Schema::SchemaObject
41
+ def _semantics_check(clazz, buffer)
42
+ rv = relation_variable
43
+ unless rv.heading.has_attributes?(definition[:attributes])
44
+ error_code = clazz::InvalidCandidateKey | clazz::NoSuchRelvarAttributes
45
+ buffer.add_error(self, error_code, :relvar_name => rv.name,
46
+ :attributes => definition[:attributes])
47
+ end
48
+ end
49
+
50
+ ############################################################################
51
+ ### About IO
52
+ ############################################################################
53
+
54
+ # Delegation pattern on YAML flushing
55
+ def to_yaml(opts = {})
56
+ YAML::quick_emit(self, opts){|out|
57
+ defn = definition
58
+ attrs = Schema::Builder::Coercion::unsymbolize_array(definition[:attributes])
59
+ out.map("tag:yaml.org,2002:map", :inline ) do |map|
60
+ map.add('type', definition[:type])
61
+ map.add('attributes', attrs)
62
+ end
63
+ }
64
+ end
65
+
66
+ end # class CandidateKey
67
+ end # module Logical
68
+ end # module Schema
69
+ end # module Core
70
+ end # module DbAgile
@@ -0,0 +1,121 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ class Logical
5
+ class ForeignKey < Constraint
6
+
7
+ ############################################################################
8
+ ### Foreign key
9
+ ############################################################################
10
+
11
+ # Returns relation variable on which this foreign key is installed.
12
+ def source_relvar
13
+ relation_variable
14
+ end
15
+ alias :referencing_relvar :source_relvar
16
+
17
+ # Collects referencing attributes on the source relvar
18
+ def source_attributes
19
+ rv = source_relvar
20
+ definition[:attributes].collect{|attr_name| rv.heading[attr_name]}
21
+ end
22
+
23
+ # Returns target relation variable (aka) referenced_relvar
24
+ def target_relvar
25
+ schema.logical.relation_variable(definition[:references])
26
+ end
27
+ alias :referenced_relvar :target_relvar
28
+
29
+ # Collects referencing attributes on the source relvar
30
+ def target_key
31
+ rv = target_relvar
32
+ if definition.key?(:key)
33
+ rv.constraints.constraint_by_name(definition[:key])
34
+ else
35
+ rv.constraints.primary_key
36
+ end
37
+ end
38
+
39
+ ############################################################################
40
+ ### Dependency control
41
+ ############################################################################
42
+
43
+ # @see DbAgile::Core::Schema::SchemaObject
44
+ def dependencies(include_parent = false)
45
+ deps = source_attributes + [ target_key ]
46
+ deps << parent if include_parent
47
+ deps
48
+ end
49
+
50
+ ############################################################################
51
+ ### Public check interface
52
+ ############################################################################
53
+
54
+ # @see DbAgile::Core::Schema::SchemaObject
55
+ def _semantics_check(clazz, errors)
56
+ failed = false
57
+
58
+ # 1) check source and target relvars
59
+ if (srv = source_relvar).nil?
60
+ raise DbAgile::SchemaInternalError, "Foreign key without source relvar"
61
+ end
62
+ if (trv = target_relvar).nil?
63
+ code = clazz::InvalidForeignKey | clazz::NoSuchRelvar
64
+ errors.add_error(self, code, :relvar_name => definition[:references])
65
+ failed = true
66
+ end
67
+ return if failed
68
+
69
+ # 2) Both exist, check source attributes
70
+ if !srv.heading.has_attributes?(definition[:attributes])
71
+ code = clazz::InvalidForeignKey | clazz::NoSuchRelvarAttributes
72
+ errors.add_error(self, code, :relvar_name => srv.name,
73
+ :attributes => definition[:attributes])
74
+ failed = true
75
+ end
76
+ return if failed
77
+
78
+ # 3) Check target key existence and kind now
79
+ trg_key = self.target_key
80
+ if trg_key.nil? or not(trg_key.candidate_key?)
81
+ code = clazz::InvalidForeignKey | clazz::NoSuchCandidateKey
82
+ errors.add_error(self, code, :constraint_name => definition[:key])
83
+ failed = true
84
+ end
85
+ return if failed
86
+
87
+ source_attrs, target_attrs = source_attributes, trg_key.key_attributes
88
+ if source_attrs.size != target_attrs.size
89
+ code = clazz::InvalidForeignKey | clazz::TargetKeyMismatch
90
+ errors.add_error(self, code, :constraint_name => definition[:key])
91
+ elsif source_attrs.collect{|a| a.domain} != target_attrs.collect{|a| a.domain}
92
+ code = clazz::InvalidForeignKey | clazz::TargetKeyMismatch
93
+ errors.add_error(self, code, :constraint_name => definition[:key])
94
+ end
95
+ end
96
+
97
+ ############################################################################
98
+ ### About IO
99
+ ############################################################################
100
+
101
+ # Delegation pattern on YAML flushing
102
+ def to_yaml(opts = {})
103
+ YAML::quick_emit(self, opts){|out|
104
+ defn = definition
105
+ attributes = Schema::Builder::Coercion::unsymbolize_array(definition[:attributes])
106
+ references = definition[:references].to_s
107
+ key = definition.key?(:key) ? definition[:key].to_s : nil
108
+ out.map("tag:yaml.org,2002:map", :inline ) do |map|
109
+ map.add('type', definition[:type])
110
+ map.add('attributes', attributes)
111
+ map.add('references', definition[:references].to_s)
112
+ map.add('key', key) unless key.nil?
113
+ end
114
+ }
115
+ end
116
+
117
+ end # class ForeignKey
118
+ end # module Logical
119
+ end # module Schema
120
+ end # module Core
121
+ end # module DbAgile
@@ -0,0 +1,58 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ class Logical
5
+ class Constraint < Schema::Part
6
+
7
+ ############################################################################
8
+ ### Constraint factory
9
+ ############################################################################
10
+
11
+ # Builds a constraint
12
+ def self.factor(name, definition)
13
+ case kind = definition[:type]
14
+ when :primary_key, :candidate_key, :key
15
+ Schema::Logical::CandidateKey.new(name, definition)
16
+ when :foreign_key
17
+ Schema::Logical::ForeignKey.new(name, definition)
18
+ else
19
+ raise ArgumentError, "Unexpected constraint kind #{kind}"
20
+ end
21
+ end
22
+
23
+ ############################################################################
24
+ ### Query interface
25
+ ############################################################################
26
+
27
+ # Returns true if this constraint is a candidate key (including a primary
28
+ # key)
29
+ def candidate_key?
30
+ self.kind_of?(Logical::CandidateKey)
31
+ end
32
+
33
+ # Returns true if this constraint is a primary key, false otherwise
34
+ def primary_key?
35
+ candidate_key? and primary?
36
+ end
37
+
38
+ # Returns true if this constraint is a foreign key
39
+ def foreign_key?
40
+ self.kind_of?(Logical::ForeignKey)
41
+ end
42
+
43
+ ############################################################################
44
+ ### Dependency control
45
+ ############################################################################
46
+
47
+ # @see DbAgile::Core::Schema::SchemaObject
48
+ def dependencies(include_parent = false)
49
+ include_parent ? [ parent ] : false
50
+ end
51
+
52
+ end # class Constraint
53
+ end # module Logical
54
+ end # module Schema
55
+ end # module Core
56
+ end # module DbAgile
57
+ require 'dbagile/core/schema/logical/constraint/candidate_key'
58
+ require 'dbagile/core/schema/logical/constraint/foreign_key'
@@ -0,0 +1,28 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ class Logical
5
+ class Constraints < Schema::Composite
6
+
7
+ # Returns the primary key
8
+ def primary_key
9
+ each_part{|c|
10
+ return c if c.kind_of?(Logical::CandidateKey) and c.primary?
11
+ }
12
+ nil
13
+ end
14
+
15
+ # Returns a constraint by name
16
+ def constraint_by_name(name)
17
+ self[name]
18
+ end
19
+
20
+ def to_s
21
+ "Constraints of #{relation_variable.name}"
22
+ end
23
+
24
+ end # class Constraints
25
+ end # class Logical
26
+ end # module Schema
27
+ end # module Core
28
+ end # module DbAgile
@@ -0,0 +1,47 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ class Logical
5
+ class Heading < Schema::Composite
6
+
7
+ alias :attributes :parts
8
+
9
+ # Yields the block with each attribute
10
+ def each_attribute(&block)
11
+ attributes.each(&block)
12
+ end
13
+
14
+ # Checks if this heading has some attributes (through
15
+ # names)
16
+ def has_attributes?(names)
17
+ parts = composite_parts
18
+ names.all?{|k| parts.key?(k)}
19
+ end
20
+
21
+ # Returns the domain of a specific attribute
22
+ def domain_of(attr_name)
23
+ attribute = self[attr_name]
24
+ attribute ? attribute.domain : nil
25
+ end
26
+
27
+ ############################################################################
28
+ ### Private interface
29
+ ############################################################################
30
+
31
+ # @see DbAgile::Core::Schema
32
+ def _semantics_check(clazz, buffer)
33
+ if empty?
34
+ buffer.add_error(self, clazz::UnsupportedEmptyHeading)
35
+ end
36
+ super(clazz, buffer)
37
+ end
38
+
39
+ def to_s
40
+ "Heading of #{relation_variable.name}"
41
+ end
42
+
43
+ end # class Heading
44
+ end # class Logical
45
+ end # module Schema
46
+ end # module Core
47
+ end # module DbAgile
@@ -0,0 +1,81 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ class Logical
5
+ class Relvar < Schema::Composite
6
+
7
+ # Relvar name
8
+ attr_reader :name
9
+
10
+ # Creates a relation variable instance
11
+ def initialize(name, parts = _default_parts)
12
+ @name = name.to_s.to_sym
13
+ super(parts)
14
+ @insert_order = [ :heading, :constraints ] & parts.keys
15
+ end
16
+
17
+ ############################################################################
18
+ ### Private interface
19
+ ############################################################################
20
+
21
+ # @see DbAgile::Core::Schema::Composite#_install_eigenclass_methods?
22
+ def _install_eigenclass_methods?
23
+ true
24
+ end
25
+
26
+ # Creates default parts
27
+ def _default_parts
28
+ {:heading => Schema::Logical::Heading.new,
29
+ :constraints => Schema::Logical::Constraints.new}
30
+ end
31
+
32
+ # Makes a sanity check on the part
33
+ def _sanity_check(schema)
34
+ raise SchemaInternalError, "No name provided on #{self}" if name.nil?
35
+ super(schema)
36
+ end
37
+
38
+ # Checks this composite's semantics and collects errors inside buffer
39
+ def _semantics_check(clazz, buffer)
40
+ if constraints.primary_key.nil?
41
+ buffer.add_error(self, clazz::MissingPrimaryKey)
42
+ end
43
+ super(clazz, buffer)
44
+ end
45
+
46
+ ############################################################################
47
+ ### Pseudo-private SchemaObject interface
48
+ ############################################################################
49
+
50
+ # Returns the arguments to pass to builder handler
51
+ def builder_args
52
+ [ name ]
53
+ end
54
+
55
+ ############################################################################
56
+ ### Equality and hash code
57
+ ############################################################################
58
+
59
+ # Compares with another attribute
60
+ def look_same_as?(other)
61
+ return nil unless other.kind_of?(Relvar)
62
+ return false unless name == other.name
63
+ super(other)
64
+ end
65
+
66
+ # Duplicates this attribute
67
+ def dup
68
+ Logical::Relvar.new(name, :heading => heading.dup, :constraints => constraints.dup)
69
+ end
70
+
71
+ # Returns a string representation
72
+ def to_s
73
+ "#{DbAgile::RubyTools::unqualified_class_name(self.class)}: #{name}"
74
+ end
75
+
76
+ private :_default_parts
77
+ end # class Relvar
78
+ end # module Logical
79
+ end # module Schema
80
+ end # module Core
81
+ end # module DbAgile
@@ -0,0 +1,24 @@
1
+ module DbAgile
2
+ module Core
3
+ module Schema
4
+ class Logical < Schema::Composite
5
+
6
+ # Returns a relation variable by its name
7
+ def relation_variable(name)
8
+ self[name]
9
+ end
10
+
11
+ # Returns an array with part dependencies
12
+ def dependencies(include_parent = false)
13
+ []
14
+ end
15
+
16
+ end # class Logical
17
+ end # module Schema
18
+ end # module Core
19
+ end # module DbAgile
20
+ require 'dbagile/core/schema/logical/relvar'
21
+ require 'dbagile/core/schema/logical/heading'
22
+ require 'dbagile/core/schema/logical/attribute'
23
+ require 'dbagile/core/schema/logical/constraints'
24
+ require 'dbagile/core/schema/logical/constraint'