Skip to content

Instantly share code, notes, and snippets.

@txus
Created September 4, 2011 19:33
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save txus/1193383 to your computer and use it in GitHub Desktop.
Save txus/1193383 to your computer and use it in GitHub Desktop.
ShitDB - YAML-backed document-oriented database in pure ruby
require 'rubygems'
require 'minitest/spec'
require 'minitest/autorun'
require 'yaml'
class DB
def initialize(name)
@name = File.join(File.dirname(__FILE__), name)
end
def collection(name)
Collection.new(self, name)
end
def file
@file ||= File.exist?(@name) ? YAML.load(File.open(@name)) : {}
end
def persist
File.open(@name, 'w') do |f|
f.write YAML.dump(@file)
end
end
end
class Collection
attr_reader :db
def initialize(db, name)
@db = db
@name = name
@db.file[@name] ||= []
@db.file["_#{@name}_last_id"] ||= 0
end
def persist
@db.persist
end
def get(id)
@db.file[@name].detect do |record|
record[:id] == id
end
end
def put(doc)
new_id = @db.file["_#{@name}_last_id"] + 1
@db.file[@name] << doc.update(:id => new_id)
@db.file["_#{@name}_last_id"] = new_id
end
def all
@db.file[@name]
end
def where(attrs)
@db.file[@name].select do |record|
attrs.map do |attr|
record[attr.first] == attr.last
end.all?{|n| n == true}
end
end
end
require 'fileutils'
describe 'acceptance tests' do
before do
FileUtils.rm('my_db') if File.exist?('my_db')
@users = DB.new('my_db').collection('users')
end
describe 'storage' do
it 'saves records in memory' do
@users.put(:name => 'James')
@users.put(:name => 'John', :age => 30)
users = @users.all.map { |record| record[:name] }
assert_equal 2, users.length
assert_includes users, 'James'
assert_includes users, 'John'
end
it 'does not save them to disk' do
@users.put(:name => 'James')
@users.put(:name => 'John', :age => 30)
persisted = DB.new('my_db').collection('users').all
assert_equal 0, persisted.length
end
it 'persists them when told so' do
@users.put(:name => 'James')
@users.put(:name => 'John', :age => 30)
@users.persist
users = DB.new('my_db').collection('users').all.map { |record| record[:name] }
assert_equal 2, users.length
assert_includes users, 'James'
assert_includes users, 'John'
end
end
describe 'querying' do
before do
@users.put(:name => 'James')
@users.put(:name => 'John', :age => 30)
@users.put(:name => 'Charles', :age => 30)
end
it 'performs simple queries with one condition inefficiently' do
result = @users.where(:age => 30).map { |record| record[:name] }
assert_equal 2, result.length
assert_includes result, 'John'
assert_includes result, 'Charles'
end
it 'performs simple queries with multiple conditions inefficiently' do
result = @users.where(:name => 'Charles', :age => 30).map { |record| record[:name]}
assert_equal 1, result.length
assert_equal 'Charles', result.first
end
it 'retrieves records by id' do
james = @users.get(1)
john = @users.get(2)
charles = @users.get(3)
assert_equal 'James', james[:name]
assert_equal 'John', john[:name]
assert_equal 'Charles', charles[:name]
end
end
describe 'consistency' do
it 'assigns autoincremental ids' do
@users.put(:name => 'James')
@users.put(:name => 'John')
ids = @users.all.map { |record| record[:id] }.compact
assert_equal 2, ids.length
refute_equal ids.first, ids.last
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment