Guest User

Untitled

a guest
Feb 20th, 2018
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.58 KB | None | 0 0
  1. require 'date'
  2. require 'time'
  3.  
  4. #
  5. # General example, these would be types that would exist in DBI proper
  6. #
  7.  
  8. module DBI
  9. class DBI::Type
  10. def self.parse(obj, type=nil, dbh=nil)
  11. if type
  12. sym = ( "to_" + type.to_s ).to_sym
  13. begin
  14. return self.__send__(sym, obj)
  15. rescue ::NoMethodError
  16. self.to_type(obj)
  17. end
  18. else
  19. return self.to_type(obj)
  20. end
  21. end
  22.  
  23. def self.coerce(obj, type=nil, dbh=nil)
  24. if type
  25. sym = ( "from_" + type.to_s ).to_sym
  26. begin
  27. return self.__send__(sym, obj)
  28. rescue ::NoMethodError
  29. self.from_type(obj)
  30. end
  31. else
  32. return self.from_type(obj)
  33. end
  34. end
  35.  
  36. def self.from_type(obj)
  37. obj.to_s rescue obj.to_str rescue obj
  38. end
  39.  
  40. def self.to_type(obj)
  41. obj
  42. end
  43. end
  44.  
  45. class DBI::Type::Null < DBI::Type
  46. def self.to_type(obj)
  47. return obj unless obj
  48. return nil if obj.to_s.match(/^null$/i)
  49. return obj
  50. end
  51.  
  52. def self.from_type(obj)
  53. obj
  54. end
  55. end
  56.  
  57. class DBI::Type::Integer < DBI::Type::Null
  58. def self.parse(obj)
  59. obj = super
  60. return obj unless obj
  61. return obj.to_i if obj.respond_to? :to_i
  62. return obj
  63. end
  64. end
  65.  
  66. class DBI::Type::Timestamp < DBI::Type::Null
  67. def self.to_type(obj)
  68. obj = super
  69. return obj unless obj
  70.  
  71. case obj
  72. when ::DateTime
  73. return obj
  74. when ::Date
  75. return ::DateTime.strptime(obj.to_s, "%Y-%m-%d")
  76. when ::Time
  77. return ::DateTime.parse(obj.to_s)
  78. when ::Integer
  79. return ::DateTime.parse(::Time.at(obj).to_s)
  80. else
  81. return ::DateTime.parse(obj.to_s) if obj.respond_to? :to_s
  82. return ::DateTime.parse(obj.to_str) if obj.respond_to? :to_str
  83. return obj
  84. end
  85. end
  86.  
  87. def self.from_type(obj)
  88. obj = super
  89. return obj unless obj
  90.  
  91. case obj
  92. when ::DateTime
  93. return obj.to_s # produces ISO8601
  94. when ::Time
  95. return obj.iso8601
  96. when ::Integer
  97. return ::Time.at(obj).iso8601
  98. else
  99. return obj
  100. end
  101. end
  102. end
  103. end
  104.  
  105. module DBI::DBD
  106. class Pg
  107.  
  108. #
  109. # during connect time, after DatabaseHandle initialization, the hash
  110. # that DatabaseHandle#type_map provides would be tweaked to take
  111. # advantage of the available date formats.
  112. #
  113. # See 'PgDatabaseHandle' below for a mock.
  114. #
  115.  
  116. class Type
  117. class Timestamp < DBI::Type::Timestamp
  118. def self.from_dmy(obj)
  119. return obj if DBI::Type::Null.parse(obj).nil?
  120.  
  121. case obj
  122. when ::DateTime, ::Time
  123. obj.strftime("%d/%m/%Y %H:%M:%S")
  124. when ::Integer
  125. ::Time.at(obj).strftime("%d/%m/%Y %H:%M:%S")
  126. else
  127. # punt... this will actually try the baseline
  128. # conversion at this point
  129. raise "Crap!"
  130. end
  131. end
  132.  
  133. def self.to_dmy(obj)
  134. return obj if DBI::Type::Null.parse(obj).nil?
  135.  
  136. # realistically all there needs to be is a check for the
  137. # type ruby-pg typically returns and string, but to be
  138. # complete I'm showing how it could be done if the type was
  139. # less clear.
  140.  
  141. case obj
  142. when ::DateTime
  143. return obj
  144. when ::Time
  145. return ::DateTime.parse(obj.to_s)
  146. else
  147. return ::DateTime.strptime(obj, "%d/%m/%Y %H:%M:%S")
  148. end
  149. end
  150. end
  151. end
  152. end
  153. end
  154.  
  155. #
  156. # this is just used to emulate the methods a DatabaseHandle would have to
  157. # faciliate this.. certainly not a full (or correct) mirroring of the DBI API.
  158. #
  159. class DatabaseHandle
  160.  
  161. attr_accessor :columns
  162.  
  163. def outbound_type_map
  164. {
  165. 'timestamp' => [DBI::Type::Timestamp]
  166. }
  167. end
  168.  
  169. def inbound_type_map
  170. {
  171. ::DateTime => [DBI::Type::Timestamp],
  172. ::Time => [DBI::Type::Timestamp]
  173. }
  174. end
  175.  
  176. # humor me while I completely break DBI for the sake of brevity..
  177. def execute(*bindvars)
  178. bindvars.collect do |var|
  179. type_info = inbound_type_map[var.class]
  180. type_info[0].coerce(var, type_info[1], self)
  181. end
  182. end
  183.  
  184. def fetch(*bindvars)
  185. ret = []
  186.  
  187. bindvars.each_with_index do |var, i|
  188. type_info = outbound_type_map[columns[i]]
  189. ret.push type_info[0].parse(var, type_info[1], self)
  190. end
  191.  
  192. return ret
  193. end
  194. end
  195.  
  196. class PgDatabaseHandle < DatabaseHandle
  197. def outbound_type_map
  198. {
  199. 'timestamp' => [DBI::DBD::Pg::Type::Timestamp, :dmy]
  200. }
  201. end
  202.  
  203. def inbound_type_map
  204. {
  205. ::DateTime => [DBI::DBD::Pg::Type::Timestamp, :dmy],
  206. ::Time => [DBI::DBD::Pg::Type::Timestamp, :dmy]
  207. }
  208. end
  209. end
  210.  
  211. # ok! now for the functional example:
  212.  
  213. if __FILE__ == $0
  214.  
  215. dbh = DatabaseHandle.new
  216. dbh.columns = %w(timestamp timestamp)
  217. # this would go TO the database..
  218. p dbh.execute(DateTime.now, Time.now)
  219. # this would come FROM the database...
  220. p dbh.fetch(Time.now.iso8601, DateTime.now.to_s)
  221.  
  222. # now the Pg example:
  223. dbh = PgDatabaseHandle.new
  224. dbh.columns = %w(timestamp timestamp)
  225.  
  226. # this would go TO the database..
  227. p dbh.execute(DateTime.now, Time.now)
  228. # this would come FROM the database...
  229. p dbh.fetch(Time.now.strftime("%d/%m/%Y %H:%M:%S"), DateTime.now.strftime("%d/%m/%Y %H:%M:%S"))
  230.  
  231. # this should fail appropriately
  232. begin
  233. dbh.fetch(Time.now.iso8601, DateTime.now.to_s)
  234. rescue Exception
  235. puts "this failed like it should"
  236. end
  237. end
Add Comment
Please, Sign In to add comment