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