Class: Ductwork::DatabaseClock

Inherits:
Object
  • Object
show all
Defined in:
lib/ductwork/database_clock.rb

Overview

NOTE: these are SQL fragments that resolve against the database server's clock instead of the calling Ruby process's clock. use them in WHERE clauses that compare between a stored timestamp and "now" so that NTP drift between hosts cannot make healthy work look stale (or vice versa)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(column) ⇒ DatabaseClock

Returns a new instance of DatabaseClock.



43
44
45
46
# File 'lib/ductwork/database_clock.rb', line 43

def initialize(column)
  @adapter = Ductwork::Record.connection.adapter_name.downcase
  @column = column
end

Class Method Details

.ago_sql(column, interval) ⇒ Object



9
10
11
# File 'lib/ductwork/database_clock.rb', line 9

def self.ago_sql(column, interval)
  new(column).ago_sql(interval)
end

.nowObject



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/ductwork/database_clock.rb', line 17

def self.now
  adapter = Ductwork::Record.connection.adapter_name.downcase
  sql =
    case adapter
    when /postgresql|cockroach/i
      "SELECT clock_timestamp()"
    when /mysql|trilogy/i
      "SELECT CURRENT_TIMESTAMP(6)"
    when /sqlite/i
      "SELECT strftime('%Y-%m-%d %H:%M:%f', 'now')"
    when /oracle/i
      "SELECT CURRENT_TIMESTAMP FROM dual"
    else
      raise NotImplementedError, "Database clock does not support adapter #{adapter}"
    end
  raw = Ductwork::Record.connection.select_value(sql)

  case raw
  when ::Time, ::DateTime
    raw.in_time_zone
  else
    # NOTE: SQLite returns an ISO-8601 string already expressed in UTC
    ::Time.find_zone!("UTC").parse(raw.to_s)
  end
end

.now_sql(column) ⇒ Object



13
14
15
# File 'lib/ductwork/database_clock.rb', line 13

def self.now_sql(column)
  new(column).now_sql
end

Instance Method Details

#ago_sql(interval) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/ductwork/database_clock.rb', line 48

def ago_sql(interval)
  seconds = interval.to_i

  case adapter
  when /postgresql|cockroach/i
    "#{column} <= clock_timestamp() - INTERVAL '#{seconds} seconds'"
  when /mysql|trilogy/i
    "#{column} <= CURRENT_TIMESTAMP(6) - INTERVAL #{seconds} SECOND"
  when /sqlite/i
    "julianday(#{column}) <= julianday('now', '-#{seconds} seconds')"
  when /oracle/i
    "#{column} <= CURRENT_TIMESTAMP - NUMTODSINTERVAL(#{seconds}, 'SECOND')"
  else
    raise NotImplementedError, "Database clock does not support adapter #{adapter}"
  end
end

#now_sqlObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/ductwork/database_clock.rb', line 65

def now_sql
  case adapter
  when /sqlite/i
    "julianday(#{column}) <= julianday('now')"
  when /mysql|trilogy/i
    "#{column} <= CURRENT_TIMESTAMP(6)"
  when /postgresql|cockroach/i
    "#{column} <= clock_timestamp()"
  when /oracle/i
    "#{column} <= CURRENT_TIMESTAMP"
  else
    raise NotImplementedError, "Database clock does not support adapter #{adapter}"
  end
end