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,208 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
class Environment
|
|
3
|
+
#
|
|
4
|
+
# Environment's interactions contract.
|
|
5
|
+
#
|
|
6
|
+
module Interactions
|
|
7
|
+
|
|
8
|
+
# The buffer to use for displaying messages
|
|
9
|
+
attr_reader :message_buffer
|
|
10
|
+
|
|
11
|
+
# The buffer to use for asking questions
|
|
12
|
+
attr_reader :asking_buffer
|
|
13
|
+
|
|
14
|
+
##############################################################################
|
|
15
|
+
### Robustness
|
|
16
|
+
##############################################################################
|
|
17
|
+
|
|
18
|
+
#
|
|
19
|
+
# Asserts that the interactive mode is enabled. Raises a
|
|
20
|
+
# InteractiveModeRequiredError otherwise.
|
|
21
|
+
#
|
|
22
|
+
def interactive!(msg = nil)
|
|
23
|
+
unless interactive?
|
|
24
|
+
msg = "The interactive mode is required, but disabled."
|
|
25
|
+
raise InteractiveModeRequiredError, msg
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
##############################################################################
|
|
30
|
+
### Configuration
|
|
31
|
+
##############################################################################
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
# Returns true if the environment is interactive, false
|
|
35
|
+
# otherwise
|
|
36
|
+
#
|
|
37
|
+
def interactive?
|
|
38
|
+
@interactive
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
#
|
|
42
|
+
# Sets the interactive mode.
|
|
43
|
+
#
|
|
44
|
+
# In all cases, the highline instance for interaction is reset
|
|
45
|
+
# to nil.
|
|
46
|
+
#
|
|
47
|
+
def interactive=(value)
|
|
48
|
+
@interactive = value
|
|
49
|
+
@interaction_highline = nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
#
|
|
53
|
+
# Sets the message/output buffer to use for interactions.
|
|
54
|
+
#
|
|
55
|
+
# In all cases, the highline instance for interaction is reset
|
|
56
|
+
# to nil.
|
|
57
|
+
#
|
|
58
|
+
def message_buffer=(buffer)
|
|
59
|
+
@message_buffer = buffer
|
|
60
|
+
@interaction_highline = nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
#
|
|
64
|
+
# Sets the asking/input buffer to use for interactions.
|
|
65
|
+
#
|
|
66
|
+
# In all cases, the highline instance for interaction is reset
|
|
67
|
+
# to nil.
|
|
68
|
+
#
|
|
69
|
+
def asking_buffer=(buffer)
|
|
70
|
+
@asking_buffer = buffer
|
|
71
|
+
@interaction_highline = nil
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
##############################################################################
|
|
75
|
+
### HighLine delegation
|
|
76
|
+
##############################################################################
|
|
77
|
+
|
|
78
|
+
#
|
|
79
|
+
# Returns an instance of HighLine for interactions, creating it
|
|
80
|
+
# if required.
|
|
81
|
+
#
|
|
82
|
+
# This method factors an HighLine instance even if interactive
|
|
83
|
+
# is set to false. Checking the interactive? flag should be made
|
|
84
|
+
# upstream.
|
|
85
|
+
#
|
|
86
|
+
def interaction_highline
|
|
87
|
+
if @interaction_highline.nil?
|
|
88
|
+
in_buffer = asking_buffer || input_buffer
|
|
89
|
+
out_buffer = message_buffer || output_buffer
|
|
90
|
+
@interaction_highline = HighLine.new(in_buffer, out_buffer)
|
|
91
|
+
end
|
|
92
|
+
@interaction_highline
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
#
|
|
96
|
+
# Asks something to the user/oracle and returns the result.
|
|
97
|
+
#
|
|
98
|
+
# This method is provided when something needs to be asked to the user.
|
|
99
|
+
# It simply returns non_interactive_value if the interaction flag is set
|
|
100
|
+
# to false. Otherwise, it delegates the call to the interaction highline
|
|
101
|
+
# instance.
|
|
102
|
+
#
|
|
103
|
+
# @param [String] question a prompt for the question
|
|
104
|
+
# @param [Proc] continuation a optional continuation procedure
|
|
105
|
+
# @param [...] non_interactive_value value to return in non-interactive
|
|
106
|
+
# mode
|
|
107
|
+
# @return [...] non_interactive_value in non-interactive mode, the result
|
|
108
|
+
# of continuation proc otherwise.
|
|
109
|
+
#
|
|
110
|
+
def ask(question, answer_type = String, non_interactive_value = nil, &continuation)
|
|
111
|
+
if interactive?
|
|
112
|
+
interaction_highline.ask(question, answer_type, &continuation)
|
|
113
|
+
else
|
|
114
|
+
nil
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
#
|
|
119
|
+
# Same specification as ask, but immediately raises an
|
|
120
|
+
# InteractiveModeRequiredError if the interactive mode is not set!
|
|
121
|
+
#
|
|
122
|
+
def ask!(question, answer_type = String, &continuation)
|
|
123
|
+
interactive!
|
|
124
|
+
ask(question, answer_type, nil, &continuation)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
#
|
|
128
|
+
# Prints an information message on the appropriate buffer. An optional
|
|
129
|
+
# color may be provided if the environment supports colors.
|
|
130
|
+
#
|
|
131
|
+
# Does nothing when interactive mode is disabled. Delegates the call
|
|
132
|
+
# to highline otherwise.
|
|
133
|
+
#
|
|
134
|
+
# The something argument is expected to be a String. Use display to
|
|
135
|
+
# show complex objects, Enumerable in particular
|
|
136
|
+
#
|
|
137
|
+
# @param [String] something a message to print
|
|
138
|
+
# @param [Symbol] an optional color
|
|
139
|
+
# @return [void]
|
|
140
|
+
#
|
|
141
|
+
def say(something, color = nil)
|
|
142
|
+
if interactive?
|
|
143
|
+
h = interaction_highline
|
|
144
|
+
color.nil? ? h.say(something) : h.say(h.color(something, color))
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
#
|
|
149
|
+
# Displays something on the message buffer.
|
|
150
|
+
#
|
|
151
|
+
# Does nothing when interactive mode is disabled. Delegates the call
|
|
152
|
+
# to highline otherwise.
|
|
153
|
+
#
|
|
154
|
+
# @param [Object] something to write on environment output
|
|
155
|
+
# @return [void]
|
|
156
|
+
#
|
|
157
|
+
def display(something, color = nil)
|
|
158
|
+
if interactive?
|
|
159
|
+
if something.kind_of?(String)
|
|
160
|
+
say(something, color)
|
|
161
|
+
elsif something.kind_of?(Enumerable)
|
|
162
|
+
something.each{|v| display(v, color)}
|
|
163
|
+
else
|
|
164
|
+
display(something.to_s, color)
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
##############################################################################
|
|
170
|
+
### Console
|
|
171
|
+
##############################################################################
|
|
172
|
+
|
|
173
|
+
#
|
|
174
|
+
# When interaction mode is set, colorizes a string with highline.
|
|
175
|
+
# Simply returns str otherwise.
|
|
176
|
+
#
|
|
177
|
+
def color(str, color)
|
|
178
|
+
interactive? ? interaction_highline.color(str, color) : str
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
#
|
|
182
|
+
# Forces the console width.
|
|
183
|
+
#
|
|
184
|
+
# When a width is set, it will always be returned by console_width, bypassing
|
|
185
|
+
# any attempt to use highline to infer it.
|
|
186
|
+
#
|
|
187
|
+
def console_width=(width)
|
|
188
|
+
@console_width = width
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
#
|
|
192
|
+
# Returns width of the console. Width set with console_width= is returned in
|
|
193
|
+
# priority. Otherwise, return highline's output_cols in interactive mode.
|
|
194
|
+
# Returns 80 in all other cases.
|
|
195
|
+
#
|
|
196
|
+
def console_width
|
|
197
|
+
@console_width ||= infer_console_width
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
# Tries to infer the console width
|
|
201
|
+
def infer_console_width
|
|
202
|
+
interactive? ? interaction_highline.output_cols-3 : 80
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
private :infer_console_width
|
|
206
|
+
end # module Interactions
|
|
207
|
+
end # class Environment
|
|
208
|
+
end # module DbAgile
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
class Environment
|
|
3
|
+
module OnError
|
|
4
|
+
|
|
5
|
+
# Show backtrace on errors?
|
|
6
|
+
attr_writer :show_backtrace
|
|
7
|
+
|
|
8
|
+
# Shows the backtrace when an error occurs?
|
|
9
|
+
def show_backtrace?
|
|
10
|
+
@show_backtrace
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
#
|
|
14
|
+
# Handles an error that occured during command execution.
|
|
15
|
+
#
|
|
16
|
+
# @param [Exception] error the error that was raised
|
|
17
|
+
# @return nil to continue execution, an error to raise otherwise
|
|
18
|
+
#
|
|
19
|
+
def on_error(command, error)
|
|
20
|
+
case error
|
|
21
|
+
when SystemExit
|
|
22
|
+
when OptionParser::ParseError
|
|
23
|
+
say(error.message, :red)
|
|
24
|
+
display(command.options.to_s)
|
|
25
|
+
when Sequel::Error, IOError
|
|
26
|
+
say(error.message, :red)
|
|
27
|
+
when DbAgile::SchemaSemanticsError
|
|
28
|
+
say(error.message(true), :red)
|
|
29
|
+
when DbAgile::InternalError
|
|
30
|
+
say("DbAgile encountered an internal error.\n Please replay with dba --backtrace and report the error!", :red)
|
|
31
|
+
say(error.message, :red)
|
|
32
|
+
when DbAgile::Error
|
|
33
|
+
say(error.message, :red)
|
|
34
|
+
when Interrupt
|
|
35
|
+
say("Command interrupted by user", :magenta)
|
|
36
|
+
else
|
|
37
|
+
say("ERROR (#{error.class}): #{error.message}", :red)
|
|
38
|
+
end
|
|
39
|
+
if show_backtrace?
|
|
40
|
+
say(error.backtrace.join("\n"))
|
|
41
|
+
end
|
|
42
|
+
error
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end # module OnError
|
|
46
|
+
end # class Environment
|
|
47
|
+
end # module DbAgile
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
class Environment
|
|
3
|
+
module Repository
|
|
4
|
+
|
|
5
|
+
#
|
|
6
|
+
# Checks if the repository exists or should be created.
|
|
7
|
+
#
|
|
8
|
+
# If the repository is currently loaded, this method returns true.
|
|
9
|
+
# Otherwise it returns true if the repository path exists. Note that
|
|
10
|
+
# repository consistency itself (index file) is not checked. You have
|
|
11
|
+
# to load it and catch exception to have a finer grained info.
|
|
12
|
+
#
|
|
13
|
+
def repository_exists?
|
|
14
|
+
return true if @repository
|
|
15
|
+
File.exists?(repository_path)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
#
|
|
19
|
+
# Returns a friendly path for the repository, to display to the user.
|
|
20
|
+
# If a repository is loaded, the call is delegated. Otherwise, the
|
|
21
|
+
# repository_path is displayed, without attempting to load repository.
|
|
22
|
+
#
|
|
23
|
+
def friendly_repository_path
|
|
24
|
+
if @repository
|
|
25
|
+
@repository.friendly_path
|
|
26
|
+
else
|
|
27
|
+
DbAgile::FileSystemTools::friendly_path!(repository_path)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
#
|
|
32
|
+
# Returns path to the repository
|
|
33
|
+
#
|
|
34
|
+
def repository_path
|
|
35
|
+
@repository_path
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
#
|
|
39
|
+
# Sets the path to the .dbagile file
|
|
40
|
+
#
|
|
41
|
+
def repository_path=(path)
|
|
42
|
+
@repository = nil
|
|
43
|
+
@repository_path = path
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
#
|
|
47
|
+
# Ensures that repository is loaded and returns the Repository instance.
|
|
48
|
+
#
|
|
49
|
+
# ATTENTION: the Repository instance is kept in cache. It will not be
|
|
50
|
+
# synchronized with modifications of the underlying files made by another
|
|
51
|
+
# process/thread.
|
|
52
|
+
#
|
|
53
|
+
# @raise IOError if the repository does not exists or something goes wrong
|
|
54
|
+
# with repository dir/files
|
|
55
|
+
# @raise CorruptedRepositoryError if something goes wrong when parsing the
|
|
56
|
+
# repository index file
|
|
57
|
+
# @return [Repository] repository instance
|
|
58
|
+
# @see DbAgile::Core::Repository::load
|
|
59
|
+
#
|
|
60
|
+
def repository
|
|
61
|
+
@repository ||= DbAgile::Core::Repository::load(repository_path)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
#
|
|
65
|
+
# Yields the block with each database in turn
|
|
66
|
+
#
|
|
67
|
+
# As this method is a wrapper on repository, it shares the specification
|
|
68
|
+
# about exceptions.
|
|
69
|
+
#
|
|
70
|
+
# @raise ArgumentError if no block is provided
|
|
71
|
+
#
|
|
72
|
+
def each_database(&block)
|
|
73
|
+
raise ArgumentError, "Missing block" unless block_given?
|
|
74
|
+
repository.each(&block)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
#
|
|
78
|
+
# Yields the block with the Repository instance (loaded using repository)
|
|
79
|
+
#
|
|
80
|
+
# As this method is a wrapper on repository, it shares the specification
|
|
81
|
+
# about exceptions.
|
|
82
|
+
#
|
|
83
|
+
# @return [...] result of the block execution
|
|
84
|
+
# @raise ArgumentError if no block is provided
|
|
85
|
+
#
|
|
86
|
+
def with_repository
|
|
87
|
+
raise ArgumentError, "Missing block" unless block_given?
|
|
88
|
+
yield(repository)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
#
|
|
92
|
+
# Yields the block with a Database instance found by name in the
|
|
93
|
+
# repository
|
|
94
|
+
#
|
|
95
|
+
# As this method relies on repository, it shares its exception contract.
|
|
96
|
+
#
|
|
97
|
+
# @raise ArgumentError if no block is provided
|
|
98
|
+
# @raise NoSuchDatabaseError if the database cannot be found.
|
|
99
|
+
# @return block execution result
|
|
100
|
+
#
|
|
101
|
+
def with_database(name)
|
|
102
|
+
raise ArgumentError, "Missing block" unless block_given?
|
|
103
|
+
db = repository.database(name)
|
|
104
|
+
raise NoSuchDatabaseError if db.nil?
|
|
105
|
+
yield(db)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
#
|
|
109
|
+
# Yields the block with the Database instance for the current one
|
|
110
|
+
# in repository.
|
|
111
|
+
#
|
|
112
|
+
# As this method relies on repository, it shares its exception contract.
|
|
113
|
+
#
|
|
114
|
+
# @raise ArgumentError if no block is provided
|
|
115
|
+
# @raise NoDefaultDatabaseError if the database cannot be found.
|
|
116
|
+
# @return block execution result
|
|
117
|
+
#
|
|
118
|
+
def with_current_database
|
|
119
|
+
raise ArgumentError, "Missing block" unless block_given?
|
|
120
|
+
db = repository.current_database
|
|
121
|
+
raise NoDefaultDatabaseError if db.nil?
|
|
122
|
+
yield(db)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
#
|
|
126
|
+
# Yields the block with a connection on a given database; diconnect after that.
|
|
127
|
+
#
|
|
128
|
+
# As this method relies on repository, it shares its exception contract.
|
|
129
|
+
#
|
|
130
|
+
# @raise ArgumentError if no block is provided
|
|
131
|
+
# @raise NoSuchDatabaseError if the database cannot be found.
|
|
132
|
+
# @return block execution result
|
|
133
|
+
#
|
|
134
|
+
def with_connection(db, conn_options = {}, &block)
|
|
135
|
+
case db
|
|
136
|
+
when Symbol
|
|
137
|
+
db = repository.database(db)
|
|
138
|
+
when DbAgile::Core::Database
|
|
139
|
+
else
|
|
140
|
+
raise ArgumentError, "Invalid database name #{db}"
|
|
141
|
+
end
|
|
142
|
+
raise NoSuchDatabaseError if db.nil?
|
|
143
|
+
db.with_connection(&block)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
#
|
|
147
|
+
# Yields the block with a connection on the current database.
|
|
148
|
+
#
|
|
149
|
+
# Same contract as with_connection, expect for parameters.
|
|
150
|
+
#
|
|
151
|
+
# @raise NoDefaultDatabaseError if the database cannot be found.
|
|
152
|
+
#
|
|
153
|
+
def with_current_connection(conn_options = {}, &block)
|
|
154
|
+
with_current_database{|db|
|
|
155
|
+
with_connection(db, conn_options, &block)
|
|
156
|
+
}
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
end # module Repository
|
|
160
|
+
end # class Environment
|
|
161
|
+
end # module DbAgile
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
class Environment
|
|
3
|
+
module Testing
|
|
4
|
+
|
|
5
|
+
# Returns the output buffer as a string
|
|
6
|
+
def output_buffer_str
|
|
7
|
+
if self.output_buffer.kind_of?(StringIO)
|
|
8
|
+
output_buffer.string
|
|
9
|
+
else
|
|
10
|
+
raise DbAgile::AssumptionFailedError, "StringIO expected as output buffer"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
#
|
|
15
|
+
# Returns true if the current output buffer matches a regular expression
|
|
16
|
+
#
|
|
17
|
+
def has_flushed?(rx)
|
|
18
|
+
(self.output_buffer_str =~ rx) ? true : false
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end # module Testing
|
|
22
|
+
end # class Environment
|
|
23
|
+
end # module DbAgile
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
require 'dbagile/environment/robustness'
|
|
2
|
+
require 'dbagile/environment/on_error'
|
|
3
|
+
require 'dbagile/environment/buffering'
|
|
4
|
+
require 'dbagile/environment/interactions'
|
|
5
|
+
require 'dbagile/environment/repository'
|
|
6
|
+
require 'dbagile/environment/delegator'
|
|
7
|
+
module DbAgile
|
|
8
|
+
#
|
|
9
|
+
# Defines the contract to be an environment for dbagile.
|
|
10
|
+
#
|
|
11
|
+
class Environment
|
|
12
|
+
include DbAgile::Environment::OnError
|
|
13
|
+
include DbAgile::Environment::Buffering
|
|
14
|
+
include DbAgile::Environment::Interactions
|
|
15
|
+
include DbAgile::Environment::Repository
|
|
16
|
+
|
|
17
|
+
#
|
|
18
|
+
# Installs the testing methods, StringIO on output buffers then
|
|
19
|
+
# returns self
|
|
20
|
+
#
|
|
21
|
+
def with_testing_methods!(interactive = true)
|
|
22
|
+
require 'dbagile/environment/testing'
|
|
23
|
+
extend(DbAgile::Environment::Testing)
|
|
24
|
+
self.output_buffer = StringIO.new
|
|
25
|
+
self.message_buffer = StringIO.new
|
|
26
|
+
self.interactive = interactive
|
|
27
|
+
self
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
#
|
|
31
|
+
# Creates a default Environment instance with following options:
|
|
32
|
+
#
|
|
33
|
+
# - repository_path -> what Environment::default_repository_path returns
|
|
34
|
+
# - input_buffer -> STDIN
|
|
35
|
+
# - output_buffer -> STDOUT
|
|
36
|
+
# - interactive? -> true
|
|
37
|
+
# - asking_buffer -> STDIN
|
|
38
|
+
# - message_buffer -> STDERR
|
|
39
|
+
# - show_backtrace -> false
|
|
40
|
+
#
|
|
41
|
+
def initialize
|
|
42
|
+
@repository_path = Environment::default_repository_path
|
|
43
|
+
@input_buffer = STDIN
|
|
44
|
+
@output_buffer = STDOUT
|
|
45
|
+
@interactive = true
|
|
46
|
+
@asking_buffer = STDIN
|
|
47
|
+
@message_buffer = STDERR
|
|
48
|
+
@show_backtrace = false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
#
|
|
52
|
+
# Duplicates the environment but removes any cached value (repository
|
|
53
|
+
# and so on)
|
|
54
|
+
#
|
|
55
|
+
def dup
|
|
56
|
+
env = Environment.new
|
|
57
|
+
env.repository_path = self.repository_path
|
|
58
|
+
env.input_buffer = self.input_buffer
|
|
59
|
+
env.output_buffer = self.output_buffer
|
|
60
|
+
env.interactive = self.interactive?
|
|
61
|
+
env.asking_buffer = self.asking_buffer
|
|
62
|
+
env.message_buffer = self.message_buffer
|
|
63
|
+
env.show_backtrace = self.show_backtrace?
|
|
64
|
+
env
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
#
|
|
68
|
+
# Returns the default path to use for a repository.
|
|
69
|
+
#
|
|
70
|
+
# The algorithm implemented tries to locate a repository folder in the
|
|
71
|
+
# following order:
|
|
72
|
+
#
|
|
73
|
+
# - dbagile.idx file in the current directory -> it's parent folder
|
|
74
|
+
# - dbagile folder in the current directory -> ./dbagile
|
|
75
|
+
# - .dbagile folder in user's home -> ~/.dbagile
|
|
76
|
+
#
|
|
77
|
+
# If none of those files exists, ~/.dbagile is returned
|
|
78
|
+
#
|
|
79
|
+
def self.default_repository_path
|
|
80
|
+
if File.exists?("./dbagile.idx")
|
|
81
|
+
"."
|
|
82
|
+
elsif File.exists?("dbagile")
|
|
83
|
+
"dbagile"
|
|
84
|
+
else
|
|
85
|
+
File.join(ENV['HOME'], '.dbagile')
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
#
|
|
90
|
+
# Returns the default environment to use.
|
|
91
|
+
#
|
|
92
|
+
# The algorithm implemented tries to locate a repository folder in the
|
|
93
|
+
# following order:
|
|
94
|
+
#
|
|
95
|
+
# - dbagile.idx file in the current directory -> it's parent folder
|
|
96
|
+
# - dbagile folder in the current directory -> ./dbagile
|
|
97
|
+
# - .dbagile folder in user's home -> ~/.dbagile
|
|
98
|
+
#
|
|
99
|
+
# If none of those files exists, a default environment will be created
|
|
100
|
+
# mapping to an unexisting repository folder in ~/.dbagile
|
|
101
|
+
#
|
|
102
|
+
# By default, the repository is not loaded at all, and errors can therefore
|
|
103
|
+
# occur later, when the repository will be first accessed. Set
|
|
104
|
+
# load_repository to true to force immediate load.
|
|
105
|
+
#
|
|
106
|
+
def self.default(load_repository = false)
|
|
107
|
+
env = Environment.new
|
|
108
|
+
if load_repository
|
|
109
|
+
env.repository
|
|
110
|
+
end
|
|
111
|
+
env
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
#
|
|
115
|
+
# Convenient method for Environment::default(true)
|
|
116
|
+
#
|
|
117
|
+
def self.default!
|
|
118
|
+
Environment::default(true)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end # class Environment
|
|
122
|
+
end # module DbAgile
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
|
|
3
|
+
# Raised when a database name is not valid
|
|
4
|
+
class InvalidDatabaseName < DbAgile::Error; end
|
|
5
|
+
|
|
6
|
+
# Raised when a database URI is not valid
|
|
7
|
+
class InvalidDatabaseUri < DbAgile::Error; end
|
|
8
|
+
|
|
9
|
+
# Raised when a command does not exists (dba command line tool)
|
|
10
|
+
class NoSuchCommandError < DbAgile::Error; end
|
|
11
|
+
|
|
12
|
+
# Raised when the repository seems corrupted
|
|
13
|
+
class CorruptedRepositoryError < DbAgile::Error; end
|
|
14
|
+
|
|
15
|
+
# Raised when a database cannot be found
|
|
16
|
+
class NoSuchDatabaseError < DbAgile::Error; end
|
|
17
|
+
|
|
18
|
+
# Raised when a database name is already used (on add)
|
|
19
|
+
class DatabaseNameConflictError < DbAgile::Error; end
|
|
20
|
+
|
|
21
|
+
# Raised when no default database is set
|
|
22
|
+
class NoDefaultDatabaseError < DbAgile::Error; end
|
|
23
|
+
|
|
24
|
+
# Raised when input parsing of data fails for some reason
|
|
25
|
+
class InvalidFormatError < DbAgile::Error; end
|
|
26
|
+
|
|
27
|
+
# Raised when usage of schema files fails because they are not installed
|
|
28
|
+
class NoSchemaFilesError < DbAgile::Error; end
|
|
29
|
+
|
|
30
|
+
end # module DbAgile
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module IO
|
|
3
|
+
module CSV
|
|
4
|
+
extend IO::TypeSafe
|
|
5
|
+
|
|
6
|
+
# Normalizes CSV options from DBAgile options
|
|
7
|
+
def normalize_options(options)
|
|
8
|
+
if options[:type_system]
|
|
9
|
+
options[:headers] = true unless options.key?(:headers)
|
|
10
|
+
options[:quote_char] = "'" unless options.key?(:quote_char)
|
|
11
|
+
options[:force_quotes] = true unless options.key?(:force_quotes)
|
|
12
|
+
end
|
|
13
|
+
if options[:headers]
|
|
14
|
+
options[:write_headers] = true
|
|
15
|
+
options[:return_headers] = true
|
|
16
|
+
end
|
|
17
|
+
options
|
|
18
|
+
end
|
|
19
|
+
module_function :normalize_options
|
|
20
|
+
|
|
21
|
+
# Makes the CSV require, depending on Ruby version
|
|
22
|
+
def build_csv_instance(io, options)
|
|
23
|
+
if RUBY_VERSION >= "1.9.0"
|
|
24
|
+
require 'csv'
|
|
25
|
+
options = normalize_options(options)
|
|
26
|
+
csv_options = options.dup.delete_if{|key,value| !::CSV::DEFAULT_OPTIONS.key?(key)}
|
|
27
|
+
[::CSV.new(io, csv_options), options]
|
|
28
|
+
else
|
|
29
|
+
require 'faster_csv'
|
|
30
|
+
options = normalize_options(options)
|
|
31
|
+
csv_options = options.dup.delete_if{|key,value| !FasterCSV::DEFAULT_OPTIONS.key?(key)}
|
|
32
|
+
[FasterCSV.new(io, csv_options), options]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
module_function :build_csv_instance
|
|
36
|
+
|
|
37
|
+
#
|
|
38
|
+
# Outputs some data as a CSV string.
|
|
39
|
+
#
|
|
40
|
+
# @return [...] the buffer itself
|
|
41
|
+
#
|
|
42
|
+
def to_csv(data, columns, buffer = "", options = {})
|
|
43
|
+
# Creates a CSV outputter with options
|
|
44
|
+
csv, options = build_csv_instance(buffer, options)
|
|
45
|
+
|
|
46
|
+
# Write header if required
|
|
47
|
+
if options[:headers]
|
|
48
|
+
if ts = options[:type_system]
|
|
49
|
+
csv << columns.collect{|c| ts.to_literal(c)}
|
|
50
|
+
else
|
|
51
|
+
csv << columns
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Write tuples now
|
|
56
|
+
with_type_safe_relation(data, options) do |tuple|
|
|
57
|
+
csv << columns.collect{|c| tuple[c]}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Return buffer
|
|
61
|
+
buffer
|
|
62
|
+
end
|
|
63
|
+
module_function :to_csv
|
|
64
|
+
|
|
65
|
+
#
|
|
66
|
+
# If a block is given yields it with each tuple that can be loaded from
|
|
67
|
+
# the CSV input and returns nil. Otherwise, reads the CSV input and returns
|
|
68
|
+
# an array of tuples.
|
|
69
|
+
#
|
|
70
|
+
def from_csv(input, options = {})
|
|
71
|
+
# Creates a CSV inputer with options
|
|
72
|
+
csv, options = build_csv_instance(input, options)
|
|
73
|
+
if ts = options[:type_system]
|
|
74
|
+
converter = lambda{|field| ts.parse_literal(field)}
|
|
75
|
+
csv.header_convert(&converter)
|
|
76
|
+
csv.convert(&converter)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Load data now
|
|
80
|
+
ts = options[:type_system]
|
|
81
|
+
if block_given?
|
|
82
|
+
csv.each do |row|
|
|
83
|
+
next if row.header_row?
|
|
84
|
+
yield(row.to_hash)
|
|
85
|
+
end
|
|
86
|
+
else
|
|
87
|
+
tuples = []
|
|
88
|
+
csv.each do |row|
|
|
89
|
+
next if row.header_row?
|
|
90
|
+
tuples << row.to_hash
|
|
91
|
+
end
|
|
92
|
+
tuples
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
module_function :from_csv
|
|
96
|
+
|
|
97
|
+
end # module CSVTools
|
|
98
|
+
end # module IO
|
|
99
|
+
end # module DbAgile
|