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.
- data/LICENCE.textile +12 -0
- data/README.textile +89 -0
- data/bin/dba +22 -0
- data/lib/dbagile/adapter/sequel/class_methods.rb +18 -0
- data/lib/dbagile/adapter/sequel/connection.rb +38 -0
- data/lib/dbagile/adapter/sequel/data/table_driven.rb +30 -0
- data/lib/dbagile/adapter/sequel/data/transaction_driven.rb +43 -0
- data/lib/dbagile/adapter/sequel/schema/concrete_script.rb +135 -0
- data/lib/dbagile/adapter/sequel/schema/physical_dump.rb +106 -0
- data/lib/dbagile/adapter/sequel/schema/schema2sequel_args.rb +71 -0
- data/lib/dbagile/adapter/sequel/schema/table_driven.rb +52 -0
- data/lib/dbagile/adapter/sequel/schema/transaction_driven.rb +46 -0
- data/lib/dbagile/adapter/sequel/sequel_tracer.rb +144 -0
- data/lib/dbagile/adapter/sequel.rb +46 -0
- data/lib/dbagile/adapter.rb +15 -0
- data/lib/dbagile/command/api.rb +49 -0
- data/lib/dbagile/command/bulk/commons.rb +130 -0
- data/lib/dbagile/command/bulk/export.rb +99 -0
- data/lib/dbagile/command/bulk/import.rb +147 -0
- data/lib/dbagile/command/bulk.rb +3 -0
- data/lib/dbagile/command/class_methods.rb +103 -0
- data/lib/dbagile/command/db/add.rb +94 -0
- data/lib/dbagile/command/db/list.rb +40 -0
- data/lib/dbagile/command/db/ping.rb +49 -0
- data/lib/dbagile/command/db/rm.rb +52 -0
- data/lib/dbagile/command/db/stage.rb +81 -0
- data/lib/dbagile/command/db/use.rb +48 -0
- data/lib/dbagile/command/db.rb +6 -0
- data/lib/dbagile/command/dba.rb +121 -0
- data/lib/dbagile/command/help.rb +50 -0
- data/lib/dbagile/command/repo/create.rb +54 -0
- data/lib/dbagile/command/repo.rb +1 -0
- data/lib/dbagile/command/robust.rb +86 -0
- data/lib/dbagile/command/schema/check.rb +59 -0
- data/lib/dbagile/command/schema/commons.rb +118 -0
- data/lib/dbagile/command/schema/diff.rb +101 -0
- data/lib/dbagile/command/schema/dump.rb +48 -0
- data/lib/dbagile/command/schema/merge.rb +55 -0
- data/lib/dbagile/command/schema/sql_script.rb +124 -0
- data/lib/dbagile/command/schema.rb +6 -0
- data/lib/dbagile/command/sql/drop.rb +40 -0
- data/lib/dbagile/command/sql/heading.rb +34 -0
- data/lib/dbagile/command/sql/send.rb +67 -0
- data/lib/dbagile/command/sql/show.rb +42 -0
- data/lib/dbagile/command/sql.rb +4 -0
- data/lib/dbagile/command/web/tools.rb +23 -0
- data/lib/dbagile/command/web.rb +1 -0
- data/lib/dbagile/command.rb +158 -0
- data/lib/dbagile/contract/connection.rb +66 -0
- data/lib/dbagile/contract/data/dataset.rb +69 -0
- data/lib/dbagile/contract/data/table_driven.rb +49 -0
- data/lib/dbagile/contract/data/transaction_driven.rb +74 -0
- data/lib/dbagile/contract/data.rb +3 -0
- data/lib/dbagile/contract/robust/helpers.rb +19 -0
- data/lib/dbagile/contract/robust/optimistic/data/table_driven.rb +31 -0
- data/lib/dbagile/contract/robust/optimistic/data/transaction_driven.rb +45 -0
- data/lib/dbagile/contract/robust/optimistic/schema/table_driven.rb +53 -0
- data/lib/dbagile/contract/robust/optimistic/schema/transaction_driven.rb +45 -0
- data/lib/dbagile/contract/robust/optimistic.rb +18 -0
- data/lib/dbagile/contract/robust.rb +20 -0
- data/lib/dbagile/contract/schema/table_driven.rb +89 -0
- data/lib/dbagile/contract/schema/transaction_driven.rb +68 -0
- data/lib/dbagile/contract/schema.rb +2 -0
- data/lib/dbagile/contract/utils/delegate.rb +17 -0
- data/lib/dbagile/contract/utils/full.rb +13 -0
- data/lib/dbagile/contract/utils.rb +2 -0
- data/lib/dbagile/contract.rb +5 -0
- data/lib/dbagile/core/chain.rb +92 -0
- data/lib/dbagile/core/connection.rb +51 -0
- data/lib/dbagile/core/database.rb +221 -0
- data/lib/dbagile/core/io/dsl.rb +95 -0
- data/lib/dbagile/core/io/robustness.rb +82 -0
- data/lib/dbagile/core/io.rb +2 -0
- data/lib/dbagile/core/repository/builder.rb +67 -0
- data/lib/dbagile/core/repository/yaml_methods.rb +82 -0
- data/lib/dbagile/core/repository.rb +211 -0
- data/lib/dbagile/core/schema/builder/coercion.rb +210 -0
- data/lib/dbagile/core/schema/builder/concept_factory.rb +61 -0
- data/lib/dbagile/core/schema/builder.rb +187 -0
- data/lib/dbagile/core/schema/composite.rb +239 -0
- data/lib/dbagile/core/schema/computations/filter.rb +40 -0
- data/lib/dbagile/core/schema/computations/merge.rb +55 -0
- data/lib/dbagile/core/schema/computations/minus.rb +44 -0
- data/lib/dbagile/core/schema/computations/split.rb +37 -0
- data/lib/dbagile/core/schema/computations.rb +4 -0
- data/lib/dbagile/core/schema/database_schema.rb +129 -0
- data/lib/dbagile/core/schema/errors.rb +173 -0
- data/lib/dbagile/core/schema/logical/attribute.rb +68 -0
- data/lib/dbagile/core/schema/logical/constraint/candidate_key.rb +70 -0
- data/lib/dbagile/core/schema/logical/constraint/foreign_key.rb +121 -0
- data/lib/dbagile/core/schema/logical/constraint.rb +58 -0
- data/lib/dbagile/core/schema/logical/constraints.rb +28 -0
- data/lib/dbagile/core/schema/logical/heading.rb +47 -0
- data/lib/dbagile/core/schema/logical/relvar.rb +81 -0
- data/lib/dbagile/core/schema/logical.rb +24 -0
- data/lib/dbagile/core/schema/migrate/abstract_script.rb +35 -0
- data/lib/dbagile/core/schema/migrate/collapse_table.rb +15 -0
- data/lib/dbagile/core/schema/migrate/create_table.rb +15 -0
- data/lib/dbagile/core/schema/migrate/drop_table.rb +15 -0
- data/lib/dbagile/core/schema/migrate/expand_table.rb +15 -0
- data/lib/dbagile/core/schema/migrate/operation.rb +141 -0
- data/lib/dbagile/core/schema/migrate/stager.rb +282 -0
- data/lib/dbagile/core/schema/migrate.rb +2 -0
- data/lib/dbagile/core/schema/part.rb +114 -0
- data/lib/dbagile/core/schema/physical/index.rb +64 -0
- data/lib/dbagile/core/schema/physical/indexes.rb +12 -0
- data/lib/dbagile/core/schema/physical.rb +26 -0
- data/lib/dbagile/core/schema/robustness.rb +39 -0
- data/lib/dbagile/core/schema/schema_object.rb +94 -0
- data/lib/dbagile/core/schema.rb +254 -0
- data/lib/dbagile/core/transaction.rb +74 -0
- data/lib/dbagile/core.rb +7 -0
- data/lib/dbagile/environment/buffering.rb +45 -0
- data/lib/dbagile/environment/delegator.rb +59 -0
- data/lib/dbagile/environment/interactions.rb +208 -0
- data/lib/dbagile/environment/on_error.rb +47 -0
- data/lib/dbagile/environment/repository.rb +161 -0
- data/lib/dbagile/environment/robustness.rb +7 -0
- data/lib/dbagile/environment/testing.rb +23 -0
- data/lib/dbagile/environment.rb +122 -0
- data/lib/dbagile/errors.rb +30 -0
- data/lib/dbagile/io/csv.rb +99 -0
- data/lib/dbagile/io/json.rb +41 -0
- data/lib/dbagile/io/pretty_table.rb +128 -0
- data/lib/dbagile/io/ruby.rb +62 -0
- data/lib/dbagile/io/text.rb +18 -0
- data/lib/dbagile/io/type_safe.rb +65 -0
- data/lib/dbagile/io/xml.rb +35 -0
- data/lib/dbagile/io/yaml.rb +30 -0
- data/lib/dbagile/io.rb +94 -0
- data/lib/dbagile/loader.rb +16 -0
- data/lib/dbagile/plugin.rb +29 -0
- data/lib/dbagile/restful/client/delete.rb +22 -0
- data/lib/dbagile/restful/client/get.rb +24 -0
- data/lib/dbagile/restful/client/post.rb +22 -0
- data/lib/dbagile/restful/client/utils.rb +16 -0
- data/lib/dbagile/restful/client.rb +41 -0
- data/lib/dbagile/restful/middleware/delete.rb +22 -0
- data/lib/dbagile/restful/middleware/get.rb +27 -0
- data/lib/dbagile/restful/middleware/one_database.rb +82 -0
- data/lib/dbagile/restful/middleware/post.rb +23 -0
- data/lib/dbagile/restful/middleware/utils.rb +65 -0
- data/lib/dbagile/restful/middleware.rb +54 -0
- data/lib/dbagile/restful/server.rb +65 -0
- data/lib/dbagile/restful.rb +9 -0
- data/lib/dbagile/robustness/dependencies.rb +36 -0
- data/lib/dbagile/robustness/file_system.rb +53 -0
- data/lib/dbagile/robustness.rb +14 -0
- data/lib/dbagile/tools/file_system.rb +24 -0
- data/lib/dbagile/tools/math.rb +11 -0
- data/lib/dbagile/tools/ordered_hash.rb +39 -0
- data/lib/dbagile/tools/ruby.rb +78 -0
- data/lib/dbagile/tools/string.rb +6 -0
- data/lib/dbagile/tools/tuple.rb +49 -0
- data/lib/dbagile/tools.rb +6 -0
- data/lib/dbagile.rb +66 -0
- data/test/assumptions/equality.spec +11 -0
- data/test/assumptions/fixtures.rb +39 -0
- data/test/assumptions/inheritance.spec +17 -0
- data/test/assumptions/sequel/autonumber.spec +19 -0
- data/test/assumptions/sequel/connect.spec +29 -0
- data/test/assumptions/sequel/test.db +0 -0
- data/test/assumptions/stdlib/pathname.spec +13 -0
- data/test/assumptions/yaml/fixtures.rb +25 -0
- data/test/assumptions/yaml/to_yaml.spec +10 -0
- data/test/assumptions.spec +2 -0
- data/test/commands/bulk/export.spec +100 -0
- data/test/commands/bulk/import.spec +49 -0
- data/test/commands/db/add.spec +31 -0
- data/test/commands/db/list.spec +29 -0
- data/test/commands/db/ping.spec +21 -0
- data/test/commands/db/rm.spec +18 -0
- data/test/commands/db/use.spec +18 -0
- data/test/commands/dba.spec +54 -0
- data/test/commands/repo/create.spec +30 -0
- data/test/commands/schema/check.spec +25 -0
- data/test/commands/schema/diff.spec +30 -0
- data/test/commands/schema/dump.spec +23 -0
- data/test/commands/schema/fixtures/add_constraint.yaml +30 -0
- data/test/commands/schema/fixtures/announced.yaml +28 -0
- data/test/commands/schema/fixtures/effective.yaml +20 -0
- data/test/commands/schema/fixtures/invalid.yaml +6 -0
- data/test/commands/schema/sql_script.spec +56 -0
- data/test/commands/sql/drop.spec +25 -0
- data/test/commands/sql/heading.spec +7 -0
- data/test/commands/sql/scripts/delete.sql +1 -0
- data/test/commands/sql/scripts/insert.sql +2 -0
- data/test/commands/sql/send.spec +29 -0
- data/test/commands/sql/show.spec +17 -0
- data/test/commands.spec +138 -0
- data/test/contract/connection/transaction.ex +11 -0
- data/test/contract/connection.spec +9 -0
- data/test/contract/data/dataset/columns.ex +5 -0
- data/test/contract/data/dataset/count.ex +5 -0
- data/test/contract/data/dataset.spec +9 -0
- data/test/contract/data/table_driven/dataset.ex +31 -0
- data/test/contract/data/table_driven/exists_q.ex +27 -0
- data/test/contract/data/table_driven.spec +9 -0
- data/test/contract/data/transaction_driven/delete.ex +29 -0
- data/test/contract/data/transaction_driven/direct_sql.ex +19 -0
- data/test/contract/data/transaction_driven/insert.ex +8 -0
- data/test/contract/data/transaction_driven/update.ex +19 -0
- data/test/contract/data/transaction_driven.spec +18 -0
- data/test/contract/robust/data/table_driven.spec +15 -0
- data/test/contract/robust/data/transaction_driven.spec +21 -0
- data/test/contract/robust/schema/table_driven.spec +21 -0
- data/test/contract/robust/schema/transaction_driven.spec +19 -0
- data/test/contract/schema/table_driven/column_names.ex +5 -0
- data/test/contract/schema/table_driven/has_column_q.ex +13 -0
- data/test/contract/schema/table_driven/has_table_q.ex +11 -0
- data/test/contract/schema/table_driven/heading.ex +5 -0
- data/test/contract/schema/table_driven.spec +9 -0
- data/test/contract/schema/transaction_driven/create_table.ex +10 -0
- data/test/contract/schema/transaction_driven/drop_table.ex +10 -0
- data/test/contract/schema/transaction_driven.spec +18 -0
- data/test/contract.spec +66 -0
- data/test/fixtures/basics/data/basic_values.rb +13 -0
- data/test/fixtures/basics/data/empty_table.rb +3 -0
- data/test/fixtures/basics/data/non_empty_table.rb +4 -0
- data/test/fixtures/basics/data/parts.rb +8 -0
- data/test/fixtures/basics/data/suppliers.rb +7 -0
- data/test/fixtures/basics/data/supplies.rb +14 -0
- data/test/fixtures/basics/dbagile.idx +20 -0
- data/test/fixtures/basics/fixtures.yaml +28 -0
- data/test/fixtures/basics/robust.db +0 -0
- data/test/fixtures/basics/suppliers.yaml +30 -0
- data/test/fixtures/basics/test.db +0 -0
- data/test/fixtures/empty/dbagile.idx +5 -0
- data/test/fixtures.rb +152 -0
- data/test/restful/delete/no_format.ex +32 -0
- data/test/restful/delete.spec +8 -0
- data/test/restful/get/csv_format.ex +12 -0
- data/test/restful/get/json_format.ex +19 -0
- data/test/restful/get/query_string.ex +11 -0
- data/test/restful/get/text_format.ex +12 -0
- data/test/restful/get/yaml_format.ex +14 -0
- data/test/restful/get.spec +5 -0
- data/test/restful/post/no_format.ex +22 -0
- data/test/restful/post.spec +8 -0
- data/test/restful.spec +32 -0
- data/test/run_all_suite.rb +51 -0
- data/test/spec_helper.rb +26 -0
- data/test/support/be_a_valid_json_string.rb +19 -0
- data/test/support/be_a_valid_yaml_string.rb +18 -0
- data/test/unit/adapter/factor.spec +13 -0
- data/test/unit/adapter/sequel/new.spec +19 -0
- data/test/unit/command/api.spec +12 -0
- data/test/unit/command/command_for.spec +36 -0
- data/test/unit/command/command_name_of.spec +21 -0
- data/test/unit/command/ruby_method_for.spec +21 -0
- data/test/unit/command/sanity.spec +34 -0
- data/test/unit/contract/utils/delegate/delegate.spec +23 -0
- data/test/unit/core/chain/chain.spec +57 -0
- data/test/unit/core/chain/connect.spec +22 -0
- data/test/unit/core/chain/delegate_chain.spec +16 -0
- data/test/unit/core/chain/initialize.spec +19 -0
- data/test/unit/core/chain/plug.spec +31 -0
- data/test/unit/core/io/dsl/scope.spec +9 -0
- data/test/unit/core/repository/create_bang.spec +31 -0
- data/test/unit/core/repository/current.spec +31 -0
- data/test/unit/core/repository/database.spec +47 -0
- data/test/unit/core/repository/fixtures/corrupted/dbagile.idx +1 -0
- data/test/unit/core/repository/fixtures/test_and_prod/dbagile.idx +21 -0
- data/test/unit/core/repository/fixtures.rb +25 -0
- data/test/unit/core/repository/has_database_q.spec +16 -0
- data/test/unit/core/repository/load.spec +51 -0
- data/test/unit/core/repository/to_yaml.spec +17 -0
- data/test/unit/core/schema/check.spec +32 -0
- data/test/unit/core/schema/empty_q.spec +18 -0
- data/test/unit/core/schema/filter.spec +42 -0
- data/test/unit/core/schema/fixtures/dbagile.yaml +7 -0
- data/test/unit/core/schema/fixtures/empty.yaml +11 -0
- data/test/unit/core/schema/fixtures/invalid.yaml +54 -0
- data/test/unit/core/schema/fixtures/left.yaml +46 -0
- data/test/unit/core/schema/fixtures/left_minus_right.yaml +31 -0
- data/test/unit/core/schema/fixtures/right.yaml +46 -0
- data/test/unit/core/schema/fixtures/right_minus_left.yaml +31 -0
- data/test/unit/core/schema/fixtures/suppliers_and_parts.yaml +30 -0
- data/test/unit/core/schema/fixtures.rb +32 -0
- data/test/unit/core/schema/merge.spec +72 -0
- data/test/unit/core/schema/minus.spec +26 -0
- data/test/unit/core/schema/sanity.spec +39 -0
- data/test/unit/core/schema/split.spec +58 -0
- data/test/unit/core/schema/stage_script.spec +26 -0
- data/test/unit/core/schema/to_yaml.spec +13 -0
- data/test/unit/core/schema/yaml_display.spec +14 -0
- data/test/unit/core/schema/yaml_load.spec +20 -0
- data/test/unit/core/transaction/transaction.spec +10 -0
- data/test/unit/fixtures.rb +67 -0
- data/test/unit/io/to_xxx.spec +52 -0
- data/test/unit/plugin/options.spec +21 -0
- data/test/unit/plugin/tuple_heading.spec +11 -0
- data/test/unit/plugin/with_options.spec +12 -0
- data/test/unit/tools/ruby/class_unqualified_name.spec +26 -0
- data/test/unit/tools/ruby/extract_file_rdoc.spec +10 -0
- data/test/unit/tools/ruby/fixtures/rdoc.txt +12 -0
- data/test/unit/tools/ruby/fixtures.rb +19 -0
- data/test/unit/tools/ruby/optional_args_block_call.spec +35 -0
- data/test/unit/tools/ruby/parent_module.spec +21 -0
- data/test/unit/tools/ruby/rdoc_file_paragraphs.spec +13 -0
- data/test/unit/tools/tuple/tuple_heading.spec +11 -0
- data/test/unit/tools/tuple/tuple_key.spec +27 -0
- data/test/unit/tools/tuple/tuple_project.spec +23 -0
- data/test/unit.spec +3 -0
- metadata +422 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Core
|
|
3
|
+
module Schema
|
|
4
|
+
class Composite < SchemaObject
|
|
5
|
+
|
|
6
|
+
# Creates a composite instance with parts
|
|
7
|
+
def initialize(composite_parts = _default_parts)
|
|
8
|
+
unless composite_parts.kind_of?(Hash)
|
|
9
|
+
raise ArgumentError, "Composite parts must be a hash, got #{composite_parts.inspect}"
|
|
10
|
+
end
|
|
11
|
+
_install_parts(composite_parts)
|
|
12
|
+
@insert_order = nil
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
############################################################################
|
|
16
|
+
### Private interface
|
|
17
|
+
############################################################################
|
|
18
|
+
attr_reader :composite_parts
|
|
19
|
+
protected :composite_parts
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
# Creates defaut parts hash
|
|
23
|
+
def _default_parts
|
|
24
|
+
{}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Returns prefered keys order
|
|
28
|
+
def _prefered_order
|
|
29
|
+
@insert_order || []
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def _prefered_order=(order)
|
|
33
|
+
@insert_order = order
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Make installation of parts
|
|
37
|
+
def _install_parts(parts)
|
|
38
|
+
meth = _install_eigenclass_methods?
|
|
39
|
+
parts.each_pair{|k, v|
|
|
40
|
+
v.send(:parent=, self)
|
|
41
|
+
if meth
|
|
42
|
+
eigenclazz = (class << self; self; end)
|
|
43
|
+
eigenclazz.send(:define_method, k){ @composite_parts[k] }
|
|
44
|
+
end
|
|
45
|
+
}
|
|
46
|
+
@composite_parts = parts
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Installs eigenclass methods on parts provided at construction
|
|
50
|
+
def _install_eigenclass_methods?
|
|
51
|
+
false
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Duplicates parts
|
|
55
|
+
def _dup_parts
|
|
56
|
+
dup_parts = {}
|
|
57
|
+
@composite_parts.each_pair{|name, part| dup_parts[name] = part.dup}
|
|
58
|
+
dup_parts
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
protected
|
|
62
|
+
|
|
63
|
+
# Removes empty objects from parts
|
|
64
|
+
def _strip!
|
|
65
|
+
to_remove = part_keys.select{|k|
|
|
66
|
+
self[k].composite? and self[k].empty?
|
|
67
|
+
}
|
|
68
|
+
@composite_parts.delete_if{|k, v|
|
|
69
|
+
to_remove.include?(k)
|
|
70
|
+
}
|
|
71
|
+
if @insert_order
|
|
72
|
+
@insert_order -= to_remove
|
|
73
|
+
end
|
|
74
|
+
_sanity_check(schema)
|
|
75
|
+
self
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Makes a sanity check on the composite
|
|
79
|
+
def _sanity_check(schema)
|
|
80
|
+
if @insert_order
|
|
81
|
+
too_much = @insert_order - @composite_parts.keys
|
|
82
|
+
missing = @composite_parts.keys - @insert_order
|
|
83
|
+
unless too_much.empty? and missing.empty?
|
|
84
|
+
raise SchemaInternalError, "Key divergence"
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
parts.each{|p|
|
|
88
|
+
raise SchemaInternalError, "Invalid parent on #{self}" unless p.parent == self
|
|
89
|
+
raise SchemaInternalError, "Invalid schema on on #{self}" unless p.schema == schema
|
|
90
|
+
p._sanity_check(schema)
|
|
91
|
+
}
|
|
92
|
+
rescue StandardError => ex
|
|
93
|
+
raise SchemaInternalError, "Something goes wrong on #{self}: #{ex.message}", ex.backtrace
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Checks this composite's semantics and collect errors
|
|
97
|
+
def _semantics_check(clazz, buffer)
|
|
98
|
+
parts.collect{|p| p._semantics_check(clazz, buffer)}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
############################################################################
|
|
102
|
+
### Public interface
|
|
103
|
+
############################################################################
|
|
104
|
+
public
|
|
105
|
+
|
|
106
|
+
# Returns an array with part dependencies
|
|
107
|
+
def dependencies(include_parent = false)
|
|
108
|
+
deps = parts.collect{|p| p.dependencies(include_parent)}.flatten.uniq
|
|
109
|
+
deps += [ parent ] if include_parent and not(parent.nil?)
|
|
110
|
+
deps
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Yields the block with each part in turn
|
|
114
|
+
def each_part(&block)
|
|
115
|
+
parts.each(&block)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# @see DbAgile::Core::Schema
|
|
119
|
+
def visit(&block)
|
|
120
|
+
block.call(self, parent)
|
|
121
|
+
parts.each{|p| p.visit(&block)}
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
############################################################################
|
|
125
|
+
### SchemaObject
|
|
126
|
+
############################################################################
|
|
127
|
+
|
|
128
|
+
# @see DbAgile::Core::SchemaObject
|
|
129
|
+
def empty?(recurse = true)
|
|
130
|
+
if recurse
|
|
131
|
+
parts.all?{|p| p.composite? && p.empty?(recurse)}
|
|
132
|
+
else
|
|
133
|
+
@composite_parts.empty?
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Returns number of parts
|
|
138
|
+
def size
|
|
139
|
+
@composite_parts.size
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# @see DbAgile::Core::SchemaObject
|
|
143
|
+
def part_keys(sort = false)
|
|
144
|
+
if sort
|
|
145
|
+
@composite_parts.keys.sort{|k1,k2| k1.to_s <=> k2.to_s}
|
|
146
|
+
else
|
|
147
|
+
(_prefered_order + @composite_parts.keys).uniq
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# @see DbAgile::Core::SchemaObject
|
|
152
|
+
def parts
|
|
153
|
+
part_keys(false).collect{|k| self[k]}
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# @see DbAgile::Core::SchemaObject
|
|
157
|
+
def [](name)
|
|
158
|
+
@composite_parts[name]
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# @see DbAgile::Core::SchemaObject
|
|
162
|
+
def []=(name, part, status = nil)
|
|
163
|
+
if @composite_parts.key?(name)
|
|
164
|
+
raise SchemaConflictError.new(self[name], part, name)
|
|
165
|
+
end
|
|
166
|
+
@composite_parts[name] = part
|
|
167
|
+
(@insert_order ||= []) << name
|
|
168
|
+
part.send(:parent=, self)
|
|
169
|
+
unless status.nil?
|
|
170
|
+
part.visit{|p, parent| p.status = status}
|
|
171
|
+
end
|
|
172
|
+
part
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
############################################################################
|
|
176
|
+
### About IO
|
|
177
|
+
############################################################################
|
|
178
|
+
|
|
179
|
+
# @see DbAgile::Core::SchemaObject
|
|
180
|
+
def to_yaml(opts = {})
|
|
181
|
+
YAML::quick_emit(self, opts){|out|
|
|
182
|
+
out.map("tag:yaml.org,2002:map") do |map|
|
|
183
|
+
part_keys.each{|k|
|
|
184
|
+
map.add(k.to_s, self[k])
|
|
185
|
+
}
|
|
186
|
+
end
|
|
187
|
+
}
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Returns a yaml string
|
|
191
|
+
def yaml_display(env,
|
|
192
|
+
options = {},
|
|
193
|
+
colors = DbAgile::Core::Schema::STATUS_TO_COLOR,
|
|
194
|
+
indent = 0)
|
|
195
|
+
part_keys.each{|k|
|
|
196
|
+
part = self[k]
|
|
197
|
+
status = part.status.to_s.ljust(25)
|
|
198
|
+
show_it = !(part.status == Schema::NO_CHANGE and options[:skip_unchanged])
|
|
199
|
+
if show_it
|
|
200
|
+
mine = " "*indent + k.to_s + ":"
|
|
201
|
+
if part.composite?
|
|
202
|
+
env.display(mine, colors[part.status])
|
|
203
|
+
part.yaml_display(env, options, colors, indent+1)
|
|
204
|
+
else
|
|
205
|
+
part_str = part.to_yaml
|
|
206
|
+
part_str =~ /---\s*(.*)$/
|
|
207
|
+
part_str = $1
|
|
208
|
+
env.display(mine + " " + part_str, colors[part.status])
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
}
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
############################################################################
|
|
215
|
+
### Equality and hash code
|
|
216
|
+
############################################################################
|
|
217
|
+
|
|
218
|
+
# @see DbAgile::Core::SchemaObject
|
|
219
|
+
def look_same_as?(other)
|
|
220
|
+
return nil unless other.kind_of?(self.class)
|
|
221
|
+
my_parts = part_keys(true)
|
|
222
|
+
return false unless (my_parts == other.part_keys(true))
|
|
223
|
+
my_parts.all?{|k| self[k].look_same_as?(other[k])}
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# @see DbAgile::Core::SchemaObject
|
|
227
|
+
def dup
|
|
228
|
+
self.class.new(_dup_parts)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# Returns a string representation
|
|
232
|
+
def to_s
|
|
233
|
+
"#{DbAgile::RubyTools::unqualified_class_name(self.class)}"
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
end # class Composite
|
|
237
|
+
end # module Schema
|
|
238
|
+
end # module Core
|
|
239
|
+
end # module DbAgile
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Core
|
|
3
|
+
module Schema
|
|
4
|
+
module Computations
|
|
5
|
+
module Filter
|
|
6
|
+
|
|
7
|
+
# Default filtering options
|
|
8
|
+
DEFAULT_OPTIONS = {}
|
|
9
|
+
|
|
10
|
+
# Computes set difference between schemas.
|
|
11
|
+
def filter(object, options, builder, &block)
|
|
12
|
+
unless object.composite?
|
|
13
|
+
raise ArgumentError, "Filter called on a part object!"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Make a deep filtered copy
|
|
17
|
+
keys = object.part_keys
|
|
18
|
+
copied = builder.send(object.builder_handler, *object.builder_args){|builder_object|
|
|
19
|
+
keys.each{|key|
|
|
20
|
+
sub_object = object[key]
|
|
21
|
+
if sub_object.composite?
|
|
22
|
+
filter(sub_object, options, builder, &block)
|
|
23
|
+
else
|
|
24
|
+
if block.call(sub_object)
|
|
25
|
+
builder_object.[]=(key, sub_object.dup)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
}
|
|
29
|
+
builder_object
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
copied
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end # module Filter
|
|
36
|
+
extend(Filter)
|
|
37
|
+
end # module Computations
|
|
38
|
+
end # module Schema
|
|
39
|
+
end # module Core
|
|
40
|
+
end # module DbAgile
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Core
|
|
3
|
+
module Schema
|
|
4
|
+
module Computations
|
|
5
|
+
module Merge
|
|
6
|
+
|
|
7
|
+
# Computes set difference between schemas.
|
|
8
|
+
def merge(left, right, builder, &block)
|
|
9
|
+
unless left.class == right.class
|
|
10
|
+
raise ArgumentError, "#{left.class} != #{right.class}"
|
|
11
|
+
end
|
|
12
|
+
unless left.composite?
|
|
13
|
+
raise ArgumentError, "Diff called on a part object!"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Computes key differences
|
|
17
|
+
left_keys, right_keys = left.part_keys(true), right.part_keys(true)
|
|
18
|
+
left_only = left_keys - right_keys
|
|
19
|
+
right_only = right_keys - left_keys
|
|
20
|
+
commons = left_keys & right_keys
|
|
21
|
+
|
|
22
|
+
mine = Schema::NO_CHANGE
|
|
23
|
+
builder.send(left.builder_handler, *left.builder_args){|builder_object|
|
|
24
|
+
left_only.each {|key|
|
|
25
|
+
mine = Schema::TO_ALTER
|
|
26
|
+
builder_object.[]=(key, left[key].dup, Schema::TO_DROP)
|
|
27
|
+
}
|
|
28
|
+
right_only.each{|key|
|
|
29
|
+
mine = Schema::TO_ALTER
|
|
30
|
+
builder_object.[]=(key, right[key].dup, Schema::TO_CREATE)
|
|
31
|
+
}
|
|
32
|
+
commons.each{|key|
|
|
33
|
+
on_left, on_right = left[key], right[key]
|
|
34
|
+
if on_left.composite?
|
|
35
|
+
recursed = merge(on_left, on_right, builder, &block).status
|
|
36
|
+
mine = Schema::TO_ALTER if recursed != Schema::NO_CHANGE
|
|
37
|
+
elsif on_left.look_same_as?(on_right)
|
|
38
|
+
builder_object.[]=(key, left[key].dup, Schema::NO_CHANGE)
|
|
39
|
+
elsif block
|
|
40
|
+
resolved = block.call(on_left, on_right)
|
|
41
|
+
if resolved
|
|
42
|
+
builder_object.[]=(key, resolved, Schema::TO_ALTER)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
}
|
|
46
|
+
builder_object.status = mine
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end # module Merge
|
|
51
|
+
extend(Merge)
|
|
52
|
+
end # module Computations
|
|
53
|
+
end # module Schema
|
|
54
|
+
end # module Core
|
|
55
|
+
end # module DbAgile
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Core
|
|
3
|
+
module Schema
|
|
4
|
+
module Computations
|
|
5
|
+
module Minus
|
|
6
|
+
|
|
7
|
+
# Computes set difference between schemas.
|
|
8
|
+
def minus(left, right, builder)
|
|
9
|
+
unless left.class == right.class
|
|
10
|
+
raise ArgumentError, "#{left.class} != #{right.class}"
|
|
11
|
+
end
|
|
12
|
+
unless left.composite?
|
|
13
|
+
raise ArgumentError, "Minus called on a part object!"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
result = builder.send(left.builder_handler, *left.builder_args){|builder_object|
|
|
17
|
+
left.part_keys.each{|name|
|
|
18
|
+
left_sub, right_sub = left[name], right[name]
|
|
19
|
+
if right_sub.nil?
|
|
20
|
+
# missing in right
|
|
21
|
+
builder_object[name] = left_sub.dup
|
|
22
|
+
elsif left_sub.composite?
|
|
23
|
+
# present in right, possibly the same
|
|
24
|
+
minus(left_sub, right_sub, builder)
|
|
25
|
+
elsif not(left_sub.look_same_as?(right_sub))
|
|
26
|
+
# present in right, conflicting
|
|
27
|
+
builder_object[name] = left_sub.dup
|
|
28
|
+
else
|
|
29
|
+
# present in right, same
|
|
30
|
+
# (following line otherwise, not counted by rcov)
|
|
31
|
+
1
|
|
32
|
+
end
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
result
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end # module Minus
|
|
40
|
+
extend(Minus)
|
|
41
|
+
end # module Computations
|
|
42
|
+
end # module Schema
|
|
43
|
+
end # module Core
|
|
44
|
+
end # module DbAgile
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Core
|
|
3
|
+
module Schema
|
|
4
|
+
module Computations
|
|
5
|
+
module Split
|
|
6
|
+
|
|
7
|
+
# Default split options
|
|
8
|
+
DEFAULT_OPTIONS = {}
|
|
9
|
+
|
|
10
|
+
# Computes set difference between schemas.
|
|
11
|
+
def split(schema, options, &block)
|
|
12
|
+
|
|
13
|
+
# Build the split hash
|
|
14
|
+
split_hash = Hash.new{|h,k| h[k] = []}
|
|
15
|
+
schema.visit{|object, parent|
|
|
16
|
+
if object.part?
|
|
17
|
+
kind = block.call(object)
|
|
18
|
+
split_hash[kind] << object
|
|
19
|
+
end
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Rebuild schemas now
|
|
23
|
+
schemas = {}
|
|
24
|
+
split_hash.keys.each{|kind|
|
|
25
|
+
split_proc = lambda{|obj| split_hash[kind].include?(obj)}
|
|
26
|
+
split_options = {:identifier => kind}
|
|
27
|
+
schemas[kind] = Schema::filter(schema, split_options, &split_proc)
|
|
28
|
+
}
|
|
29
|
+
schemas
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end # module Split
|
|
33
|
+
extend(Split)
|
|
34
|
+
end # module Computations
|
|
35
|
+
end # module Schema
|
|
36
|
+
end # module Core
|
|
37
|
+
end # module DbAgile
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Core
|
|
3
|
+
module Schema
|
|
4
|
+
class DatabaseSchema < Schema::Composite
|
|
5
|
+
include Enumerable
|
|
6
|
+
alias :each :visit
|
|
7
|
+
|
|
8
|
+
# Identifier of this schema
|
|
9
|
+
attr_accessor :schema_identifier
|
|
10
|
+
|
|
11
|
+
# Creates a schema instance
|
|
12
|
+
def initialize(schema_identifier = nil, parts = _default_parts)
|
|
13
|
+
@schema_identifier = schema_identifier
|
|
14
|
+
super(parts)
|
|
15
|
+
@insert_order = [:logical, :physical]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
############################################################################
|
|
20
|
+
### Private interface
|
|
21
|
+
############################################################################
|
|
22
|
+
|
|
23
|
+
# @see DbAgile::Core::Schema::Composite#_install_eigenclass_methods?
|
|
24
|
+
def _install_eigenclass_methods?
|
|
25
|
+
true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @see DbAgile::Core::Schema::Composite#_default_parts
|
|
29
|
+
def _default_parts
|
|
30
|
+
{:logical => Schema::Logical.new,
|
|
31
|
+
:physical => Schema::Physical.new}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Strips this schema
|
|
35
|
+
def _strip!
|
|
36
|
+
logical._strip!
|
|
37
|
+
self
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
############################################################################
|
|
41
|
+
### SchemaObject
|
|
42
|
+
############################################################################
|
|
43
|
+
|
|
44
|
+
# Returns an array with part dependencies
|
|
45
|
+
def dependencies(include_parent = false)
|
|
46
|
+
[]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Overrided to return self.
|
|
50
|
+
def schema
|
|
51
|
+
self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# @see DbAgile::Core::Schema::SchemaObject
|
|
55
|
+
def dup
|
|
56
|
+
DatabaseSchema.new(schema_identifier, _dup_parts)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
############################################################################
|
|
61
|
+
### IO
|
|
62
|
+
############################################################################
|
|
63
|
+
|
|
64
|
+
# Dumps the schema to YAML
|
|
65
|
+
def to_yaml(opts = {})
|
|
66
|
+
YAML::dump_stream({'logical' => logical}, {'physical' => physical})
|
|
67
|
+
end
|
|
68
|
+
alias :inspect :to_yaml
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# Returns a yaml string
|
|
72
|
+
def yaml_display(env,
|
|
73
|
+
options = {},
|
|
74
|
+
colors = DbAgile::Core::Schema::STATUS_TO_COLOR,
|
|
75
|
+
indent = 0)
|
|
76
|
+
env.display("---\nlogical:")
|
|
77
|
+
logical.yaml_display(env, options, colors, indent + 1)
|
|
78
|
+
env.display("\n---\nphysical:")
|
|
79
|
+
physical.yaml_display(env, options, colors, indent + 1)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
############################################################################
|
|
83
|
+
### Computations
|
|
84
|
+
############################################################################
|
|
85
|
+
|
|
86
|
+
# Applies schema checking and raises a SchemaSemanticsError if something is wrong.
|
|
87
|
+
def check!(raise_on_error = true)
|
|
88
|
+
errors = SchemaSemanticsError.new(self)
|
|
89
|
+
_semantics_check(SchemaSemanticsError, errors)
|
|
90
|
+
if raise_on_error and not(errors.empty?)
|
|
91
|
+
raise errors
|
|
92
|
+
else
|
|
93
|
+
errors
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Convenient method for <code>schema.check!(false).empty?</code>
|
|
98
|
+
def looks_valid?
|
|
99
|
+
check!(false).empty?
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Applies schema minus
|
|
103
|
+
def minus(other)
|
|
104
|
+
Schema::minus(self, other)
|
|
105
|
+
end
|
|
106
|
+
alias :- :minus
|
|
107
|
+
|
|
108
|
+
# Applies schema merging
|
|
109
|
+
def merge(other)
|
|
110
|
+
Schema::merge(self, other)
|
|
111
|
+
end
|
|
112
|
+
alias :+ :merge
|
|
113
|
+
|
|
114
|
+
# Applies schema filtering
|
|
115
|
+
def filter(options = {}, &filter_block)
|
|
116
|
+
Schema::filter(self, options, &filter_block)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Applies schema splitting
|
|
120
|
+
def split(options = {}, &split_block)
|
|
121
|
+
Schema::split(self, options, &split_block)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
end # class DatabaseSchema
|
|
125
|
+
end # module Schema
|
|
126
|
+
end # module Core
|
|
127
|
+
end # module DbAgile
|
|
128
|
+
require 'dbagile/core/schema/logical'
|
|
129
|
+
require 'dbagile/core/schema/physical'
|