lib/atig/db/followings.rb
# -*- mode:ruby; coding:utf-8 -*-
require 'atig/db/listenable'
require 'atig/db/transaction'
require 'atig/db/sql'
module Atig
module Db
class Followings
include Listenable
include Transaction
def initialize(name)
@db = Sql.new name
unless File.exist? name then
@db.execute do|db|
db.execute %{create table users (
id integer primary key,
screen_name text,
user_id text,
protected bool,
only bool,
data blob);}
db.execute %{
create index users_screen on users (screen_name);
}
end
end
@users = []
@on_invalidated = lambda{}
end
def size
@db.execute do|db|
db.get_first_value('SELECT COUNT(*) FROM users').to_i
end
end
def empty?
@db.execute do|db|
db.get_first_value('SELECT * FROM users LIMIT 1') == nil
end
end
def invalidate
@on_invalidated.call
end
def on_invalidated(&f)
@on_invalidated = f
end
def users
@db.execute{|db|
db.execute("SELECT data FROM users").map{|data|
@db.load data[0]
}
}
end
def exists?(db, templ, *args)
db.get_first_value("SELECT * FROM users WHERE #{templ} LIMIT 1",*args) != nil
end
def may_notify(mode, xs)
unless xs.empty? then
notify mode, xs
end
end
def bool(b)
if b then 1 else 0 end
end
def update(users)
@db.execute do|db|
may_notify :join, users.select{|u|
not exists?(db,
"screen_name = ?",
u.screen_name)
}
names = users.map{|u| u.screen_name.inspect }.join(",")
may_notify :part, db.execute(%{SELECT screen_name,data FROM users
WHERE screen_name NOT IN (#{names})}).map{|_,data|
@db.load(data)
}
db.execute(%{DELETE FROM users
WHERE screen_name NOT IN (#{names})})
may_notify :mode, users.select{|u|
exists?(db,
"screen_name = ? AND (protected != ? OR only != ?)",
u.screen_name, bool(u.protected), bool(u.only))
}
users.each do|user|
id = db.get_first_value('SELECT id FROM users WHERE user_id = ? LIMIT 1', user.id)
if id then
db.execute("UPDATE users SET screen_name = ?, protected = ?, only = ?, data = ? WHERE id = ?",
user.screen_name,
bool(user.protected),
bool(user.only),
@db.dump(user),
id)
else
db.execute("INSERT INTO users
VALUES(NULL, :screen_name, :user_id, :protected, :only, :data)",
screen_name: user.screen_name,
user_id: user.id,
protected: bool(user.protected),
only: bool(user.only),
data: @db.dump(user))
end
end
end
end
def find_by_screen_name(name)
@db.execute do|db|
@db.load db.get_first_value('SELECT data FROM users WHERE screen_name = ? LIMIT 1', name)
end
end
def include?(user)
@db.execute do|db|
exists? db,'user_id = ?', user.id
end
end
end
end
end