bank 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,94 @@
1
+ require 'attr_protected'
2
+ require 'forwardable'
3
+
4
+ require 'bank/sequel'
5
+ require 'bank/collection_config'
6
+ require 'bank/serialize'
7
+
8
+ module Bank
9
+ RecordNotFound = Class.new(RuntimeError)
10
+ UnknownConversionType = Class.new(RuntimeError)
11
+
12
+ class Collection
13
+ class << self
14
+ extend Forwardable
15
+
16
+ def_delegators :db, *DatasetMethods
17
+
18
+ def config
19
+ @_config ||= CollectionConfig.new
20
+ end
21
+
22
+ def db
23
+ Result.new(config.db, self)
24
+ end
25
+
26
+ def scope(name, blk)
27
+ define_singleton_method(name) { |*args| instance_exec *args, &blk }
28
+ end
29
+
30
+ def find_by(key, value)
31
+ where(key => value).first
32
+ end
33
+
34
+ def save(model)
35
+ pkey = config.primary_key
36
+
37
+ if new?(model)
38
+ model.send(:"#{pkey}=", db.insert(Serialize.pack(config, model)))
39
+ else
40
+ db.where(pkey => model.send(pkey)).
41
+ update(Serialize.pack(config, model))
42
+ end
43
+
44
+ return model
45
+ end
46
+
47
+ def create(attrs)
48
+ save(config.model.new(attrs))
49
+ end
50
+
51
+ def update(*args, &blk)
52
+ model = find(*args)
53
+
54
+ blk.call(model)
55
+ save(model)
56
+ model
57
+ end
58
+
59
+ def find(key)
60
+ result = key.nil? ? nil : where(config.primary_key => key).first
61
+
62
+ raise RecordNotFound,
63
+ "no record found in collection with id `#{key.inspect}'" if result.nil?
64
+
65
+ return result
66
+ end
67
+
68
+ def delete(key)
69
+ db.where(config.primary_key => key).delete
70
+ end
71
+
72
+ def convert(attrs)
73
+ case attrs
74
+ when Array
75
+ attrs.map(&method(:convert))
76
+ when Hash
77
+ config.model.new(Serialize.unpack(config, attrs))
78
+ else
79
+ raise UnknownConversionType, "unable to convert #{attrs.inspect}"
80
+ end
81
+ end
82
+
83
+ def join_as(table, *args, &blk)
84
+ select(*config.model._fields.map { |f| :"#{table}__#{f}"}).join(*args, &blk)
85
+ end
86
+
87
+ private
88
+
89
+ def new?(model)
90
+ model.send(config.primary_key).nil?
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,49 @@
1
+ require 'attr_protected'
2
+ require 'bank/database'
3
+
4
+ module Bank
5
+ class CollectionConfig
6
+ attr_protected :_model_block
7
+ attr_writer :packer, :unpacker
8
+
9
+ def model(&block)
10
+ if block_given?
11
+ self._model_block = block
12
+ else
13
+ @_model ||= _model_block.call
14
+ end
15
+ end
16
+
17
+ def packer
18
+ @packer ||= identity
19
+ end
20
+
21
+ def unpacker
22
+ @unpacker ||= identity
23
+ end
24
+
25
+ def db(&block)
26
+ if block_given?
27
+ @_db_block = block
28
+ @_db = nil
29
+ else
30
+ value = @_db_block.call
31
+ @_db ||= value.is_a?(Symbol) ? Database[value] : value
32
+ end
33
+ end
34
+
35
+ def primary_key(value = nil)
36
+ if value
37
+ @_primary_key = value
38
+ else
39
+ @_primary_key ||= :id
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def identity
46
+ ->(i) { i }
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,23 @@
1
+ require 'attr_protected'
2
+
3
+ require 'bank/result'
4
+
5
+ module Bank
6
+ class Database
7
+ class << self
8
+ attr_protected :db
9
+
10
+ def self.db
11
+ db.dup
12
+ end
13
+
14
+ def use_db(db)
15
+ self.db = db
16
+ end
17
+
18
+ def [](name)
19
+ self.db[name]
20
+ end
21
+ end
22
+ end
23
+ end
data/lib/bank/model.rb ADDED
@@ -0,0 +1,65 @@
1
+ require 'attr_protected'
2
+
3
+ module Bank
4
+ class Model
5
+ class << self
6
+ attr_protected :_fields, :_defaults
7
+
8
+ def fields(*fields)
9
+ attr_accessor *fields
10
+ self._fields = fields
11
+ end
12
+
13
+ def _fields
14
+ @_fields ||= []
15
+ end
16
+
17
+ def defaults(defaults)
18
+ self._defaults = defaults
19
+ end
20
+
21
+ def _defaults
22
+ @_defaults ||= {}
23
+ end
24
+ end
25
+
26
+ def initialize(attrs = {})
27
+ set(attrs)
28
+ _defaults.each { |key, val| set(key, val) if !get(key) }
29
+ end
30
+
31
+ def to_hash
32
+ _fields.reduce({}) do |acc, field|
33
+ acc.merge(field => get(field))
34
+ end
35
+ end
36
+
37
+ def get(attr)
38
+ instance_variable_get(:"@#{attr}")
39
+ end
40
+
41
+ def set(attr, value = nil)
42
+ if attr.is_a?(Hash)
43
+ attr.each { |key, value| set(key, value) }
44
+ else
45
+ public_send(:"#{attr}=", value)
46
+ end
47
+
48
+ return self
49
+ end
50
+
51
+ def ==(other)
52
+ other.is_a?(self.class) && other.to_hash == to_hash
53
+ end
54
+
55
+ private
56
+
57
+ def _fields
58
+ self.class._fields
59
+ end
60
+
61
+ def _defaults
62
+ self.class._defaults
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,61 @@
1
+ require 'attr_protected'
2
+ require 'forwardable'
3
+
4
+ require 'bank/sequel'
5
+
6
+ module Bank
7
+ class Result
8
+ include Enumerable
9
+ extend Forwardable
10
+
11
+ attr_protected :db, :collection
12
+
13
+ def_delegators :db, *[:update, :insert, :delete, :max, :min, :count]
14
+ def_delegators :all, :inspect, :empty?
15
+
16
+ def initialize(db, collection)
17
+ self.db = db
18
+ self.collection = collection
19
+ end
20
+
21
+ def each(&blk)
22
+ raw.each { |result| blk.call(collection.convert(result)) }
23
+ end
24
+
25
+ def raw
26
+ db.all
27
+ end
28
+
29
+ def all
30
+ collection.convert(raw)
31
+ end
32
+
33
+ # db overrides for Enumerable-clashing methods
34
+ def select(*args, &block) new(db.select(*args, &block)) end
35
+ def group_by(*args, &block) new(db.group_by(*args, &block)) end
36
+ def grep(*args, &block) new(db.grep(*args, &block)) end
37
+
38
+ def method_missing(*args, &blk)
39
+ DatasetMethods.include?(args[0]) ? new(db.send(*args, &blk)) : super
40
+ end
41
+
42
+ def respond_to?(method)
43
+ DatasetMethods.include?(method) || super
44
+ end
45
+
46
+ def ==(other)
47
+ self.all == other
48
+ end
49
+ alias_method :eql?, :==
50
+
51
+ def inspect
52
+ all.inspect
53
+ end
54
+
55
+ private
56
+
57
+ def new(db)
58
+ self.class.new(db, collection)
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,17 @@
1
+ module Bank
2
+
3
+ DatasetMethods = [:select, :select_all, :select_append, :select_group,
4
+ :select_more, :join, :left_join, :right_join, :full_join,
5
+ :natural_join, :natural_left_join, :natural_right_join,
6
+ :natural_full_join, :cross_join, :inner_join, :left_outer_join,
7
+ :right_outer_join, :full_outer_join, :join_table, :where, :filter,
8
+ :exclude, :exclude_where, :and, :or, :grep, :invert, :unfiltered,
9
+ :group, :group_by, :group_and_count, :select_group, :ungrouped,
10
+ :having, :exclude_having, :invert, :unfiltered, :order, :order_by,
11
+ :order_append, :order_prepend, :order_more, :reverse, :reverse_order,
12
+ :unordered, :limit, :offset, :unlimited, :union, :intersect, :except,
13
+ :for_update, :lock_style, :with, :with_recursive, :clone, :distinct,
14
+ :naked, :qualify, :server, :with_sql, :count,
15
+ :insert, :update, :delete, :max, :min]
16
+
17
+ end
@@ -0,0 +1,101 @@
1
+ module Bank
2
+ module Serialize
3
+ def self.pack(*args)
4
+ Packer.new(*args).call
5
+ end
6
+
7
+ def self.unpack(*args)
8
+ Unpacker.new(*args).call
9
+ end
10
+
11
+ class Packer
12
+ attr_protected :config, :model
13
+
14
+ def initialize(config, model)
15
+ self.config = config
16
+ self.model = model
17
+ end
18
+
19
+ def call
20
+ attrs = normalize(model.to_hash)
21
+
22
+ config.packer.call(attrs)
23
+ set_timestamps(attrs, model)
24
+
25
+ model.set(Serialize.unpack(config, attrs.dup))
26
+ attrs
27
+ end
28
+
29
+ private
30
+
31
+ def set_timestamps(attrs, model)
32
+ now = Time.now
33
+
34
+ attrs[:updated_at] = now if model.respond_to?(:updated_at=)
35
+ attrs[:created_at] = now if model.respond_to?(:created_at=) &&
36
+ !model.send(config.primary_key)
37
+ end
38
+
39
+ def normalize(attrs)
40
+ attrs = attrs.dup
41
+
42
+ columns.select { |column, opts|
43
+ !attrs[column].nil? && opts[:type] == :integer
44
+ }.each { |column, opts| attrs[column] = attrs[column].to_i }
45
+
46
+ columns.select { |column, opts|
47
+ !attrs[column].nil? && opts[:type] == :boolean
48
+ }.each { |column, opts| attrs[column] = attrs[column] ? 1 : 0 }
49
+
50
+ attrs
51
+ end
52
+
53
+ def columns
54
+ @columns ||= Database.db.schema(config.db)
55
+ end
56
+ end
57
+
58
+ class Unpacker
59
+ attr_protected :config, :attrs
60
+
61
+ def initialize(config, attrs)
62
+ self.config = config
63
+ self.attrs = attrs
64
+ end
65
+
66
+ def call
67
+ columns.select { |column, opts|
68
+ opts[:type] == :datetime && ![nil, 0].include?(attrs[column])
69
+ }.each { |column, opts| attrs[column] = drop_usecs(attrs[column]) }
70
+
71
+ columns.select { |column, opts|
72
+ opts[:type] == :date && ![nil, 0].include?(attrs[column])
73
+ }.each { |column, opts|
74
+ attrs[column] = Date.parse(attrs[column]) if attrs[column].is_a?(String)
75
+ }
76
+
77
+ columns.select { |column, opts|
78
+ !attrs[column].nil? && opts[:type] == :boolean
79
+ }.each { |column, opts| attrs[column] = [1, true].include?(attrs[column]) }
80
+
81
+ config.unpacker.call(attrs)
82
+ attrs
83
+ end
84
+
85
+ def drop_usecs(time)
86
+ if time.is_a?(String)
87
+ Time.at(Time.parse(time).to_i)
88
+ elsif time.is_a?(DateTime)
89
+ Time.at(time.to_time.to_i)
90
+ else
91
+ Time.at(time.to_i)
92
+ end
93
+ end
94
+
95
+ def columns
96
+ @columns ||= Database.db.schema(config.db)
97
+ end
98
+ end
99
+
100
+ end
101
+ end
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bank
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.8
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Brian Pratt
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-04-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: sequel
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '4.7'
22
+ - - ! '>='
23
+ - !ruby/object:Gem::Version
24
+ version: 4.7.0
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '4.7'
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: 4.7.0
36
+ - !ruby/object:Gem::Dependency
37
+ name: attr_protected
38
+ requirement: !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '1.0'
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: 1.0.0
47
+ type: :runtime
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: 1.0.0
58
+ - !ruby/object:Gem::Dependency
59
+ name: rake
60
+ requirement: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: '10.1'
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: 10.1.1
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: '10.1'
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: 10.1.1
80
+ - !ruby/object:Gem::Dependency
81
+ name: rspec
82
+ requirement: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ version: '2.14'
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: 2.14.1
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ~>
97
+ - !ruby/object:Gem::Version
98
+ version: '2.14'
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: 2.14.1
102
+ description: wraps Sequel to provide a non-ORM data-mapping interface
103
+ email: brian@8thlight.com
104
+ executables: []
105
+ extensions: []
106
+ extra_rdoc_files: []
107
+ files:
108
+ - lib/bank/collection.rb
109
+ - lib/bank/collection_config.rb
110
+ - lib/bank/database.rb
111
+ - lib/bank/model.rb
112
+ - lib/bank/result.rb
113
+ - lib/bank/sequel.rb
114
+ - lib/bank/serialize.rb
115
+ homepage: https://github.com/pratt121/bank
116
+ licenses:
117
+ - WTFPL
118
+ post_install_message:
119
+ rdoc_options: []
120
+ require_paths:
121
+ - lib
122
+ required_ruby_version: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ required_rubygems_version: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project:
136
+ rubygems_version: 1.8.23.2
137
+ signing_key:
138
+ specification_version: 3
139
+ summary: simple interface for persistence built on Sequel
140
+ test_files: []