dddbl 0.0.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ pkg/*
2
+ *.gem
3
+ *~
4
+ *#
5
+ .bundle
6
+ Gemfile.lock
data/LICENSE ADDED
@@ -0,0 +1,24 @@
1
+ Copyright (c) 2011, André Gawron
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without modification,
5
+ are permitted provided that the following conditions are met:
6
+
7
+ - Redistributions of source code must retain the above copyright notice,
8
+ this list of conditions and the following disclaimer.
9
+ - Redistributions in binary form must reproduce the above copyright notice,
10
+ this list of conditions and the following disclaimer in the documentation
11
+ and/or other materials provided with the distribution.
12
+ - The names of its contributors may be used to endorse or promote products
13
+ derived from this software without specific prior written permission.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
19
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
20
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
22
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
23
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
24
+ OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.rdoc ADDED
@@ -0,0 +1,188 @@
1
+ = DDDBL - Definition Driven Database Layer
2
+
3
+ == What?
4
+
5
+ DDDBL is a library to simplify the use of (different) databases and splits up
6
+ application's and database's (e.g: SQL queries) code through an easy
7
+ and unified API. The SQL is defined in files outside of the application's source
8
+ to easiliy port the SQL to diffrent applications - or even programming languages.
9
+ Refering to the written queries using an alias makes it even more clearer and
10
+ better to understand for newcomers, who then don't have to waste time figuring out
11
+ what the query does.
12
+
13
+ == Why?
14
+
15
+ Many applications interacting with databases have the sql code directly written
16
+ in the its source. Reading, reviewing and understanding that
17
+ unfimiliar code can be hard, even more for non sql-pros. Most of the time -
18
+ to optimize the queries and the database performance in general - DBAs are hired
19
+ who are probably not familiar with the programming language used. So they have
20
+ to dig into the code and try to optimize it without breaking anything.
21
+
22
+ == Supported databases
23
+
24
+ Common RDMS like MySQL, PostgreSQL and SQLite are supported. The DDDBL uses another
25
+ gem called RDBI which simplifies the handling of several databases. For a full
26
+ list please of supported drivers please check the RDBI's github page
27
+ (https://github.com/RDBI/).
28
+
29
+ == It's a port, isn't it?
30
+
31
+ Yes. The DDDBL was orginally written in PHP and is a creation of Torsten Zühlsdorff.
32
+ For more information on the PHP version, go to http://www.dddbl.de (German only).
33
+ The ruby version will also be featured there in the near future.
34
+
35
+ === Any differences?
36
+
37
+ Yes. As of writing, the ruby port does not include every functionality the
38
+ PHP version offers. For example:
39
+
40
+ * not as much freedom regarding manipulating query-parameter pre-execution besides
41
+ casting the binded parameters to any value extendable through TypeLib
42
+ * caching of prepared statements
43
+
44
+ == Dependecies
45
+
46
+ The database handling and querying is handled by the RDBI library. For more
47
+ information please see their README (https://github.com/RDBI/rdbi/blob/master/README.txt)
48
+ or visit the project's page on https://github.com/RDBI/ .
49
+
50
+ == Getting started
51
+
52
+ === Database definitions
53
+
54
+ Every database the DDDBL should connect to has to be defined in a configuration
55
+ file using the ini-format. Example:
56
+
57
+ [TEST-DB]
58
+ HOST = localhost
59
+ DBNAME = test
60
+ TYPE = PostgreSQL
61
+ USER = root
62
+ PASS =
63
+ DEFAULT = true
64
+
65
+ * [TEST-DB]: alias of the database connection. It's used if the DDDBL shall
66
+ execute the query to another database
67
+ * HOST: host of the database
68
+ * DBNAME: database to select
69
+ * TYPE: driver to use
70
+ * USER: user who will be used to connect to the database
71
+ * PASS: user's password
72
+ * DEFAULT: normally, the DDDBL needs to know which database shall be used
73
+ to execute the query. If the DEFAULT flag is set to true, this connection
74
+ will be used at first - no explit connection selection needed. DEFAULT is optional.
75
+
76
+ Now the file has to be added to the database pool:
77
+
78
+ DDDBL::Pool::DB << DDDBL::Config.parse_dbs('/path/to/db/definitions.def')
79
+
80
+ The database has to be added before any queries. Adding a file with database
81
+ definitions results in establishing a connection to every defined database.
82
+
83
+ ==== Selecting (another) database
84
+
85
+ If only one connection is used, the following is just "good-to-know".
86
+ To select (another) database but the default is done by calling
87
+
88
+ DDDBL::select_db('TEST-DB')
89
+
90
+ Now every query executed after #select_db will be using the database connection
91
+ defined through the alias 'TEST-DB'.
92
+
93
+ === Query definitions
94
+
95
+ The query definition file also uses the ini-format and has to be configurated
96
+ seperately from the application (that's what the DDDBL is all about, isn't it?)
97
+
98
+ As for now, the query definitions of the PHP and ruby versions are interchangable:
99
+
100
+ [QUERY-ALIAS]
101
+ QUERY = "SELECT * FROM table"
102
+ HANDLER = MULTI
103
+
104
+ [QUERY-MULTILINE]
105
+ QUERY = "SELECT *
106
+ FROM table
107
+ WHERE foo = ?"
108
+ HANDLER = MULTI
109
+
110
+ [CREATE-TABLE]
111
+ QUERY = "CREATE TABLE foobar ( id SERIAL, name VARCHAR(50) )"
112
+
113
+ * [QUERY-ALIAS]: as with the database definition, the alias is used to
114
+ refer to the query inside of the application.
115
+ * QUERY: the sql query. It can be enclosed by " but it's optional as long
116
+ as the query fits into one line. ? is used to define parameters which will
117
+ be binded later on. No ; needed.
118
+ * HANDLER: the handler is in charge of transforming the query's result set.
119
+ There's own section devoted to that topic. HANDLER is optional (since a
120
+ result set can be empty).
121
+
122
+ As the database definitions, the query definitions also have to be added to the pool:
123
+
124
+ DDDBL::Pool << DDDBL::Config.parse_queries('/path/to/query/definitions.sql')
125
+
126
+ ==== Querying
127
+
128
+ To execute a query which was be added to the pool is straight forward:
129
+
130
+ formated_result = DDDBL::get('QUERY-ALIAS')
131
+
132
+ # binds 'bar'
133
+ formated_result = DDDBL::get('QUERY-MULTILINE', 'bar')
134
+
135
+ # without a result set
136
+ DDDBL::get('CREATE-TABLE')
137
+
138
+ === Transactions
139
+
140
+ DDDBL also supports transaction. More information on the implementation details
141
+ has to be looked up in the RDBI::Database documentation
142
+
143
+ DDDBL::transaction do
144
+ DDDBL::get('CREATE-TABLE')
145
+
146
+ # will fail because QUERY-MULTILINE expects a parameter
147
+ DDDBL::get('QUERY-MULTILINE')
148
+ end
149
+
150
+ Since the QUERY-MULTLINE will fail, the whole transaction will be rolled back
151
+ and no table will be created.
152
+
153
+ === Creating your own result handler
154
+
155
+ As you may know or guess by now, RDBI supports transforming the query's result
156
+ set to any datastructure you want. It's as straight forward as adding a query
157
+ file to the pool, just extend the RDBI's RDBI::Result::Driver class and
158
+ implement at least #fetch. The name of the new result driver is then the name
159
+ which has to be used in the query's HANDLER configuration field.
160
+
161
+ It's also possible to pass a configuration to the result driver defined in the
162
+ query definition:
163
+
164
+ [QUERY-ALIAS]
165
+ QUERY = "SELECT bar FROM foo;"
166
+ HANDLER = MULTI INT::bar
167
+
168
+ MULTI, as in the other examples, is the name of the result driver. If there's
169
+ a whitespace following with more text, this additional text will be passed to
170
+ the result driver's constructor. The example definition will explitictly cast
171
+ every row's bar-column value to an Integer.
172
+
173
+ For more information on creating a result driver, please read the documentation
174
+ of RDBI::Result::Driver. If you want to overwrite a default result driver,
175
+ just override the class.
176
+
177
+ == Bughunting was successful!
178
+
179
+ Just report the bug through github's tracker: https://github.com/melkon/dddbl/issues
180
+
181
+ == I'd like to patch and / or help maintain DDDBL. How can I?
182
+
183
+ * Fork the project: http://github.com/melkon/dddbl
184
+ * Make your feature addition or bug fix.
185
+
186
+ == Copyright
187
+
188
+ Copyright (c) 2011 André Gawron. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
data/dddbl.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require "dddbl/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "dddbl"
6
+ s.version = DDDBL::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ["André Gawron"]
9
+ s.email = ["andre@ziemek.de"]
10
+ s.homepage = "https://github.com/melkon/dddbl"
11
+ s.summary = %q{A Definition Driven Database Layer}
12
+ s.description = %q{A Definition Driven Database Layer. First developed in php, see: http://www.dddbl.de}
13
+
14
+ s.rubyforge_project = "dddbl"
15
+
16
+ s.add_dependency "inifile", ">= 0.4.1"
17
+ s.add_dependency "rdbi"
18
+
19
+ s.files = `git ls-files`.split("\n")
20
+ s.require_paths = ["lib"]
21
+ end
data/example/dbdef.def ADDED
@@ -0,0 +1,9 @@
1
+ [TEST-DB]
2
+ HOST = localhost
3
+ DBNAME = trackadev
4
+ TYPE = PostgreSQL
5
+ USER = trackadev
6
+ PASS =
7
+ BIND = true
8
+ DEFAULT = true
9
+
data/example/demo.rb ADDED
@@ -0,0 +1,59 @@
1
+ require 'rdbi'
2
+ require 'rdbi-driver-postgresql'
3
+
4
+ require 'inifile'
5
+ require 'dddbl'
6
+
7
+ class RDBI::Result::Driver::YAL < RDBI::Result::Driver
8
+ def initialize(result, *args)
9
+ super
10
+ RDBI::Util.optional_require('yaml')
11
+ end
12
+
13
+ def format_single_row(raw)
14
+ ::Hash[column_names.zip(raw)].to_yaml
15
+ end
16
+
17
+ def format_multiple_rows(raw_rows)
18
+ raw_rows.collect { |row| ::Hash[column_names.zip(row)] }.to_yaml
19
+ end
20
+
21
+ private
22
+ def column_names
23
+ @column_names ||= @result.schema.columns.map(&:name)
24
+ end
25
+ end
26
+
27
+
28
+ DDDBL::Pool::DB << DDDBL::Config.parse_dbs('dbdef.def')
29
+ DDDBL::Pool << DDDBL::Config.parse_queries('test.sql')
30
+
31
+ DDDBL::get('TEST-QUERY')
32
+
33
+ DDDBL::get('TEST-INSERT', 'andre')
34
+ DDDBL::get('TEST-INSERT', 'melkon')
35
+
36
+ before = DDDBL::get('TEST-SELECT') ; p before
37
+
38
+ begin
39
+ DDDBL::transaction do
40
+
41
+ DDDBL::get('TEST-UPDATE', 'thorny', 2)
42
+
43
+ # raises an exception
44
+ # rollback initiated
45
+ # throws an exception
46
+ DDDBL::get('TEST-INSERT')
47
+
48
+ end ; rescue => e ; end
49
+
50
+ after = DDDBL::get('TEST-SELECT') ; p after
51
+
52
+
53
+ if before.to_s == after.to_s
54
+ p "transaction rollbacked"
55
+ else
56
+ p "transaction commited"
57
+ end
58
+
59
+ DDDBL::get('TEST-DROP')
data/example/test.sql ADDED
@@ -0,0 +1,12 @@
1
+ [TEST-QUERY]
2
+ QUERY = "CREATE TABLE muff (id SERIAL, name VARCHAR(255))"
3
+
4
+ [TEST-INSERT]
5
+ QUERY = "INSERT INTO muff (name) VALUES(?)"
6
+
7
+ [TEST-SELECT]
8
+ QUERY = "SELECT * FROM muff"
9
+ HANDLER = YAML
10
+
11
+ [TEST-DROP]
12
+ QUERY = "DROP TABLE IF EXISTS muff"
data/lib/dddbl.rb ADDED
@@ -0,0 +1,152 @@
1
+ #
2
+ # DDDBL - Definition Driven Database Layer
3
+ # Copyright (c) 2011 André Gawron. See LICENSE and README for details.
4
+ #
5
+ # @example Executing Query
6
+ # result = DDDBL::get('QUERY-ALIAS', 'foo', 'bar')
7
+ #
8
+ # @example Simple Transaction
9
+ # DDDBL::transaction do
10
+ # DDDBL::get('QUERY-ALIAS', 'foo', 'bar')
11
+ # DDDBL::get('CREATE-TABLE')
12
+ # end
13
+ #
14
+ # @example Select another database
15
+ # DDDBL::select_db('DATABASE-ALIAS')
16
+ #
17
+ class DDDBL
18
+
19
+ #
20
+ # a query can be associated with a specific
21
+ # database driver but if none is given, it will
22
+ # be safed in GLOBAL_POOL so every database connection
23
+ # can execute the defined query.
24
+ #
25
+ GLOBAL_POOL = :default
26
+
27
+ class << self
28
+
29
+ #
30
+ # selects an database connection which will then
31
+ # be used to execute queries. if the connection
32
+ # is not yet established, it will be after calling
33
+ # this method.
34
+ #
35
+ # @param [String] database_name databse alias which was defined in the config file
36
+ #
37
+ def select_db(database_name)
38
+ if @dbh == nil || @database != database_name
39
+ @dbh = RDBI::pool(database_name).get_dbh
40
+ end
41
+ end
42
+
43
+ #
44
+ # executes a defined alias and returns its result set which is
45
+ # transformed by an optionally defined result hanlder before.
46
+ #
47
+ # #get uses the current database connection set by #select_db
48
+ # if none was explicity selected but a default database was set
49
+ # using the configuration files, the default connection
50
+ # will be used.
51
+ #
52
+ # @param [String] query_alias querie's alias defined in the config file
53
+ # @param [Array] *binds the parameters which shall be binded to the query
54
+ #
55
+ # @return the result set transformed by the defined handler
56
+ #
57
+ def get(query_alias, *binds)
58
+ query = DDDBL::Pool[@dbh.driver, query_alias]
59
+ res = @dbh.execute(query[:query], *binds)
60
+ res.as(query[:handler]).fetch(:all) if !query[:handler].empty?
61
+ end
62
+
63
+ #
64
+ # delegates method calls to RDBI::Database
65
+ # DDDBL::transaction is currently implemented this way.
66
+ #
67
+ # @param [String] method valid RDBI::Database method
68
+ # @param [Array] *args RDBI::Database method's arguments
69
+ # @param [Proc] &block and finally the optional block
70
+ #
71
+ # @return everything that the RDBI::Datbase method calls will return
72
+ # @return [Boolean] false if no database connection is set
73
+ #
74
+ # @raise [ArgumentError] if RDBI::Database does not implement given method
75
+ #
76
+ def method_missing(method, *args, &block)
77
+ return false if !@dbh.is_a? RDBI::Database
78
+ raise ArgumentError, "RDBI::Database doesnt have #{method}" if !@dbh.respond_to?(method)
79
+
80
+ @dbh.send(method, *args, &block)
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+
87
+ #
88
+ # DDDBL::Utils provides methods for validation of queries
89
+ # and database definitions.
90
+ #
91
+ # @see DDDBL::Pool for implementation examples
92
+ # @see DDDBL::Pool::DB for implementation examples
93
+ #
94
+ module DDDBL::Utils
95
+
96
+ #
97
+ # sets the mandatory fiels of a configuration
98
+ #
99
+ # @param [#each] fields which are mandatory, has to implement `#each`
100
+ #
101
+ # @raise [ArgumentError] if fields does not respond to #each
102
+ #
103
+ def mandatory(fields)
104
+ raise ArgumentError, 'parameter has to implement #each' if !fields.respond_to?('each')
105
+
106
+ @mandatory = fields
107
+ end
108
+
109
+ #
110
+ # sets the optional fiels of a configuration
111
+ #
112
+ # @param [#each] fields which are optional, has to implement #each
113
+ #
114
+ # @raise [ArgumentError] if fields does not respond to #each
115
+ #
116
+ def optional(fields)
117
+ raise ArgumentError, 'parameter has to implement #each' if !fields.respond_to?('each')
118
+
119
+ @optional = fields
120
+ end
121
+
122
+ #
123
+ # checks check for the defined mandatory and optional values
124
+ #
125
+ # @param [#each] check data structure which implements #each
126
+ #
127
+ # @return [Boolean] true if validation was successful
128
+ # @return [Boolean] false if not
129
+ #
130
+ # @raise [ArgumentError] if check does not respond to #has_key?
131
+ # @raise [ArgumentError] if check does not respond to #empty?
132
+ #
133
+ def valid?(check)
134
+ raise ArgumentError, 'parameter has to implement has_key?' if !check.respond_to?('has_key?')
135
+ raise ArgumentError, 'parameter has to implement empty?' if !check.respond_to?('empty?')
136
+
137
+ @mandatory.each do |key|
138
+ return false if !check.has_key?(key) || check[key].empty?
139
+ end
140
+
141
+ @optional.each do |key|
142
+ return false if !check.has_key?(key)
143
+ end
144
+ end
145
+
146
+ end
147
+
148
+ require 'dddbl/config'
149
+ require 'dddbl/pool'
150
+
151
+ # result handler
152
+ require 'dddbl/results'
@@ -0,0 +1,119 @@
1
+ #
2
+ # DDDBL - Definition Driven Database Layer
3
+ # Copyright (c) 2011 André Gawron. See LICENSE and README for details.
4
+ #
5
+ # DDDBL::Config parses the configuration files for queries and databases.
6
+ #
7
+ # Feel free to implement another parser (for example YAML-based files)
8
+ # and overwrite or extend DDDBL::Config. DDDBL::Config::Defaults
9
+ # will give you reasonable default values.
10
+ #
11
+ # @example Parse database definitions
12
+ # db_defintions = DDDBL::Config.parse_dbs('/path/to/file')
13
+ #
14
+ # @example Parse query definitions
15
+ # query_definitions = DDDBL::Config.parse_queries('/path/to/file')
16
+ #
17
+ module DDDBL::Config
18
+
19
+ class << self
20
+
21
+ #
22
+ # Offers methods to get default values for a database
23
+ # and query configuration.
24
+ #
25
+ module DDDBL::Config::Defaults
26
+
27
+ #
28
+ # returns the default values for a query configuration
29
+ #
30
+ # @param [String] query_alias the query's alias
31
+ #
32
+ # @return [Hash] the default values for a query configuration
33
+ # @option [String] :alias will contain the query_alias
34
+ # @option [String, Symbol] :type will contain DDDBL::GLOBAL_POOL
35
+ # @option [String] :handler will contain an empty string
36
+ #
37
+ def default_query(query_alias)
38
+ {
39
+ :alias => query_alias,
40
+ :type => DDDBL::GLOBAL_POOL,
41
+ :handler => ''
42
+ }
43
+ end
44
+
45
+ #
46
+ # returns the default values for a database configuration
47
+ #
48
+ # @param [String] db_alias the database's alias
49
+ #
50
+ # @return [Hash] the default values for a database configuration
51
+ # @option [String] :pool_name will contain the db_alias
52
+ # @option [Boolean] :default will contain false
53
+ # @option [String] :pass will contain the user's password
54
+ #
55
+ def default_db(db_alias)
56
+ {
57
+ :pool_name => db_alias,
58
+ :default => false,
59
+ :pass => ''
60
+ }
61
+ end
62
+
63
+ end
64
+
65
+ include DDDBL::Config::Defaults
66
+
67
+ end
68
+
69
+ #
70
+ # parses the queries from given file
71
+ #
72
+ # @param [File] file containing query definitions in IniFile-format
73
+ #
74
+ # @return [Hash<Hash>] parsed queries
75
+ #
76
+ # @raise [ArgumentError] if file does not exist
77
+ #
78
+ # @see [IniFile] for more information on the syntax
79
+ #
80
+ def self.parse_queries(file)
81
+ raise ArgumentError, "#{file} does not exist" if !File.exists?(file)
82
+
83
+ queries = {}
84
+
85
+ IniFile.load(file).each do |query_alias, query_param, query_value|
86
+ queries[query_alias] ||= default_query(query_alias)
87
+ queries[query_alias][query_param.downcase.to_sym] = query_value
88
+ end
89
+
90
+ queries
91
+
92
+ end
93
+
94
+ #
95
+ # parses the databases from given file
96
+ #
97
+ # @param [File] file containing database definitions in IniFile-format
98
+ #
99
+ # @return [Hash<Hash>] parsed databases
100
+ #
101
+ # @raise [ArgumentError] if file does not exist
102
+ #
103
+ # @see [IniFile] for more information on the syntax
104
+ #
105
+ def self.parse_dbs(file)
106
+ raise ArgumentError, "#{file} does not exist" if !File.exists?(file)
107
+
108
+ dbs = {}
109
+
110
+ IniFile.load(file).each do |db_alias, db_param, db_value|
111
+ dbs[db_alias] ||= default_db(db_alias)
112
+ dbs[db_alias][db_param.downcase.to_sym] = db_value
113
+ end
114
+
115
+ dbs
116
+
117
+ end
118
+
119
+ end
data/lib/dddbl/pool.rb ADDED
@@ -0,0 +1,108 @@
1
+ #
2
+ # DDDBL - Definition Driven Database Layer
3
+ # Copyright (c) 2011 André Gawron. See LICENSE and README for details.
4
+ #
5
+ # DDDBL::Pool contains the parsed queries
6
+ #
7
+ class DDDBL::Pool
8
+
9
+ class << self
10
+ include DDDBL::Utils
11
+ end
12
+
13
+ mandatory [:alias, :query, :type]
14
+ optional [:handler]
15
+
16
+ #
17
+ # returns a stored query for given database driver
18
+ # if none is found, the method looks in the global "namespace"
19
+ # if there is also no query stored, it raises an exception.
20
+ #
21
+ # @param [String] dbtype database's driver name (e.g. MySQL or PostgreSQL)
22
+ # @param [String] query_alias the query's alias
23
+ #
24
+ # @return [Hash] the query configuration
25
+ #
26
+ # @raise [StandardError] if no query is stored under given alias and driver
27
+ #
28
+ # @see [DDDBL::Pool::[]=] for hash keys
29
+ # @see [DDDBL::GLOBAL_POOL] for global "namespace"
30
+ #
31
+ def self.[](dbtype, query_alias)
32
+ if @pool.has_key?(dbtype) && @pool[dbtype].has_key?(query_alias)
33
+ @pool[dbtype][query_alias]
34
+ elsif @pool.has_key?(DDDBL::GLOBAL_POOL) && @pool[DDDBL::GLOBAL_POOL].has_key?(query_alias)
35
+ @pool[DDDBL::GLOBAL_POOL][query_alias]
36
+ else
37
+ raise StandardError, "#{query_alias} not a saved query alias"
38
+ end
39
+ end
40
+
41
+ #
42
+ # sets a query configuration for given database pool
43
+ # optional keys have to be set but can be empty.
44
+ #
45
+ # @param [String] dbtype database's driver name (e.g. MySQL or PostgreSQL)
46
+ # @param [Hash] query_config a valid query configuration
47
+ #
48
+ # @raise [StandardError] if the query configuration is not valid
49
+ #
50
+ # @see #mandatory for mandatory query configration keys
51
+ # @see #optional for optional query configuration keys
52
+ #
53
+ def self.[]=(dbtype, query_config)
54
+ raise StandardError, 'query is not properly configured' if !valid?(query_config)
55
+
56
+ @pool ||= Hash.new(&(p=lambda{|h,k| h[k] = Hash.new(&p)}))
57
+ @pool[dbtype][query_config[:alias]] = query_config
58
+ end
59
+
60
+ #
61
+ # shortcut for an array (or hash) of query configurations
62
+ # adds the whole query_configs to their corresponding pools.
63
+ #
64
+ # @param [#each] query_configs a list of query_configs, has to respond to #each(key, query_config)
65
+ #
66
+ def self.<<(query_configs)
67
+ query_configs.each do |key, query_config|
68
+ DDDBL::Pool[query_config[:type]] = query_config
69
+ end
70
+ end
71
+
72
+ end
73
+
74
+ #
75
+ # DDDBL - Definition Driven Database Layer
76
+ # Copyright (c) 2011 André Gawron. See LICENSE and README for details.
77
+ #
78
+ # DDDBL::Pool::DB contains the parsed database definitions
79
+ #
80
+ class DDDBL::Pool::DB
81
+
82
+ class << self
83
+ include DDDBL::Utils
84
+ end
85
+
86
+ mandatory [:type, :pool_name, :host, :dbname, :user]
87
+ optional [:default, :pass]
88
+
89
+ #
90
+ # adds the whole db_configs to the pool,
91
+ # establishs a connection to each of them,
92
+ # and selects the default database connection
93
+ # if no connection is already set.
94
+ #
95
+ # @param [#each] query_configs a list of query_configs, has to respond to #each(key, query_config)
96
+ #
97
+ # @raise [StandardError] if the configration file is not valid
98
+ #
99
+ def self.<<(db_configs)
100
+ db_configs.each do |key, db_config|
101
+ raise StandardError, 'db_config is not valid' if !valid?(db_config)
102
+
103
+ RDBI::connect_cached(db_config[:type], db_config);
104
+ DDDBL::select_db(db_config[:pool_name]) if db_config[:default] && !DDDBL::connected?
105
+ end
106
+ end
107
+
108
+ end
@@ -0,0 +1,5 @@
1
+ # the php-library makes use of MULTI as result handler
2
+ # RDBI provides with Struct the same functionality
3
+ # for portability reasons of the query config files
4
+ # a MULTI handler is introduced which is an alias for Struct
5
+ class RDBI::Result::Driver::MULTI < RDBI::Result::Driver::Struct ; end
@@ -0,0 +1,3 @@
1
+ class DDDBL
2
+ VERSION = "0.0.1.alpha"
3
+ end
metadata ADDED
@@ -0,0 +1,88 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dddbl
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: 6
5
+ version: 0.0.1.alpha
6
+ platform: ruby
7
+ authors:
8
+ - "Andr\xC3\xA9 Gawron"
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-08-31 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: inifile
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.4.1
24
+ type: :runtime
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: rdbi
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :runtime
36
+ version_requirements: *id002
37
+ description: "A Definition Driven Database Layer. First developed in php, see: http://www.dddbl.de"
38
+ email:
39
+ - andre@ziemek.de
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - .gitignore
48
+ - LICENSE
49
+ - README.rdoc
50
+ - Rakefile
51
+ - dddbl.gemspec
52
+ - example/dbdef.def
53
+ - example/demo.rb
54
+ - example/test.sql
55
+ - lib/dddbl.rb
56
+ - lib/dddbl/config.rb
57
+ - lib/dddbl/pool.rb
58
+ - lib/dddbl/results.rb
59
+ - lib/dddbl/version.rb
60
+ homepage: https://github.com/melkon/dddbl
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options: []
65
+
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: "0"
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ">"
78
+ - !ruby/object:Gem::Version
79
+ version: 1.3.1
80
+ requirements: []
81
+
82
+ rubyforge_project: dddbl
83
+ rubygems_version: 1.8.5
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: A Definition Driven Database Layer
87
+ test_files: []
88
+