Module: Mao
- Defined in:
- lib/mao.rb,
lib/mao/version.rb
Overview
The top-level module to access Mao.
Defined Under Namespace
Modules: Filter Classes: Query
Constant Summary collapse
- Rollback =
When raised in a transaction, causes a rollback without the exception bubbling.
Class.new(Exception)
- VERSION =
The version of the last release of Mao made. Increment when releasing a new gem.
"0.0.7"
Class Method Summary collapse
-
.connect!(options) ⇒ Object
Connect to the database.
-
.convert_type(value, type) ⇒ Object
Converts
value
to a native Ruby value, based on the PostgreSQL typetype
. -
.disconnect! ⇒ Object
Disconnect from the database.
-
.escape_literal(value) ⇒ Object
Escape
value
as appropriate for a literal in an SQL statement. -
.normalize_join_result(result, from_query, to_query) ⇒ Object
Normalizes the Hash
result
(of Strings to Strings), with the joining tables offrom_query
andto_query
. -
.normalize_result(result, col_types) ⇒ Object
Normalizes the Hash
result
(of Strings to Strings), withcol_types
specifying Symbol column names to String PostgreSQL types. -
.query(table) ⇒ Object
Returns a new Mao::Query object for
table
. -
.quote_ident(name) ⇒ Object
Quote
name
as appropriate for a table or column name in an SQL statement. -
.sql(sql, *args, &block) ⇒ Object
Execute the raw SQL
sql
with positionalargs
. -
.transaction(&block) ⇒ Object
Executes
block
in a transaction.
Class Method Details
.connect!(options) ⇒ Object
Connect to the database. options
is currently the straight Postgres gem options.
10 11 12 13 14 15 |
# File 'lib/mao.rb', line 10 def self.connect!() unless @conn @conn = PG.connect() @conn.internal_encoding = Encoding::UTF_8 end end |
.convert_type(value, type) ⇒ Object
Converts value
to a native Ruby value, based on the PostgreSQL type type
.
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/mao.rb', line 158 def self.convert_type(value, type) return nil if value.nil? case type when "integer", "smallint", "bigint", "serial", "bigserial" value.to_i when /^character varying/, "text" value when "timestamp without time zone" # We assume it's in UTC. (Dangerous?) value =~ /^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2}(?:\.\d+)?)$/ Time.new($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_f, 0) when "boolean" value == "t" when "bytea" PG::Connection.unescape_bytea(value) when "numeric" BigDecimal.new(value) else STDERR.puts "#{self.name}: unknown type: #{type}" value end end |
.disconnect! ⇒ Object
Disconnect from the database.
18 19 20 21 |
# File 'lib/mao.rb', line 18 def self.disconnect! @conn.close @conn = nil end |
.escape_literal(value) ⇒ Object
Escape value
as appropriate for a literal in an SQL statement.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/mao.rb', line 40 def self.escape_literal(value) case value when String if @conn.respond_to?(:escape_literal) @conn.escape_literal(value) else "'#{@conn.escape_string(value)}'" end when NilClass "null" when TrueClass "true" when FalseClass "false" when Numeric value.to_s when Array if value == [] # NULL IN NULL is NULL in SQL, so this is "safe". Empty lists () are # apparently part of the standard, but not widely supported (!). "(null)" else "(#{value.map {|v| escape_literal(v)}.join(", ")})" end when Mao::Query::Raw value.text when Time escape_literal(value.utc.strftime("%Y-%m-%d %H:%M:%S.%6N")) else raise ArgumentError, "don't know how to escape #{value.class}" end end |
.normalize_join_result(result, from_query, to_query) ⇒ Object
Normalizes the Hash result
(of Strings to Strings), with the joining tables of from_query
and to_query
. Assumes the naming convention for result keys of Mao::Query#join (see Mao::Query#sql) has been followed.
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/mao.rb', line 127 def self.normalize_join_result(result, from_query, to_query) results = {} n = 0 from_table = from_query.table from_types = from_query.col_types from_types.keys.sort.each do |k| n += 1 key = "c#{n}" if result.include?(key) results[from_table] ||= {} results[from_table][k] = convert_type(result[key], from_types[k]) end end to_table = to_query.table to_types = to_query.col_types to_types.keys.sort.each do |k| n += 1 key = "c#{n}" if result.include?(key) results[to_table] ||= {} results[to_table][k] = convert_type(result[key], to_types[k]) end end results end |
.normalize_result(result, col_types) ⇒ Object
Normalizes the Hash result
(of Strings to Strings), with col_types
specifying Symbol column names to String PostgreSQL types.
117 118 119 120 121 122 |
# File 'lib/mao.rb', line 117 def self.normalize_result(result, col_types) Hash[result.map {|k,v| k = k.to_sym [k, convert_type(v, col_types[k])] }] end |
.query(table) ⇒ Object
Returns a new Mao::Query object for table
.
74 75 76 77 |
# File 'lib/mao.rb', line 74 def self.query(table) @queries ||= {} @queries[table] ||= Query.new(table).freeze end |
.quote_ident(name) ⇒ Object
Quote name
as appropriate for a table or column name in an SQL statement.
30 31 32 33 34 35 36 37 |
# File 'lib/mao.rb', line 30 def self.quote_ident(name) case name when Symbol @conn.quote_ident(name.to_s) else @conn.quote_ident(name) end end |
.sql(sql, *args, &block) ⇒ Object
Execute the raw SQL sql
with positional args
. The returned object varies depending on the database vendor.
25 26 27 |
# File 'lib/mao.rb', line 25 def self.sql(sql, *args, &block) @conn.exec(sql, *args, &block) end |
.transaction(&block) ⇒ Object
Executes block
in a transaction.
If block
executes without an exception, the transaction is committed.
If a Mao::Rollback is raised, the transaction is rolled back, and #transaction returns false.
If any other Exception is raised, the transaction is rolled back, and the exception is re-raised.
Otherwise, the transaction is committed, and the result of block
is returned.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/mao.rb', line 95 def self.transaction(&block) return block.call if @in_transaction @in_transaction = true sql("BEGIN") begin r = block.call rescue Rollback sql("ROLLBACK") return false rescue Exception sql("ROLLBACK") raise ensure @in_transaction = false end sql("COMMIT") r end |