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,211 @@
|
|
|
1
|
+
require 'dbagile/core/repository/yaml_methods'
|
|
2
|
+
require 'dbagile/core/repository/builder'
|
|
3
|
+
module DbAgile
|
|
4
|
+
module Core
|
|
5
|
+
class Repository
|
|
6
|
+
include Enumerable
|
|
7
|
+
extend Repository::YAMLClassMethods
|
|
8
|
+
include Repository::YAMLInstanceMethods
|
|
9
|
+
|
|
10
|
+
# Index file name
|
|
11
|
+
REPOSITORY_INDEX_FILE_NAME = "dbagile.idx"
|
|
12
|
+
|
|
13
|
+
# Path to the root path of the repository
|
|
14
|
+
attr_reader :root_path
|
|
15
|
+
|
|
16
|
+
# Repository version
|
|
17
|
+
attr_accessor :version
|
|
18
|
+
private :version=
|
|
19
|
+
|
|
20
|
+
# Databases as an array of Database instances
|
|
21
|
+
attr_reader :databases
|
|
22
|
+
|
|
23
|
+
# Current database (its name, i.e. a Symbol)
|
|
24
|
+
attr_accessor :current_db_name
|
|
25
|
+
|
|
26
|
+
#############################################################################################
|
|
27
|
+
### Initialization and parsing
|
|
28
|
+
#############################################################################################
|
|
29
|
+
|
|
30
|
+
# Creates a repository instance
|
|
31
|
+
def initialize(root_path, version = DbAgile::VERSION)
|
|
32
|
+
DbAgile::Robustness::valid_rw_directory!(root_path)
|
|
33
|
+
DbAgile::Robustness::valid_rw_file!(File.join(root_path, REPOSITORY_INDEX_FILE_NAME))
|
|
34
|
+
@root_path = root_path
|
|
35
|
+
@version = version
|
|
36
|
+
@databases = []
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
#############################################################################################
|
|
40
|
+
### File management
|
|
41
|
+
#############################################################################################
|
|
42
|
+
|
|
43
|
+
# Returns a friendly path to be printed to user
|
|
44
|
+
def friendly_path
|
|
45
|
+
DbAgile::FileSystemTools::friendly_path!(root_path)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Returns the path to the index file
|
|
49
|
+
def index_file
|
|
50
|
+
File.join(root_path, REPOSITORY_INDEX_FILE_NAME)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Returns a file resolver Proc instance
|
|
54
|
+
def file_resolver
|
|
55
|
+
@file_resolver ||= lambda{|f|
|
|
56
|
+
if f[0, 1] == '/'
|
|
57
|
+
f
|
|
58
|
+
else
|
|
59
|
+
File.join(File.expand_path(self.root_path), f)
|
|
60
|
+
end
|
|
61
|
+
}
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Resolves a file which could be relative to repository root path
|
|
65
|
+
def resolve_file(f)
|
|
66
|
+
file_resolve.call(f)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
#############################################################################################
|
|
70
|
+
### About databases
|
|
71
|
+
#############################################################################################
|
|
72
|
+
|
|
73
|
+
# Checks if at least one database exists
|
|
74
|
+
def empty?
|
|
75
|
+
databases.empty?
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Checks if a database exists
|
|
79
|
+
def has_database?(name)
|
|
80
|
+
!database(name).nil?
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Checks if a name/database is the current one
|
|
84
|
+
def current?(name_or_db)
|
|
85
|
+
case name_or_db
|
|
86
|
+
when Symbol
|
|
87
|
+
return nil unless has_database?(name_or_db)
|
|
88
|
+
self.current_db_name == name_or_db
|
|
89
|
+
when Core::Database
|
|
90
|
+
self.current_db_name == name_or_db.name
|
|
91
|
+
else
|
|
92
|
+
raise ArgumentError, "Symbol or Database expected, #{name_or_db.inspect} found."
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Yields the block with each database in turn
|
|
97
|
+
def each(*args, &block)
|
|
98
|
+
databases.each(*args, &block)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Returns a database by match. Returns nil if no such database
|
|
102
|
+
def database(match)
|
|
103
|
+
return match if match.kind_of?(::DbAgile::Core::Database)
|
|
104
|
+
databases.find{|c|
|
|
105
|
+
case match
|
|
106
|
+
when Symbol
|
|
107
|
+
c.name == match
|
|
108
|
+
when String
|
|
109
|
+
c.uri == match
|
|
110
|
+
when Regexp
|
|
111
|
+
match =~ c.uri
|
|
112
|
+
end
|
|
113
|
+
}
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Returns the current database
|
|
117
|
+
def current_database
|
|
118
|
+
database(current_db_name)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
#############################################################################################
|
|
122
|
+
### Updates
|
|
123
|
+
#############################################################################################
|
|
124
|
+
|
|
125
|
+
# Adds a database instance
|
|
126
|
+
def <<(db)
|
|
127
|
+
db.file_resolver = file_resolver
|
|
128
|
+
self.databases << db
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Removes a database from this repository
|
|
132
|
+
def remove(db)
|
|
133
|
+
db = self.database(db)
|
|
134
|
+
db.nil? ? nil : databases.delete(db)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
#############################################################################################
|
|
138
|
+
### Input/output
|
|
139
|
+
#############################################################################################
|
|
140
|
+
|
|
141
|
+
#
|
|
142
|
+
# Loads a repository from a root path
|
|
143
|
+
#
|
|
144
|
+
# @param [String] root_path path to a repository folder
|
|
145
|
+
# @raise IOError if required repository files do not exists or access is denied
|
|
146
|
+
# @raise DbAgile::CorruptedRepositoryError if anything goes wrong
|
|
147
|
+
#
|
|
148
|
+
def self.load(root_path)
|
|
149
|
+
# some checks first
|
|
150
|
+
DbAgile::Robustness::valid_rw_directory!(root_path)
|
|
151
|
+
index_file = File.join(root_path, REPOSITORY_INDEX_FILE_NAME)
|
|
152
|
+
msg = "Not a dbagile repository, missing or access denied on #{index_file}"
|
|
153
|
+
DbAgile::Robustness::valid_rw_file!(index_file, msg)
|
|
154
|
+
|
|
155
|
+
# loading
|
|
156
|
+
begin
|
|
157
|
+
from_yaml_file(index_file, root_path)
|
|
158
|
+
rescue StandardError => ex
|
|
159
|
+
msg = "Repository corruped: #{ex.message}"
|
|
160
|
+
raise DbAgile::CorruptedRepositoryError, msg, ex.backtrace
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
#
|
|
165
|
+
# Creates a fresh new repository somewhere
|
|
166
|
+
#
|
|
167
|
+
# @param [String] root_path path to an unexisting repository folder
|
|
168
|
+
# @return [Repository] the created repository instance
|
|
169
|
+
# @raise IOError is the repository already exists or cannot be created.
|
|
170
|
+
#
|
|
171
|
+
def self.create!(root_path)
|
|
172
|
+
DbAgile::Robustness::unexisting_directory!(root_path)
|
|
173
|
+
index_file = File.join(root_path, REPOSITORY_INDEX_FILE_NAME)
|
|
174
|
+
FileUtils.mkdir_p(root_path)
|
|
175
|
+
FileUtils.touch(index_file)
|
|
176
|
+
repo = Repository.new(root_path, DbAgile::VERSION)
|
|
177
|
+
repo.save!
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
#
|
|
181
|
+
# Saves the repository
|
|
182
|
+
#
|
|
183
|
+
# @return [Repository] the repository itself
|
|
184
|
+
# @raise IOError if something goes wrong when saving the repository
|
|
185
|
+
#
|
|
186
|
+
def save!
|
|
187
|
+
DbAgile::Robustness::valid_rw_file!(self.index_file)
|
|
188
|
+
flush(self.index_file)
|
|
189
|
+
self
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
#
|
|
193
|
+
# Flushes the repository into a given file or IO
|
|
194
|
+
#
|
|
195
|
+
# This method is not robust to dir/file errors and should be protected
|
|
196
|
+
# upstream.
|
|
197
|
+
#
|
|
198
|
+
def flush(output_file)
|
|
199
|
+
if output_file.kind_of?(::IO)
|
|
200
|
+
output_file << to_yaml
|
|
201
|
+
else
|
|
202
|
+
::File.open(output_file, 'w'){|io| flush(io)}
|
|
203
|
+
end
|
|
204
|
+
self
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
private :flush
|
|
208
|
+
private_class_method :from_yaml_file, :from_yaml
|
|
209
|
+
end # class Repository
|
|
210
|
+
end # module Core
|
|
211
|
+
end # module DbAgile
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Core
|
|
3
|
+
module Schema
|
|
4
|
+
class Builder
|
|
5
|
+
module Coercion
|
|
6
|
+
|
|
7
|
+
###############################################################################
|
|
8
|
+
### Tools
|
|
9
|
+
###############################################################################
|
|
10
|
+
def unsymbolize_hash(h)
|
|
11
|
+
unsymbolized = {}
|
|
12
|
+
h.each_pair{|k,v| unsymbolized[k.to_s] = v}
|
|
13
|
+
unsymbolized
|
|
14
|
+
end
|
|
15
|
+
module_function :unsymbolize_hash
|
|
16
|
+
|
|
17
|
+
# Unsymbolizes an array of names
|
|
18
|
+
def unsymbolize_array(array)
|
|
19
|
+
array.collect{|c| c.to_s}
|
|
20
|
+
end
|
|
21
|
+
module_function :unsymbolize_array
|
|
22
|
+
|
|
23
|
+
###############################################################################
|
|
24
|
+
### Validity
|
|
25
|
+
###############################################################################
|
|
26
|
+
|
|
27
|
+
# Raises a DbAgile::SchemaSyntaxError
|
|
28
|
+
def invalid!(msg)
|
|
29
|
+
raise DbAgile::SchemaSyntaxError, msg, caller
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Raises a coercion error
|
|
33
|
+
def coercion_error!(msg = "")
|
|
34
|
+
raise ::SByC::TypeSystem::CoercionError, msg, caller
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Asserts that all args are not nil
|
|
38
|
+
def not_nil!(*args)
|
|
39
|
+
if args.any?{|arg| arg.nil?}
|
|
40
|
+
coercion_error!
|
|
41
|
+
end
|
|
42
|
+
args
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Asserts that all args are not empty
|
|
46
|
+
def not_empty!(*args)
|
|
47
|
+
if args.any?{|arg| arg.nil? or arg.to_s.empty?}
|
|
48
|
+
coercion_error!
|
|
49
|
+
end
|
|
50
|
+
args
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Asserts that a hash is not nil and a hash
|
|
54
|
+
def not_nil_hash!(hash)
|
|
55
|
+
not_nil!(hash)
|
|
56
|
+
unless hash.kind_of?(Hash)
|
|
57
|
+
coercion_error!("Hash expected, #{hash.class} received")
|
|
58
|
+
end
|
|
59
|
+
hash
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def has_exactly_hash_keys!(hash, *keys)
|
|
63
|
+
not_nil!(hash)
|
|
64
|
+
unless keys.all?{|k| hash.key?(k)}
|
|
65
|
+
coercion_error!("Expected #{keys.inspect}, found #{hash.keys.inspect}")
|
|
66
|
+
end
|
|
67
|
+
hash
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Asserts that a name is valid
|
|
71
|
+
def valid_name!(name)
|
|
72
|
+
not_empty!(name)
|
|
73
|
+
unless [String, Symbol].include?(name.class)
|
|
74
|
+
coercion_error!
|
|
75
|
+
end
|
|
76
|
+
name
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
###############################################################################
|
|
80
|
+
### Data types (coercion error)
|
|
81
|
+
###############################################################################
|
|
82
|
+
|
|
83
|
+
# Coerces an array
|
|
84
|
+
def coerce_array(array, non_empty)
|
|
85
|
+
unless array.kind_of?(Array)
|
|
86
|
+
coercion_error!
|
|
87
|
+
end
|
|
88
|
+
if non_empty and array.empty?
|
|
89
|
+
coercion_error!
|
|
90
|
+
end
|
|
91
|
+
array
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Coerces a symbolized hash
|
|
95
|
+
def coerce_symbolized_hash(hash, recursive = false)
|
|
96
|
+
hash = not_nil_hash!(hash)
|
|
97
|
+
symbolized = {}
|
|
98
|
+
hash.each_pair{|k,v|
|
|
99
|
+
if recursive and v.kind_of?(Hash)
|
|
100
|
+
v = coerce_symbolized_hash(v)
|
|
101
|
+
end
|
|
102
|
+
symbolized[coerce_name(k)] = v
|
|
103
|
+
}
|
|
104
|
+
symbolized
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
###############################################################################
|
|
108
|
+
### Sub-concepts (coercion error)
|
|
109
|
+
###############################################################################
|
|
110
|
+
|
|
111
|
+
# Coerces a name
|
|
112
|
+
def coerce_name(name)
|
|
113
|
+
valid_name!(name)
|
|
114
|
+
name.to_s.to_sym
|
|
115
|
+
end
|
|
116
|
+
alias :coerce_relvar_name :coerce_name
|
|
117
|
+
alias :coerce_attribute_name :coerce_name
|
|
118
|
+
alias :coerce_constraint_name :coerce_name
|
|
119
|
+
alias :coerce_index_name :coerce_name
|
|
120
|
+
|
|
121
|
+
# Coerces a default value
|
|
122
|
+
def coerce_default_value(value, domain)
|
|
123
|
+
not_nil!(value, domain)
|
|
124
|
+
if value.kind_of?(Symbol)
|
|
125
|
+
case value
|
|
126
|
+
when :autonumber
|
|
127
|
+
:autonumber
|
|
128
|
+
else
|
|
129
|
+
invalid!("unknown default value handler #{value}")
|
|
130
|
+
end
|
|
131
|
+
else
|
|
132
|
+
SByC::TypeSystem::Ruby::coerce(value, domain)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Coerces a domain
|
|
137
|
+
def coerce_domain(domain)
|
|
138
|
+
not_nil!(domain)
|
|
139
|
+
domain = SByC::TypeSystem::Ruby::coerce(domain, Module)
|
|
140
|
+
unless DbAgile::RECOGNIZED_DOMAINS.include?(domain)
|
|
141
|
+
invalid!("unable to use #{domain} for attribute domain")
|
|
142
|
+
end
|
|
143
|
+
domain
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Coerces a mandatory value
|
|
147
|
+
def coerce_mandatory(mandatory)
|
|
148
|
+
mandatory.nil? ? true : SByC::TypeSystem::Ruby::coerce(mandatory, SByC::TypeSystem::Ruby::Boolean)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# Coerces attributes names
|
|
152
|
+
def coerce_attribute_names(defn, non_empty = true)
|
|
153
|
+
defn = coerce_array(defn, non_empty)
|
|
154
|
+
defn.collect{|c| coerce_name(c)}
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
###############################################################################
|
|
158
|
+
### Concepts (coercion error)
|
|
159
|
+
###############################################################################
|
|
160
|
+
|
|
161
|
+
# Coerces an attribute definition
|
|
162
|
+
def coerce_attribute_definition(defn)
|
|
163
|
+
defn = coerce_symbolized_hash(defn)
|
|
164
|
+
defn[:domain] = coerce_domain(defn[:domain])
|
|
165
|
+
if defn.key?(:default)
|
|
166
|
+
defn[:default] = coerce_default_value(defn[:default], defn[:domain])
|
|
167
|
+
end
|
|
168
|
+
defn[:mandatory] = coerce_mandatory(defn[:mandatory])
|
|
169
|
+
defn
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Coerces a constraint definition
|
|
173
|
+
def coerce_constraint_definition(defn)
|
|
174
|
+
defn = coerce_symbolized_hash(defn)
|
|
175
|
+
defn[:type] = coerce_name(defn[:type])
|
|
176
|
+
|
|
177
|
+
case type = defn[:type]
|
|
178
|
+
when :primary_key, :candidate_key
|
|
179
|
+
has_exactly_hash_keys!(defn, :type, :attributes)
|
|
180
|
+
defn[:attributes] = coerce_attribute_names(defn[:attributes], true)
|
|
181
|
+
when :foreign_key
|
|
182
|
+
if defn.key?(:key)
|
|
183
|
+
has_exactly_hash_keys!(defn, :type, :attributes, :references, :key)
|
|
184
|
+
defn[:attributes] = coerce_attribute_names(defn[:attributes], true)
|
|
185
|
+
defn[:references] = coerce_name(defn[:references])
|
|
186
|
+
defn[:key] = coerce_name(defn[:key])
|
|
187
|
+
else
|
|
188
|
+
has_exactly_hash_keys!(defn, :type, :attributes, :references)
|
|
189
|
+
defn[:attributes] = coerce_attribute_names(defn[:attributes], true)
|
|
190
|
+
defn[:references] = coerce_name(defn[:references])
|
|
191
|
+
end
|
|
192
|
+
else
|
|
193
|
+
invalid!("unknown constraint type #{type}")
|
|
194
|
+
end
|
|
195
|
+
defn
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Coerces an index definition
|
|
199
|
+
def coerce_index_definition(defn)
|
|
200
|
+
defn = coerce_symbolized_hash(defn)
|
|
201
|
+
defn[:relvar] = coerce_name(defn[:relvar])
|
|
202
|
+
defn[:attributes] = coerce_attribute_names(defn[:attributes], true)
|
|
203
|
+
defn
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
end # module Coercion
|
|
207
|
+
end # class Builder
|
|
208
|
+
end # module Schema
|
|
209
|
+
end # module Core
|
|
210
|
+
end # module DbAgile
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Core
|
|
3
|
+
module Schema
|
|
4
|
+
class Builder
|
|
5
|
+
module ConceptFactory
|
|
6
|
+
|
|
7
|
+
# Builds a logical schema
|
|
8
|
+
def build_schema(identifier)
|
|
9
|
+
Schema.new(identifier)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Builds a logical schema
|
|
13
|
+
def build_logical
|
|
14
|
+
Schema::Logical.new
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Builds a relvar
|
|
18
|
+
def build_relvar(name)
|
|
19
|
+
Schema::Logical::Relvar.new(name)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Builds a heading
|
|
23
|
+
def build_heading
|
|
24
|
+
Schema::Logical::Heading.new
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Builds an attribute
|
|
28
|
+
def build_attribute(name, definition)
|
|
29
|
+
Schema::Logical::Attribute.new(name, definition)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Builds a constraint collection
|
|
33
|
+
def build_constraints
|
|
34
|
+
Schema::Logical::Constraint.new
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Builds a constraint
|
|
38
|
+
def build_constraint(name, definition)
|
|
39
|
+
Schema::Logical::Constraint::factor(name, definition)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Builds a physical schema
|
|
43
|
+
def build_physical
|
|
44
|
+
Schema::Physical.new
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Builds an index collection
|
|
48
|
+
def build_indexes
|
|
49
|
+
Schema::Physical::Indexes.new
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Builds an index
|
|
53
|
+
def build_index(name, definition)
|
|
54
|
+
Schema::Physical::Index.new(name, definition)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end # module ConceptFactory
|
|
58
|
+
end # class Builder
|
|
59
|
+
end # module Schema
|
|
60
|
+
end # module Core
|
|
61
|
+
end # module DbAgile
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
require 'dbagile/core/schema/builder/coercion'
|
|
2
|
+
require 'dbagile/core/schema/builder/concept_factory'
|
|
3
|
+
module DbAgile
|
|
4
|
+
module Core
|
|
5
|
+
module Schema
|
|
6
|
+
class Builder
|
|
7
|
+
include Builder::Coercion
|
|
8
|
+
include Builder::ConceptFactory
|
|
9
|
+
|
|
10
|
+
# Call stack
|
|
11
|
+
attr_accessor :stack
|
|
12
|
+
|
|
13
|
+
# Creates a builder instance
|
|
14
|
+
def initialize(schema = Schema.new)
|
|
15
|
+
if schema
|
|
16
|
+
@stack = [ [:schema, schema ] ]
|
|
17
|
+
else
|
|
18
|
+
@stack = [ [:root, {}] ]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
############################################################################
|
|
23
|
+
### About result
|
|
24
|
+
############################################################################
|
|
25
|
+
|
|
26
|
+
# Dumps as a Schema instance
|
|
27
|
+
def _dump
|
|
28
|
+
if stack.last[0] == :schema
|
|
29
|
+
_peek(:schema)
|
|
30
|
+
else
|
|
31
|
+
_peek(:root)[:schema]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
############################################################################
|
|
36
|
+
### About the call stack
|
|
37
|
+
############################################################################
|
|
38
|
+
|
|
39
|
+
# Push a hash on the stack
|
|
40
|
+
def _push(section, object, &block)
|
|
41
|
+
stack.push([section, object])
|
|
42
|
+
if block
|
|
43
|
+
DbAgile::RubyTools::optional_args_block_call(block, [ object ])
|
|
44
|
+
_pop
|
|
45
|
+
end
|
|
46
|
+
object
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Pops a hash from the stack
|
|
50
|
+
def _pop
|
|
51
|
+
stack.pop
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Returns top value of the stack
|
|
55
|
+
def _peek(section = nil)
|
|
56
|
+
unless section.nil?
|
|
57
|
+
if stack.empty? or not(stack.last[0] == section)
|
|
58
|
+
invalid!("expected to be in #{section}, but was #{stack.last[0]}")
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
stack.last[1]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Applies natural rules according to current section
|
|
65
|
+
def _natural(hash)
|
|
66
|
+
case section = stack.last[0]
|
|
67
|
+
when :schema
|
|
68
|
+
coerce_symbolized_hash(hash).each_pair{|name, defn|
|
|
69
|
+
self.send(name, defn)
|
|
70
|
+
}
|
|
71
|
+
when :logical
|
|
72
|
+
coerce_symbolized_hash(hash).each_pair{|relvar_name, relvar_def|
|
|
73
|
+
relvar(relvar_name, relvar_def)
|
|
74
|
+
}
|
|
75
|
+
when :heading
|
|
76
|
+
coerce_symbolized_hash(hash).each_pair{|attr_name, attr_def|
|
|
77
|
+
attribute(attr_name, attr_def)
|
|
78
|
+
}
|
|
79
|
+
when :constraints
|
|
80
|
+
coerce_symbolized_hash(hash).each_pair{|c_name, c_def|
|
|
81
|
+
constraint(c_name, c_def)
|
|
82
|
+
}
|
|
83
|
+
when :physical
|
|
84
|
+
coerce_symbolized_hash(hash).each_pair{|name, defn|
|
|
85
|
+
self.send(name, defn)
|
|
86
|
+
}
|
|
87
|
+
when :indexes
|
|
88
|
+
coerce_symbolized_hash(hash).each_pair{|index_name, index_def|
|
|
89
|
+
index(index_name, index_def)
|
|
90
|
+
}
|
|
91
|
+
else
|
|
92
|
+
coerce_symbolized_hash(hash).each_pair{|k, v|
|
|
93
|
+
invalid!("No such section #{k}") unless self.respond_to?(k)
|
|
94
|
+
self.send(k, v)
|
|
95
|
+
}
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
############################################################################
|
|
100
|
+
### Logical sections
|
|
101
|
+
############################################################################
|
|
102
|
+
|
|
103
|
+
# Starts the logical section and yields
|
|
104
|
+
def database_schema(identifier = nil, hash = nil, &block)
|
|
105
|
+
block = lambda{ _natural(hash) } unless block
|
|
106
|
+
schema = (_peek(:root)[:schema] ||= build_schema(identifier))
|
|
107
|
+
_push(:schema, schema, &block)
|
|
108
|
+
end
|
|
109
|
+
alias :schema :database_schema
|
|
110
|
+
|
|
111
|
+
# Starts the logical section and yields
|
|
112
|
+
def logical(hash = nil, &block)
|
|
113
|
+
block = lambda{ _natural(hash) } unless block
|
|
114
|
+
logical = (_peek(:schema)[:logical] ||= build_logical)
|
|
115
|
+
_push(:logical, logical, &block)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Starts a relvar section
|
|
119
|
+
def relvar(name, hash = nil, &block)
|
|
120
|
+
block = lambda{ _natural(hash) } unless block
|
|
121
|
+
name = coerce_relvar_name(name)
|
|
122
|
+
relvar = (_peek(:logical)[name] ||= build_relvar(name))
|
|
123
|
+
_push(:relvar, relvar, &block)
|
|
124
|
+
rescue SByC::TypeSystem::CoercionError => ex
|
|
125
|
+
invalid!("Invalid relvar definition (#{name}): #{ex.message}")
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Starts a heading section
|
|
129
|
+
def heading(hash = nil, &block)
|
|
130
|
+
block = lambda{ _natural(hash) } unless block
|
|
131
|
+
heading = (_peek(:relvar)[:heading] ||= build_heading)
|
|
132
|
+
_push(:heading, heading, &block)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Starts a constraints section
|
|
136
|
+
def constraints(hash = nil, &block)
|
|
137
|
+
block = lambda{ _natural(hash) } unless block
|
|
138
|
+
cs = (_peek(:relvar)[:constraints] ||= build_constraints)
|
|
139
|
+
_push(:constraints, cs, &block)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
###
|
|
143
|
+
|
|
144
|
+
# Adds an attribute to current heading
|
|
145
|
+
def attribute(name, definition)
|
|
146
|
+
name, defn = coerce_attribute_name(name), coerce_attribute_definition(definition)
|
|
147
|
+
_peek(:heading)[name] = build_attribute(name, defn)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Adds a constraint to current relvar
|
|
151
|
+
def constraint(name, definition)
|
|
152
|
+
name, defn = coerce_constraint_name(name), coerce_constraint_definition(definition)
|
|
153
|
+
_peek(:constraints)[name] = build_constraint(name, defn)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
############################################################################
|
|
157
|
+
### Physical sections
|
|
158
|
+
############################################################################
|
|
159
|
+
|
|
160
|
+
# Starts the physical section and yields
|
|
161
|
+
def physical(hash = nil, &block)
|
|
162
|
+
block = lambda{ _natural(hash) } unless block
|
|
163
|
+
physical = (_peek(:schema)[:physical] ||= build_physical)
|
|
164
|
+
_push(:physical, physical, &block)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Starts the indexes section and yields
|
|
168
|
+
def indexes(hash = nil, &block)
|
|
169
|
+
block = lambda{ _natural(hash) } unless block
|
|
170
|
+
indexes = (_peek(:physical)[:indexes] ||= build_indexes)
|
|
171
|
+
_push(:indexes, indexes, &block)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
###
|
|
175
|
+
|
|
176
|
+
# Adds an index to indexes
|
|
177
|
+
def index(name, definition)
|
|
178
|
+
name, defn = coerce_index_name(name), coerce_index_definition(definition)
|
|
179
|
+
_peek(:indexes)[name] = build_index(name, defn)
|
|
180
|
+
rescue SByC::TypeSystem::CoercionError => ex
|
|
181
|
+
invalid!("Invalid index definition (#{name}, #{definition.inspect}): #{ex.message}")
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
end # class Builder
|
|
185
|
+
end # module Schema
|
|
186
|
+
end # module Core
|
|
187
|
+
end # module DbAgile
|