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,27 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Restful
|
|
3
|
+
class Middleware
|
|
4
|
+
module Get
|
|
5
|
+
|
|
6
|
+
# Implements GET access of the restful interface
|
|
7
|
+
def get(env)
|
|
8
|
+
request = Rack::Request.new(env)
|
|
9
|
+
decode(env) do |connection, table, format|
|
|
10
|
+
# Compute the projection on query string
|
|
11
|
+
heading = connection.heading(table)
|
|
12
|
+
projection = params_to_tuple(request.GET, heading)
|
|
13
|
+
|
|
14
|
+
# Retrieve dataset
|
|
15
|
+
columns = connection.column_names(table)
|
|
16
|
+
dataset = connection.dataset(table, projection)
|
|
17
|
+
|
|
18
|
+
# Make output now
|
|
19
|
+
format ||= :json
|
|
20
|
+
[format, to_xxx_enumerable(format, dataset, columns)]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end # module Get
|
|
25
|
+
end # class Middleware
|
|
26
|
+
end # module Restful
|
|
27
|
+
end # module Facts
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Restful
|
|
3
|
+
class Middleware
|
|
4
|
+
#
|
|
5
|
+
# Rack middleware that provide access to a database using a database
|
|
6
|
+
# instance (DbAgile::Core::Database)
|
|
7
|
+
#
|
|
8
|
+
class OneDatabase
|
|
9
|
+
include Middleware::Utils
|
|
10
|
+
include Middleware::Get
|
|
11
|
+
include Middleware::Post
|
|
12
|
+
include Middleware::Delete
|
|
13
|
+
|
|
14
|
+
# Database instance
|
|
15
|
+
attr_reader :database
|
|
16
|
+
|
|
17
|
+
# Creates a middleware instance
|
|
18
|
+
def initialize(database)
|
|
19
|
+
raise ArgumentError unless database.kind_of?(DbAgile::Core::Database)
|
|
20
|
+
@database = database
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Decodes a path and yield the block with a connection and the
|
|
24
|
+
# requested format
|
|
25
|
+
def decode(env)
|
|
26
|
+
case env['PATH_INFO'].strip[1..-1]
|
|
27
|
+
when ''
|
|
28
|
+
_copyright_(env)
|
|
29
|
+
when /(\w+)(\.(\w+))?$/
|
|
30
|
+
table = $1.to_sym
|
|
31
|
+
|
|
32
|
+
# Handle format
|
|
33
|
+
format = nil
|
|
34
|
+
if $2
|
|
35
|
+
format = known_extension?($2)
|
|
36
|
+
return _404_(env) unless format
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
format, body = database.with_connection do |connection|
|
|
40
|
+
yield(connection, table, format)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
content_type = DbAgile::IO::FORMAT_TO_CONTENT_TYPE[format]
|
|
44
|
+
_200_(env, content_type, body)
|
|
45
|
+
else
|
|
46
|
+
_404_(env)
|
|
47
|
+
end
|
|
48
|
+
rescue DbAgile::InvalidDatabaseName,
|
|
49
|
+
DbAgile::NoSuchDatabaseError,
|
|
50
|
+
DbAgile::NoSuchTableError => ex
|
|
51
|
+
_404_(env, ex)
|
|
52
|
+
rescue DbAgile::Error, Sequel::Error => ex
|
|
53
|
+
if ex.message =~ /exist/
|
|
54
|
+
_404_(env)
|
|
55
|
+
else
|
|
56
|
+
raise
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Rack handler
|
|
61
|
+
def call(env)
|
|
62
|
+
method = env['REQUEST_METHOD'].downcase.to_sym
|
|
63
|
+
if self.respond_to?(method)
|
|
64
|
+
result = self.send(method, env)
|
|
65
|
+
else
|
|
66
|
+
puts "Unsupported restful method #{env['REQUEST_METHOD']}"
|
|
67
|
+
[
|
|
68
|
+
500,
|
|
69
|
+
{'Content-Type' => 'text/plain'},
|
|
70
|
+
["Unsupported restful method #{env['REQUEST_METHOD']}"]
|
|
71
|
+
]
|
|
72
|
+
end
|
|
73
|
+
rescue Exception => ex
|
|
74
|
+
puts ex.message
|
|
75
|
+
puts ex.backtrace.join("\n")
|
|
76
|
+
[500, {'Content-Type' => 'text/plain'}, [ex.message]]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
end # class OneDatabase
|
|
80
|
+
end # class Middleware
|
|
81
|
+
end # module Restful
|
|
82
|
+
end # module DbAgile
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Restful
|
|
3
|
+
class Middleware
|
|
4
|
+
module Post
|
|
5
|
+
|
|
6
|
+
# Implements POST access of the restful interface
|
|
7
|
+
def post(env)
|
|
8
|
+
request = Rack::Request.new(env)
|
|
9
|
+
decode(env) do |connection, table, format|
|
|
10
|
+
format = :json if format.nil?
|
|
11
|
+
heading = connection.heading(table)
|
|
12
|
+
tuple = params_to_tuple(request.POST, heading)
|
|
13
|
+
inserted = connection.transaction do |t|
|
|
14
|
+
t.insert(table, tuple)
|
|
15
|
+
end
|
|
16
|
+
[format, to_xxx_enumerable(format, [ inserted ], tuple.keys)]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end # module Get
|
|
21
|
+
end # class Middleware
|
|
22
|
+
end # module Restful
|
|
23
|
+
end # module Facts
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Restful
|
|
3
|
+
class Middleware
|
|
4
|
+
module Utils
|
|
5
|
+
include ::DbAgile::IO
|
|
6
|
+
|
|
7
|
+
# Converts get parameters to a tuple for projection
|
|
8
|
+
def params_to_tuple(params, heading)
|
|
9
|
+
copy = {}
|
|
10
|
+
params.each_pair{|k, v|
|
|
11
|
+
k = k.to_sym
|
|
12
|
+
next unless heading.key?(k)
|
|
13
|
+
copy[k] = SByC::TypeSystem::Ruby::coerce(v, heading[k])
|
|
14
|
+
}
|
|
15
|
+
copy
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Returns a copyright response
|
|
19
|
+
def _copyright_(env)
|
|
20
|
+
[
|
|
21
|
+
200,
|
|
22
|
+
{'Content-Type' => 'text/plain'},
|
|
23
|
+
[ "dba #{DbAgile::VERSION} (c) 2010, Bernard Lambeau" ]
|
|
24
|
+
]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Returns a 404 response
|
|
28
|
+
def _404_(env, ex = nil)
|
|
29
|
+
[
|
|
30
|
+
404,
|
|
31
|
+
{'Content-Type' => 'text/plain'},
|
|
32
|
+
[ "Not found #{env['PATH_INFO']}: " ] + (ex.nil? ? [] : [ ex.message ])
|
|
33
|
+
]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Returns a 200 response for a given format
|
|
37
|
+
def _200_(env, type, result)
|
|
38
|
+
[
|
|
39
|
+
200,
|
|
40
|
+
{'Content-Type' => type},
|
|
41
|
+
result
|
|
42
|
+
]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Returns a 500 response
|
|
46
|
+
def _500_(env, message)
|
|
47
|
+
[
|
|
48
|
+
500,
|
|
49
|
+
{'Content-Type' => 'text/plain'},
|
|
50
|
+
[ message ]
|
|
51
|
+
]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Converts a dataset-like object to an enumerable rack result
|
|
55
|
+
def to_xxx_enumerable(format, dataset, columns)
|
|
56
|
+
buffer = StringIO.new
|
|
57
|
+
method = "to_#{format}".to_sym
|
|
58
|
+
DbAgile::IO.send(method, dataset, columns, buffer)
|
|
59
|
+
[ buffer.string ]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end # module Utils
|
|
63
|
+
end # class Middleware
|
|
64
|
+
end # module Restful
|
|
65
|
+
end # module DbAgile
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'stringio'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'dbagile'
|
|
4
|
+
require 'dbagile/restful/middleware/utils'
|
|
5
|
+
require 'dbagile/restful/middleware/get'
|
|
6
|
+
require 'dbagile/restful/middleware/post'
|
|
7
|
+
require 'dbagile/restful/middleware/delete'
|
|
8
|
+
require 'dbagile/restful/middleware/one_database'
|
|
9
|
+
module DbAgile
|
|
10
|
+
module Restful
|
|
11
|
+
class Middleware
|
|
12
|
+
include Middleware::Utils
|
|
13
|
+
|
|
14
|
+
# Environment
|
|
15
|
+
attr_reader :environment
|
|
16
|
+
|
|
17
|
+
# OneDatabase delegates
|
|
18
|
+
attr_reader :delegates
|
|
19
|
+
|
|
20
|
+
# Creates a Restful handler
|
|
21
|
+
def initialize(environment = DbAgile::default_environment, &block)
|
|
22
|
+
raise "Environment may not be nil" if environment.nil?
|
|
23
|
+
block.call(environment) if block
|
|
24
|
+
@environment = environment
|
|
25
|
+
_install
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Installs the delegates
|
|
29
|
+
def _install
|
|
30
|
+
@delegates = {}
|
|
31
|
+
environment.repository.each{|db|
|
|
32
|
+
@delegates[db.name] = Middleware::OneDatabase.new(db)
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Delegated according to the path
|
|
37
|
+
def call(env)
|
|
38
|
+
env['PATH_INFO'] =~ /^\/(\w+)(.*)$/
|
|
39
|
+
if $1
|
|
40
|
+
if delegates.key?($1.to_sym)
|
|
41
|
+
env['PATH_INFO'] = $2
|
|
42
|
+
delegates[$1.to_sym].call(env)
|
|
43
|
+
else
|
|
44
|
+
_404_(env)
|
|
45
|
+
end
|
|
46
|
+
else
|
|
47
|
+
_copyright_(env)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private :_install
|
|
52
|
+
end # class Middleware
|
|
53
|
+
end # module Restful
|
|
54
|
+
end # module DbAgile
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
if RUBY_VERSION == "1.8.6"
|
|
2
|
+
gem 'rack', "= 1.1.0"
|
|
3
|
+
require 'rack'
|
|
4
|
+
else
|
|
5
|
+
gem 'rack', ">= 1.1.0"
|
|
6
|
+
require 'rack'
|
|
7
|
+
end
|
|
8
|
+
require 'dbagile/restful/middleware'
|
|
9
|
+
require 'uri'
|
|
10
|
+
require "net/http"
|
|
11
|
+
require 'webrick'
|
|
12
|
+
module DbAgile
|
|
13
|
+
module Restful
|
|
14
|
+
class Server
|
|
15
|
+
|
|
16
|
+
# Default Rack options for restful server and client
|
|
17
|
+
DEFAULT_RACK_OPTIONS = {:Port => 8711, :Host => "127.0.0.1", :AccessLog => []}
|
|
18
|
+
|
|
19
|
+
# Server options
|
|
20
|
+
attr_reader :options
|
|
21
|
+
|
|
22
|
+
# Creates a server instance
|
|
23
|
+
def initialize(environment, options = DEFAULT_RACK_OPTIONS)
|
|
24
|
+
raise "Environment may not be nil" if environment.nil?
|
|
25
|
+
@environment = environment
|
|
26
|
+
@options = options
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Returns the server uri given by options
|
|
30
|
+
def uri
|
|
31
|
+
URI::parse("http://#{options[:Host]}:#{options[:Port]}/")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Starts the server inside a thread
|
|
35
|
+
def start
|
|
36
|
+
myself, env = self, @environment
|
|
37
|
+
rack_server = ::Rack::Handler::default
|
|
38
|
+
rack_app = ::Rack::Builder.new{ run DbAgile::Restful::Middleware.new(env) }
|
|
39
|
+
thread = Thread.new(rack_server, rack_app, options.dup){|s,a,o|
|
|
40
|
+
s.run(a, o){|server| @server = server}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# Wait until the server is loaded
|
|
44
|
+
try, ok, res = 0, false, nil
|
|
45
|
+
begin
|
|
46
|
+
res = Net::HTTP.get(uri)
|
|
47
|
+
ok = true
|
|
48
|
+
rescue Errno::ECONNREFUSED => ex
|
|
49
|
+
sleep 0.3
|
|
50
|
+
end until (ok or (try += 1)>10)
|
|
51
|
+
raise "Unable to connect to server" if try >= 10
|
|
52
|
+
|
|
53
|
+
@environment.say("Have a look at #{uri}")
|
|
54
|
+
thread
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Stops the server
|
|
58
|
+
def stop
|
|
59
|
+
@server.shutdown if @server.respond_to?(:shutdown)
|
|
60
|
+
@server = nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end # class Server
|
|
64
|
+
end # module Restful
|
|
65
|
+
end # module DbAgile
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Robustness
|
|
3
|
+
module Dependencies
|
|
4
|
+
|
|
5
|
+
# Raises when a dependency is missing
|
|
6
|
+
class ::DbAgile::DependencyError < ::DbAgile::Error; end
|
|
7
|
+
|
|
8
|
+
# Asserts that a standard library
|
|
9
|
+
def has_stdlib!(util_name, msg = nil)
|
|
10
|
+
require util_name
|
|
11
|
+
rescue StandardError => ex
|
|
12
|
+
if msg.nil?
|
|
13
|
+
msg = "DbAgile requires #{util_name} but failed to load it"
|
|
14
|
+
end
|
|
15
|
+
msg = "#{msg}\n#{ex.message}"
|
|
16
|
+
raise DbAgile::DependencyError, msg, ex.backtrace
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Asserts that a gem exists and is loaded
|
|
20
|
+
def has_gem!(gem_name, gem_version = nil, msg = nil)
|
|
21
|
+
require 'rubygems'
|
|
22
|
+
gem gem_name, gem_version
|
|
23
|
+
require gem_name
|
|
24
|
+
rescue StandardError => ex
|
|
25
|
+
if msg.nil?
|
|
26
|
+
msg = gem_version.nil? ? gem_name : "#{gem_name} (#{gem_version})"
|
|
27
|
+
msg = "DbAgile requires #{msg} but failed to load it"
|
|
28
|
+
end
|
|
29
|
+
msg = "#{msg}\n#{ex.message}"
|
|
30
|
+
raise DbAgile::DependencyError, msg, ex.backtrace
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end # module Dependencies
|
|
34
|
+
extend(Dependencies)
|
|
35
|
+
end # module Robustness
|
|
36
|
+
end # module DbAgile
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Robustness
|
|
3
|
+
module FileSystem
|
|
4
|
+
|
|
5
|
+
# Asserts that a directory exists, is readable and writable
|
|
6
|
+
def valid_rw_directory!(dir,
|
|
7
|
+
msg = "Unable to access #{dir} in read/write",
|
|
8
|
+
error_class = IOError)
|
|
9
|
+
unless File.directory?(dir) &&
|
|
10
|
+
File.readable?(dir) &&
|
|
11
|
+
File.writable?(dir)
|
|
12
|
+
raise error_class, msg, caller
|
|
13
|
+
end
|
|
14
|
+
dir
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Asserts that a file exists, is readable and writable
|
|
18
|
+
def valid_rw_file!(file,
|
|
19
|
+
msg = "Unable to access #{file} in read/write",
|
|
20
|
+
error_class = IOError)
|
|
21
|
+
unless File.file?(file) &&
|
|
22
|
+
File.readable?(file) &&
|
|
23
|
+
File.writable?(file)
|
|
24
|
+
raise error_class, msg, caller
|
|
25
|
+
end
|
|
26
|
+
file
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Asserts that a file exists and is readable.
|
|
30
|
+
def valid_r_file!(file,
|
|
31
|
+
msg = "Unable to access #{file} in read",
|
|
32
|
+
error_class = IOError)
|
|
33
|
+
unless File.file?(file) &&
|
|
34
|
+
File.readable?(file)
|
|
35
|
+
raise error_class, msg, caller
|
|
36
|
+
end
|
|
37
|
+
file
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Asserts that a directory does not exists
|
|
41
|
+
def unexisting_directory!(dir,
|
|
42
|
+
msg = "Directory #{dir} already exists, use --force",
|
|
43
|
+
error_class = IOError)
|
|
44
|
+
if File.exists?(dir)
|
|
45
|
+
raise error_class, msg, caller
|
|
46
|
+
end
|
|
47
|
+
dir
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end # module FileSystem
|
|
51
|
+
extend(FileSystem)
|
|
52
|
+
end # module Robustness
|
|
53
|
+
end # module DbAgile
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
|
|
3
|
+
# Main class of all DbAgile errors
|
|
4
|
+
class Error < StandardError; end
|
|
5
|
+
|
|
6
|
+
# Raised when something goes really wrong (a bug, typically)
|
|
7
|
+
class InternalError < DbAgile::Error; end
|
|
8
|
+
|
|
9
|
+
# Some internal assumption failed
|
|
10
|
+
class AssumptionFailedError < DbAgile::InternalError; end
|
|
11
|
+
|
|
12
|
+
end
|
|
13
|
+
require 'dbagile/robustness/file_system'
|
|
14
|
+
require 'dbagile/robustness/dependencies'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module FileSystemTools
|
|
3
|
+
|
|
4
|
+
# Returns a friendly path for display
|
|
5
|
+
def friendly_path(path, from)
|
|
6
|
+
from, path = Pathname.new(from), Pathname.new(path)
|
|
7
|
+
if path.to_s[0...from.to_s.length] == from.to_s
|
|
8
|
+
"~/#{path.relative_path_from(from)}"
|
|
9
|
+
else
|
|
10
|
+
nil
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Returns a friendly path, no matter what happens
|
|
15
|
+
def friendly_path!(path)
|
|
16
|
+
friendly_path(path, ENV['HOME']) or
|
|
17
|
+
friendly_path(path, File.expand_path('.')) or
|
|
18
|
+
path
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
extend(FileSystemTools)
|
|
22
|
+
end # module FileSystemTools
|
|
23
|
+
end # module DbAgile
|
|
24
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Tools
|
|
3
|
+
class OrderedHash
|
|
4
|
+
|
|
5
|
+
# Decorates a hash as an ordered hash
|
|
6
|
+
def initialize(hash = {})
|
|
7
|
+
@hash = hash
|
|
8
|
+
@keys = hash.keys
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Delegated to hash
|
|
12
|
+
def method_missing(name, *args, &block)
|
|
13
|
+
@hash.send(name, *args, &block)
|
|
14
|
+
@keys = (@keys & @hash.keys)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Sets a (name,value) pair
|
|
18
|
+
def []=(name, value)
|
|
19
|
+
@hash[name] = value
|
|
20
|
+
unless @keys.include?(name)
|
|
21
|
+
@keys << name
|
|
22
|
+
end
|
|
23
|
+
value
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Puts as YAML, maintaining order
|
|
27
|
+
def to_yaml(opts = {})
|
|
28
|
+
YAML::quick_emit(self, opts){|out|
|
|
29
|
+
out.map("tag:yaml.org,2002:map") do |map|
|
|
30
|
+
@keys.each{|key|
|
|
31
|
+
map.add(key.to_s, @hash[key])
|
|
32
|
+
}
|
|
33
|
+
end
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end # class OrderedHash
|
|
38
|
+
end # module Tools
|
|
39
|
+
end # module DbAgile
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module RubyTools
|
|
3
|
+
|
|
4
|
+
# Returns the parent module of a class
|
|
5
|
+
def parent_module(clazz)
|
|
6
|
+
name = clazz.name
|
|
7
|
+
if name =~ /^(.*?)::([^:]+)$/
|
|
8
|
+
Kernel.eval($1)
|
|
9
|
+
else
|
|
10
|
+
nil
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Returns the unqualified name of a class
|
|
15
|
+
def class_unqualified_name(clazz)
|
|
16
|
+
name = clazz.name
|
|
17
|
+
if name =~ /::([^:]+)$/
|
|
18
|
+
$1
|
|
19
|
+
else
|
|
20
|
+
name
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
alias :unqualified_class_name :class_unqualified_name
|
|
24
|
+
|
|
25
|
+
# Makes a call to a block that accepts optional arguments
|
|
26
|
+
def optional_args_block_call(block, args)
|
|
27
|
+
if RUBY_VERSION >= "1.9.0"
|
|
28
|
+
if block.arity == 0
|
|
29
|
+
block.call
|
|
30
|
+
else
|
|
31
|
+
block.call(*args)
|
|
32
|
+
end
|
|
33
|
+
else
|
|
34
|
+
block.call(*args)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Extracts the rdoc of a given ruby file source
|
|
39
|
+
def extract_file_rdoc(file)
|
|
40
|
+
source, doc, started = File.read(file), "", false
|
|
41
|
+
source.each_line{|line|
|
|
42
|
+
if /^\s*[#]/ =~ line
|
|
43
|
+
doc << line
|
|
44
|
+
started = true
|
|
45
|
+
elsif started
|
|
46
|
+
break
|
|
47
|
+
end
|
|
48
|
+
}
|
|
49
|
+
doc.gsub(/^\s*[#] ?/, "")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Splits a text obtained through extract_file_rdoc into paragraphs
|
|
53
|
+
def rdoc_paragraphs(rdoc_text)
|
|
54
|
+
paragraphs, current = [], ""
|
|
55
|
+
rdoc_text.each_line do |s|
|
|
56
|
+
if s.strip.empty?
|
|
57
|
+
unless current.strip.empty?
|
|
58
|
+
paragraphs << current
|
|
59
|
+
end
|
|
60
|
+
current = ""
|
|
61
|
+
else
|
|
62
|
+
current << s
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
unless current.strip.empty?
|
|
66
|
+
paragraphs << current
|
|
67
|
+
end
|
|
68
|
+
paragraphs
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Convenient method for <code>rdoc_paragraphs(extract_file_rdoc(file))</code>
|
|
72
|
+
def rdoc_file_paragraphs(file)
|
|
73
|
+
rdoc_paragraphs(extract_file_rdoc(file))
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
extend(RubyTools)
|
|
77
|
+
end # module RubyTools
|
|
78
|
+
end # module DbAgile
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
module DbAgile
|
|
2
|
+
module Tools
|
|
3
|
+
module Tuple
|
|
4
|
+
|
|
5
|
+
# Returns the heading of a given tuple
|
|
6
|
+
def tuple_heading(tuple)
|
|
7
|
+
heading = {}
|
|
8
|
+
tuple.each_pair{|name, value| heading[name] = value.class}
|
|
9
|
+
heading
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Checks a tuple heading, displaying a warning message on the
|
|
13
|
+
# environment if something goes bad...
|
|
14
|
+
def check_tuple_heading(heading, environment)
|
|
15
|
+
heading.each_pair{|k,v|
|
|
16
|
+
if NilClass == v
|
|
17
|
+
environment.say("WARNING: NilClass in heading (type inference failure), using String")
|
|
18
|
+
heading[k] = String
|
|
19
|
+
elsif !DbAgile::RECOGNIZED_DOMAINS.include?(v)
|
|
20
|
+
environment.say("WARNING: Unrecognized domain #{v} in heading, using String")
|
|
21
|
+
heading[k] = String
|
|
22
|
+
end
|
|
23
|
+
}
|
|
24
|
+
heading
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Projects a tuple over some columns
|
|
28
|
+
def tuple_project(tuple, columns)
|
|
29
|
+
proj = {}
|
|
30
|
+
columns.collect{|col| proj[col] = tuple[col]}
|
|
31
|
+
proj
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Extract the key/value pairs that form a key on a tuple, given
|
|
35
|
+
# keys information. Returns tuple if no such better tuple can be found.
|
|
36
|
+
def tuple_key(tuple, keys)
|
|
37
|
+
return tuple if keys.nil?
|
|
38
|
+
key = keys.find{|k| k.all?{|a| !tuple[a].nil? }}
|
|
39
|
+
key.nil? ? tuple : tuple_project(tuple, key)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Converts a tuple to a query string
|
|
43
|
+
def tuple_to_querystring(tuple)
|
|
44
|
+
tuple.collect{|k,v| "#{CGI::escape(k.to_s)}=#{CGI::escape(v.to_s)}"}.reverse.join('&')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end # module Tools
|
|
48
|
+
end # class Adapter
|
|
49
|
+
end # module DbAgile
|