Files
rubbs/lib/bbs/store.rb
2026-05-12 22:15:07 +02:00

95 lines
1.9 KiB
Ruby

# frozen_string_literal: true
require 'csv'
require 'fileutils'
require 'time'
module BBS
class Store
attr_reader :headers, :path
def initialize(path:, headers:)
@path = path
@headers = headers
@mutex = Mutex.new
@rows = nil
end
def upsert(session_id:, **fields)
@mutex.synchronize do
load_rows!
row = @rows.find { |r| r['session_id'] == session_id }
if row
fields.each { |k, v| row[k.to_s] = v.to_s }
flush!
else
@rows << build_row(session_id, fields)
append_row(@rows.last)
end
end
self
end
def find(session_id)
@mutex.synchronize do
load_rows!
row = @rows.find { |r| r['session_id'] == session_id }
row ? row.to_h : nil
end
end
def all
@mutex.synchronize do
load_rows!
@rows.map(&:to_h)
end
end
def delete(session_id)
@mutex.synchronize do
load_rows!
removed = @rows.reject! { |r| r['session_id'] == session_id }
flush! if removed
end
end
private
def load_rows!
return @rows if @rows
ensure_file!
table = CSV.read(@path, headers: true)
@rows = table.map { |row| row }
end
def build_row(session_id, fields)
values = @headers.map do |h|
case h
when 'session_id' then session_id
when 'timestamp' then Time.now.utc.iso8601
else fields[h.to_sym]&.to_s
end
end
CSV::Row.new(@headers, values)
end
def append_row(row)
CSV.open(@path, 'a') { |csv| csv << row.fields }
end
def flush!
CSV.open(@path, 'w') do |csv|
csv << @headers
@rows.each { |r| csv << r.fields }
end
end
def ensure_file!
FileUtils.mkdir_p(File.dirname(@path))
return if File.exist?(@path)
CSV.open(@path, 'w') { |csv| csv << @headers }
end
end
end