bloc_record 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bbb82ba853b6d915d4868349bbc263eaec960c6e
4
+ data.tar.gz: d94682d9e695a4860f9926adf8b684779f983acd
5
+ SHA512:
6
+ metadata.gz: f9aae1a6d31f0d23edf0e16f51857859dc99806bd38a021e3bb26248f8bf103a2f23bb00c66b12a98c5f0c3739f8495e6d96eee2895ec25c8a4adb1fe09e5a9d
7
+ data.tar.gz: 354f204cd1abfb07cbf3589834d28fab8bec0388775a77e70f80931c8d499a3ce13bb8d1cdf521081315bb37c9b1a156a3e87763bf21151e158dae1c21bfa409
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ (under construction)
2
+
3
+ How to use:
4
+
5
+ 1) Clone and bundle install
6
+
7
+ 2) Use with [AddressBlocWithDB](https://github.com/Bloc/address-bloc-with-db). It's already got the database ready to go. Then write a driver file like:
8
+
9
+ ```ruby
10
+ require_relative 'models/address_book'
11
+ require_relative 'models/entry'
12
+ require 'bloc_record'
13
+
14
+ BlocRecord.connect_to("db/address_bloc.db")
15
+
16
+ AddressBook.create(name: "My Addressbook")
17
+
18
+ entry = Entry.new(name: "ben neely", phone: "208-350-8855", email: "Ben@bloc.io")
19
+ entry.save!
20
+
21
+ book = AddressBook.new
22
+ book.name = "BLAAAA"
23
+ book.save!
24
+
25
+
26
+ p Entry.find(entry.id)
27
+ p AddressBook.take(5)
28
+ ```
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'bloc_record'
3
+ s.version = '0.0.0'
4
+ s.date = '2015-12-02'
5
+ s.summary = 'An ActiveRecord-esque ORM adaptor'
6
+ s.description = 'An ActiveRecord-esque ORM adaptor'
7
+ s.authors = ['Ben Neely']
8
+ s.email = 'ben@bloc.io'
9
+ s.files = `git ls-files`.split($/)
10
+ s.executables = s.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
11
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
12
+ s.require_paths = ["lib"]
13
+ s.homepage =
14
+ 'http://rubygems.org/gems/bloc_record'
15
+ s.license = 'MIT'
16
+ s.add_runtime_dependency 'sqlite3', '~> 1.3'
17
+ s.add_runtime_dependency 'activesupport'
18
+ end
@@ -0,0 +1,39 @@
1
+ require 'sqlite3'
2
+ require 'active_support/inflector'
3
+
4
+ module Associations
5
+ def has_many(association)
6
+ self.send(:define_method, association) do
7
+ rows = self.class.connection.execute <<-SQL
8
+ SELECT * FROM #{association.to_s.singularize}
9
+ WHERE #{self.class.table}_id = #{self.id}
10
+ SQL
11
+
12
+ class_name = association.to_s.classify.constantize
13
+ collection = BlocRecord::Collection.new
14
+
15
+ rows.each do |row|
16
+ collection << class_name.new(Hash[class_name.columns.zip(row)])
17
+ end
18
+
19
+ collection
20
+ end
21
+ end
22
+
23
+ def belongs_to(association)
24
+ self.send(:define_method, association) do
25
+ association_name = association.to_s
26
+ row = self.class.connection.get_first_row <<-SQL
27
+ SELECT * FROM #{association_name}
28
+ WHERE id = #{self.send(association_name + "_id")}
29
+ SQL
30
+
31
+ class_name = association_name.classify.constantize
32
+
33
+ if row
34
+ data = Hash[class_name.columns.zip(row)]
35
+ class_name.new(data)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ require 'bloc_record/utility'
2
+ require 'bloc_record/schema'
3
+ require 'bloc_record/persistence'
4
+ require 'bloc_record/selection'
5
+ require 'bloc_record/connection'
6
+ require 'bloc_record/collection'
7
+ require 'bloc_record/associations'
8
+
9
+ module BlocRecord
10
+ class Base
11
+ include Persistence
12
+ extend Selection
13
+ extend Schema
14
+ extend Connection
15
+ extend Associations
16
+
17
+ def initialize(options={})
18
+ options = BlocRecord::Utility.convert_keys(options)
19
+
20
+ self.class.columns.each do |col|
21
+ self.class.send(:attr_accessor, col)
22
+ self.instance_variable_set("@#{col}", options[col])
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ module BlocRecord
2
+ class Collection < Array
3
+ def update_all(updates)
4
+ ids = self.map(&:id)
5
+ self.any? ? self.first.class.update(ids, updates) : false
6
+ end
7
+
8
+ def group(*args)
9
+ ids = self.map(&:id)
10
+ self.any? ? self.first.class.group_by_ids(ids, args) : false
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ require 'sqlite3'
2
+
3
+ module Connection
4
+ def connection
5
+ @connection ||= SQLite3::Database.new(BlocRecord.databese_filename)
6
+ end
7
+ end
@@ -0,0 +1,115 @@
1
+ require 'sqlite3'
2
+ require 'bloc_record/schema'
3
+
4
+ module Persistence
5
+ def self.included(base)
6
+ base.extend(ClassMethods)
7
+ end
8
+
9
+ module ClassMethods
10
+ def create(attrs)
11
+ attrs = BlocRecord::Utility.convert_keys(attrs)
12
+ attrs.delete "id"
13
+ vals = attributes.map { |key| BlocRecord::Utility.sql_strings(attrs[key]) }
14
+
15
+ connection.execute(
16
+ "INSERT INTO #{table} (#{attributes.join(",")}) VALUES (?)",
17
+ vals.join(",")
18
+ )
19
+
20
+ data = Hash[attributes.zip attrs.values]
21
+ data["id"] = connection.execute("SELECT last_insert_rowid();")[0][0]
22
+ new(data)
23
+ end
24
+
25
+ def update(ids, updates)
26
+ updates = BlocRecord::Utility.convert_keys(updates)
27
+ updates.delete "id"
28
+ updates_array = updates.keys.map { |key| "#{key} = ?" }
29
+ if ids.class == Fixnum
30
+ where_clause = "WHERE id = #{ids};"
31
+ elsif ids.class == Array
32
+ where_clause = ids.empty? ? ";" : "WHERE id IN (#{ids.join(",")});"
33
+ else
34
+ where_clause = ";"
35
+ end
36
+
37
+ connection.execute(
38
+ "UPDATE #{table} SET #{updates_array.join(", ")} #{where_clause}",
39
+ updates.values
40
+ )
41
+
42
+ true
43
+ end
44
+
45
+ def update_all(updates)
46
+ update(nil, updates)
47
+ end
48
+
49
+ def destroy(*id)
50
+ if id.length > 1
51
+ where_clause = "WHERE id IN (#{id.join(",")});"
52
+ else
53
+ where_clause = "WHERE id = #{id.first};"
54
+ end
55
+
56
+ connection.execute <<-SQL
57
+ DELETE FROM #{table} #{where_clause}
58
+ SQL
59
+
60
+ true
61
+ end
62
+
63
+ def destroy_all(conditions_hash=nil)
64
+ if conditions_hash && !conditions_hash.empty?
65
+ conditions_hash = BlocRecord::Utility.convert_keys(conditions_hash)
66
+ conditions = conditions_hash.keys.map { |key| "#{key} = ?" }.join(" and ")
67
+
68
+ connection.execute(
69
+ "DELETE FROM #{table} WHERE #{conditions};",
70
+ conditions_hash.values
71
+ )
72
+ else
73
+ connection.execute <<-SQL
74
+ DELETE FROM #{table}
75
+ SQL
76
+ end
77
+
78
+ true
79
+ end
80
+ end
81
+
82
+ def save!
83
+ unless self.id
84
+ self.id = self.class.create(BlocRecord::Utility.instance_variables_to_hash(self)).id
85
+ BlocRecord::Utility.reload_obj(self)
86
+ return true
87
+ end
88
+
89
+ fields = self.class.attributes.map { |col| "#{col}=#{BlocRecord::Utility.sql_strings(self.instance_variable_get("@#{col}"))}" }.join(",")
90
+
91
+ self.class.connection.execute <<-SQL
92
+ UPDATE #{self.class.table}
93
+ SET #{fields}
94
+ WHERE id = #{self.id};
95
+ SQL
96
+
97
+ true
98
+ end
99
+
100
+ def save
101
+ self.save! rescue false
102
+ end
103
+
104
+ def update_attribute(attribute, value)
105
+ self.class.update(self.id, { attribute => value })
106
+ end
107
+
108
+ def update_attributes(updates)
109
+ self.class.update(self.id, updates)
110
+ end
111
+
112
+ def destroy
113
+ self.class.destroy(self.id)
114
+ end
115
+ end
@@ -0,0 +1,32 @@
1
+ require 'sqlite3'
2
+ require 'bloc_record/utility'
3
+
4
+ module Schema
5
+ def table
6
+ BlocRecord::Utility.underscore(name)
7
+ end
8
+
9
+ def columns
10
+ schema.keys
11
+ end
12
+
13
+ def attributes
14
+ columns - ["id"]
15
+ end
16
+
17
+ def schema
18
+ unless @schema
19
+ @schema = {}
20
+ connection.table_info(table) do |col|
21
+ @schema[col["name"]] = col["type"]
22
+ end
23
+ end
24
+ @schema
25
+ end
26
+
27
+ def count
28
+ connection.execute(<<-SQL)[0][0]
29
+ SELECT COUNT(*) FROM #{table}
30
+ SQL
31
+ end
32
+ end
@@ -0,0 +1,199 @@
1
+ require 'sqlite3'
2
+
3
+ module Selection
4
+ def find(*ids)
5
+
6
+ if ids.length == 1
7
+ find_one(ids.first)
8
+ else
9
+ rows = connection.execute <<-SQL
10
+ SELECT #{columns.join ","} FROM #{table}
11
+ WHERE id IN (#{ids.join(",")});
12
+ SQL
13
+
14
+ rows_to_array(rows)
15
+ end
16
+ end
17
+
18
+ def find_one(id)
19
+ row = connection.get_first_row <<-SQL
20
+ SELECT #{columns.join ","} FROM #{table}
21
+ WHERE id = #{id};
22
+ SQL
23
+
24
+ init_object_from_row(row)
25
+ end
26
+
27
+ def find_by(attribute, value)
28
+ row = connection.get_first_row(
29
+ "SELECT #{columns.join ","} FROM #{table} WHERE #{attribute} = ?;",
30
+ BlocRecord::Utility.sql_strings(value)
31
+ )
32
+
33
+ init_object_from_row(row)
34
+ end
35
+
36
+ def take(num=1)
37
+ if num > 1
38
+ rows = connection.execute(
39
+ "SELECT #{columns.join ","} FROM #{table} ORDER BY random() LIMIT ?;",
40
+ num
41
+ )
42
+
43
+ rows_to_array(rows)
44
+ else
45
+ take_one
46
+ end
47
+ end
48
+
49
+ def take_one
50
+ row = connection.get_first_row <<-SQL
51
+ SELECT #{columns.join ","} FROM #{table}
52
+ ORDER BY random()
53
+ LIMIT 1;
54
+ SQL
55
+
56
+ init_object_from_row(row)
57
+ end
58
+
59
+ def first
60
+ row = connection.get_first_row <<-SQL
61
+ SELECT #{columns.join ","} FROM #{table}
62
+ ORDER BY id
63
+ ASC LIMIT 1;
64
+ SQL
65
+
66
+ init_object_from_row(row)
67
+ end
68
+
69
+ def last
70
+ row = connection.get_first_row <<-SQL
71
+ SELECT #{columns.join ","} FROM #{table}
72
+ ORDER BY id
73
+ DESC LIMIT 1;
74
+ SQL
75
+
76
+ init_object_from_row(row)
77
+ end
78
+
79
+ def all
80
+ rows = connection.execute <<-SQL
81
+ SELECT #{columns.join ","} FROM #{table};
82
+ SQL
83
+
84
+ rows_to_array(rows)
85
+ end
86
+
87
+ def where(*args)
88
+ if args.count > 1
89
+ expression = args.shift
90
+ params = args
91
+ else
92
+ case args.first
93
+ when String
94
+ expression = "?"
95
+ params = args.first
96
+ when Hash
97
+ params = BlocRecord::Utility.convert_keys(args.first)
98
+ expression = params.keys.map {|key| "#{key}=:#{key}"}.join(" and ")
99
+ end
100
+ end
101
+
102
+ sql = <<-SQL
103
+ SELECT #{columns.join ","} FROM #{table}
104
+ WHERE #{expression};
105
+ SQL
106
+
107
+ rows = connection.execute(sql, params)
108
+ rows_to_array(rows)
109
+ end
110
+
111
+ def order(*args)
112
+ if args.count > 1
113
+ order = args.join(",")
114
+ else
115
+ order = args.first.to_s
116
+ end
117
+ rows = connection.execute(
118
+ "SELECT * FROM #{table} ORDER BY ?;",
119
+ order
120
+ )
121
+ rows_to_array(rows)
122
+ end
123
+
124
+ def join(*args)
125
+ if args.count > 1
126
+ joins = args.map { |arg| "INNER JOIN #{arg} ON #{arg}.#{table}_id = #{table}.id"}.join(" ")
127
+ rows = connection.execute <<-SQL
128
+ SELECT * FROM #{table} #{joins}
129
+ SQL
130
+ else
131
+ case args.first
132
+ when String
133
+ rows = connection.execute <<-SQL
134
+ SELECT * FROM #{table} #{BlocRecord::Utility.sql_strings(args.first)};
135
+ SQL
136
+ when Symbol
137
+ rows = connection.execute <<-SQL
138
+ SELECT * FROM #{table}
139
+ INNER JOIN #{args.first} ON #{args.first}.#{table}_id = #{table}.id
140
+ SQL
141
+ end
142
+ end
143
+ rows_to_array(rows)
144
+ end
145
+
146
+ def select(*fields)
147
+ rows = connection.execute(
148
+ "SELECT ? FROM #{table};",
149
+ fields.join(", ")
150
+ )
151
+ collection = BlocRecord::Collection.new
152
+ rows.each { |row| collection << new(Hash[fields.zip(row)]) }
153
+ collection
154
+ end
155
+
156
+ def limit(value, offset=0)
157
+ rows = connection.execute(
158
+ "SELECT * FROM #{table} LIMIT ? OFFSET ?;",
159
+ [value, offset]
160
+ )
161
+ rows_to_array(rows)
162
+ end
163
+
164
+ def group(*args)
165
+ group_by_ids(nil, args)
166
+ end
167
+
168
+ def group_by_ids(ids, args)
169
+ if args.count > 1
170
+ conditions = args.join(", ")
171
+ else
172
+ conditions = args.first
173
+ end
174
+
175
+ where_clause = ids.nil? ? "" : "WHERE id IN (#{ids.join(",")})"
176
+
177
+ rows = connection.execute(
178
+ "SELECT * FROM #{table} #{where_clause} GROUP BY ?;",
179
+ conditions.to_s
180
+ )
181
+
182
+ rows_to_array(rows)
183
+ end
184
+
185
+ private
186
+
187
+ def init_object_from_row(row)
188
+ if row
189
+ data = Hash[columns.zip(row)]
190
+ new(data)
191
+ end
192
+ end
193
+
194
+ def rows_to_array(rows)
195
+ collection = BlocRecord::Collection.new
196
+ rows.each { |row| collection << new(Hash[columns.zip(row)]) }
197
+ collection
198
+ end
199
+ end
@@ -0,0 +1,39 @@
1
+ module BlocRecord
2
+ module Utility
3
+ extend self
4
+
5
+ def underscore(camel_cased_word)
6
+    string = camel_cased_word.gsub(/::/, '/')
7
+    string.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
8
+    string.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
9
+    string.tr!("-", "_")
10
+    string.downcase
11
+ end
12
+ def sql_strings(value)
13
+ case value
14
+ when String
15
+ "'#{value}'"
16
+ when Numeric
17
+ value.to_s
18
+ else
19
+ "null"
20
+ end
21
+ end
22
+
23
+ def convert_keys(options)
24
+ options.keys.each {|k| options[k.to_s] = options.delete(k) if k.kind_of?(Symbol)}
25
+ options
26
+ end
27
+
28
+ def instance_variables_to_hash(obj)
29
+ Hash[obj.instance_variables.map{ |var| ["#{var.to_s.delete('@')}", obj.instance_variable_get(var.to_s)]}]
30
+ end
31
+
32
+ def reload_obj(dirty_obj)
33
+ persisted_obj = dirty_obj.class.find_one(dirty_obj.id)
34
+ dirty_obj.instance_variables.each do |instance_variable|
35
+ dirty_obj.instance_variable_set(instance_variable, persisted_obj.instance_variable_get(instance_variable))
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,9 @@
1
+ module BlocRecord
2
+ def self.connect_to(filename)
3
+ @database_filename = filename
4
+ end
5
+
6
+ def self.databese_filename
7
+ @database_filename
8
+ end
9
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bloc_record
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben Neely
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-12-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: sqlite3
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: An ActiveRecord-esque ORM adaptor
42
+ email: ben@bloc.io
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - README.md
48
+ - bloc_record.gemspec
49
+ - lib/bloc_record.rb
50
+ - lib/bloc_record/associations.rb
51
+ - lib/bloc_record/base.rb
52
+ - lib/bloc_record/collection.rb
53
+ - lib/bloc_record/connection.rb
54
+ - lib/bloc_record/persistence.rb
55
+ - lib/bloc_record/schema.rb
56
+ - lib/bloc_record/selection.rb
57
+ - lib/bloc_record/utility.rb
58
+ homepage: http://rubygems.org/gems/bloc_record
59
+ licenses:
60
+ - MIT
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 2.4.6
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: An ActiveRecord-esque ORM adaptor
82
+ test_files: []