Class: Kaisoku::TestMap

Inherits:
Object
  • Object
show all
Includes:
DependencyQueries, Health, HotFiles, Snapshot, Stats
Defined in:
lib/kaisoku/test_map.rb,
lib/kaisoku/test_map/stats.rb,
lib/kaisoku/test_map/health.rb,
lib/kaisoku/test_map/schema.rb,
lib/kaisoku/test_map/snapshot.rb,
lib/kaisoku/test_map/hot_files.rb,
lib/kaisoku/test_map/dependency_queries.rb

Defined Under Namespace

Modules: DependencyQueries, Health, HotFiles, Schema, Snapshot, Stats

Constant Summary collapse

SCHEMA_VERSION =
'1'

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Stats

#stats

Methods included from Snapshot

#export_json, #import_json

Methods included from HotFiles

#hot_files

Methods included from Health

#health_warnings

Methods included from DependencyQueries

#checksums_for_file, #dependencies_for, #dependency_entity_count, #entities_for_changed_files, #entities_for_dependency_keys, #entities_with_dependency_prefixes, #method_checksums_for_file

Constructor Details

#initialize(path: nil, configuration: Configuration.new) ⇒ TestMap

Returns a new instance of TestMap.



23
24
25
26
27
28
29
30
31
32
# File 'lib/kaisoku/test_map.rb', line 23

def initialize(path: nil, configuration: Configuration.new)
  @configuration = configuration
  @path = path || configuration.map_path

  FileUtils.mkdir_p(File.dirname(@path))
  @db = SQLite3::Database.new(@path)
  @db.results_as_hash = true
  Schema.setup(@db)
  Schema.(@db, adapter: configuration.adapter, configuration: configuration)
end

Instance Attribute Details

#configurationObject (readonly)

Returns the value of attribute configuration.



21
22
23
# File 'lib/kaisoku/test_map.rb', line 21

def configuration
  @configuration
end

#pathObject (readonly)

Returns the value of attribute path.



21
22
23
# File 'lib/kaisoku/test_map.rb', line 21

def path
  @path
end

Instance Method Details

#all_entities(adapter: nil) ⇒ Object



97
98
99
100
101
102
103
104
105
# File 'lib/kaisoku/test_map.rb', line 97

def all_entities(adapter: nil)
  rows = if adapter
           @db.execute('SELECT * FROM entities WHERE adapter = ? ORDER BY file ASC, identifier ASC', [adapter.to_s])
         else
           @db.execute('SELECT * FROM entities ORDER BY adapter ASC, file ASC, identifier ASC')
         end

  rows.map { |row| entity_from_row(row) }
end

#clear!Object



137
138
139
140
141
142
# File 'lib/kaisoku/test_map.rb', line 137

def clear!
  @db.transaction do
    @db.execute('DELETE FROM deps')
    @db.execute('DELETE FROM entities')
  end
end

#empty?Boolean

Returns:

  • (Boolean)


133
134
135
# File 'lib/kaisoku/test_map.rb', line 133

def empty?
  @db.get_first_value('SELECT COUNT(*) FROM entities').to_i.zero?
end

#entities_for_test_files(paths, adapter: nil) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/kaisoku/test_map.rb', line 79

def entities_for_test_files(paths, adapter: nil)
  files = paths.map { |path| configuration.relative_path(path) }.uniq
  return [] if files.empty?

  adapter_clause = adapter ? 'AND adapter = ?' : ''
  bind = adapter ? files + [adapter.to_s] : files

  sql = <<~SQL
    SELECT *
    FROM entities
    WHERE file IN (#{placeholders(files)})
    #{adapter_clause}
    ORDER BY file ASC, identifier ASC
  SQL

  @db.execute(sql, bind).map { |row| entity_from_row(row) }
end

#failed_entities(adapter: nil) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/kaisoku/test_map.rb', line 107

def failed_entities(adapter: nil)
  if adapter
    sql = <<~SQL
      SELECT * FROM entities WHERE adapter = ? AND last_status = 'failed'
      ORDER BY last_failed_at DESC, file ASC
    SQL
    rows = @db.execute(sql, [adapter.to_s])
  else
    sql = <<~SQL
      SELECT * FROM entities WHERE last_status = 'failed'
      ORDER BY last_failed_at DESC, file ASC
    SQL
    rows = @db.execute(sql)
  end

  rows.map { |row| entity_from_row(row) }
end

#known_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


125
126
127
128
129
130
131
# File 'lib/kaisoku/test_map.rb', line 125

def known_file?(path)
  file = configuration.relative_path(path)
  dep_count = @db.get_first_value('SELECT COUNT(*) FROM deps WHERE dep_file = ?', [file])
  entity_count = @db.get_first_value('SELECT COUNT(*) FROM entities WHERE file = ?', [file])

  dep_count.to_i.positive? || entity_count.to_i.positive?
end

#replace_dependencies(entity, dependencies, granularity: 'file') ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/kaisoku/test_map.rb', line 63

def replace_dependencies(entity, dependencies, granularity: 'file')
  normalized = dependencies.to_h.transform_keys { |file| configuration.relative_path(file) }

  @db.transaction do
    id = upsert_entity(entity)
    @db.execute('DELETE FROM deps WHERE entity_id = ? AND granularity = ?', [id, granularity])

    normalized.each do |file, checksum|
      @db.execute(
        'INSERT INTO deps (entity_id, dep_file, checksum, granularity) VALUES (?, ?, ?, ?)',
        [id, file, checksum, granularity]
      )
    end
  end
end

#upsert_entity(entity) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/kaisoku/test_map.rb', line 34

def upsert_entity(entity)
  sql = <<~SQL
    INSERT INTO entities (adapter, identifier, file, line, avg_duration_ms, last_status, last_failed_at, failure_count)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?)
    ON CONFLICT(adapter, identifier) DO UPDATE SET
      file = excluded.file,
      line = excluded.line,
      avg_duration_ms = COALESCE(excluded.avg_duration_ms, entities.avg_duration_ms),
      last_status = COALESCE(excluded.last_status, entities.last_status),
      last_failed_at = COALESCE(excluded.last_failed_at, entities.last_failed_at),
      failure_count = excluded.failure_count
  SQL
  @db.execute(
    sql,
    [
      entity.adapter,
      entity.identifier,
      entity.file,
      entity.line,
      entity.avg_duration_ms,
      entity.last_status,
      entity.last_failed_at,
      entity.failure_count
    ]
  )

  entity_id(entity)
end