shoden 0.4.0 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 28a3009afa5b70167a8c9128a356002e11224695
4
- data.tar.gz: 77efc3fd3a51f5d98ad27591657e96e56f7b9628
2
+ SHA256:
3
+ metadata.gz: d83a4046d2ee009631a461d017eb91587d878950b5bd2ccdd71caff7d1cbff18
4
+ data.tar.gz: 16d8fd4fd98795d99727440786ef56e7afc5a25b772753831c21dade14cb28c2
5
5
  SHA512:
6
- metadata.gz: 0ae31056c6817127730fdebeddd82ecf8cbff424c9dbedef97dd1674825a421c4b9725670ddaf5094828703fdb0214de600011b718aa5bdbfa4bb0c7dc837853
7
- data.tar.gz: 72d6ca3fa679e24c8201ba4231228f56f6a59c6b4f399b8ec70b9566b9eda835c00750759402ceb126d684b87095d48a28d0c811422b06c7c97b6b06f9bb2e74
6
+ metadata.gz: 1790591d549b5d230962ad6b72d718857e536a040f32c7c2f6a7ea04db6ae52dbe42575904d0ea2210e09f23d6c9076114440f2ba888ba487e0a1ba570256f63
7
+ data.tar.gz: 21bd29c0a876cbce995a9a833e03c453c179db0bae6e51a209995196dbac156633fd91120618759b25016dfa2b8c63dca68a5c9b25b93792b66edb22bcfa8cfb
@@ -0,0 +1 @@
1
+ coverage
@@ -1,10 +1,14 @@
1
1
  language: ruby
2
2
 
3
3
  rvm:
4
- - "1.9.3"
5
- - "2.0.0"
4
+ - 2.4
5
+ - 2.5
6
6
 
7
- services: postgresql
7
+ services:
8
+ - postgresql
9
+
10
+ addons:
11
+ postgresql: "9.6"
8
12
 
9
13
  before_script:
10
14
  - psql -c 'create database shoden_test;' -U postgres
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem "rake"
@@ -0,0 +1,33 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ shoden (1.0)
5
+ pg (~> 1.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ clap (1.0.0)
11
+ cutest (1.2.3)
12
+ clap
13
+ docile (1.3.1)
14
+ json (2.2.0)
15
+ pg (1.1.4)
16
+ rake (12.3.2)
17
+ simplecov (0.16.1)
18
+ docile (~> 1.1)
19
+ json (>= 1.8, < 3)
20
+ simplecov-html (~> 0.10.0)
21
+ simplecov-html (0.10.2)
22
+
23
+ PLATFORMS
24
+ ruby
25
+
26
+ DEPENDENCIES
27
+ cutest (~> 1.2)
28
+ rake
29
+ shoden!
30
+ simplecov (~> 0.16)
31
+
32
+ BUNDLED WITH
33
+ 1.17.2
data/README.md CHANGED
@@ -1,10 +1,9 @@
1
- # Shôden - [![Gem Version](https://badge.fury.io/rb/shoden.svg)](http://badge.fury.io/rb/shoden)
1
+ # Shôden - [![Build Status](https://travis-ci.org/elcuervo/shoden.svg)](https://travis-ci.org/elcuervo/shoden)
2
2
 
3
- ![Elephant god](http://www.redprintdna.com/wp-content/uploads/2011/09/L-Elephant-Against-Sky.jpg)
3
+ ![Elephant god](https://images.unsplash.com/photo-1523190301657-195ef118bb36?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1500&q=80)
4
4
 
5
5
  Shôden is a persistance library on top of Postgres.
6
- It is basically an [Ohm](https://github.com/soveran/ohm) clone but using
7
- Postgres as a main database.
6
+ Uses JSONB as an storage abstraction so no need for migrations.
8
7
 
9
8
  ## Installation
10
9
 
@@ -12,6 +11,20 @@ Postgres as a main database.
12
11
  gem install shoden
13
12
  ```
14
13
 
14
+ ## Connect
15
+
16
+ Shoden connects by default using a `DATABASE_URL` env variable.
17
+ But you can change the connection string by calling `Shoden.url=`
18
+
19
+ ## Setup
20
+
21
+ Shoden needs a setup method to create the proper tables.
22
+ You should do that after connecting
23
+
24
+ ```ruby
25
+ Shoden.setup
26
+ ```
27
+
15
28
  ## Models
16
29
 
17
30
  ```ruby
@@ -47,6 +60,17 @@ class Post < Shoden::Model
47
60
  end
48
61
  ```
49
62
 
63
+ ## Attributes
64
+
65
+ Shoden attributes offer you a way to type cast the values, or to perform changes
66
+ in the data itself.
67
+
68
+ ```ruby
69
+ class Shout < Shoden::Model
70
+ attribute :what, ->(x) { x.uppcase }
71
+ end
72
+ ```
73
+
50
74
  ## Indexing
51
75
 
52
76
  ```ruby
@@ -58,3 +82,17 @@ class User < Shoden::Model
58
82
  unique :email
59
83
  end
60
84
  ```
85
+
86
+ ## Querying
87
+
88
+ You can query models or relations using the `filter` method.
89
+
90
+ ```ruby
91
+ User.filter(email: "elcuervo@elcuervo.net")
92
+ User.first
93
+ User.last
94
+ User.count
95
+ ```
96
+
97
+ You can go through the entire set using: `User.all` which will give you a
98
+ `Enumerator::Lazy`
data/Rakefile CHANGED
@@ -5,4 +5,4 @@ Rake::TestTask.new("test") do |t|
5
5
  t.pattern = "test/**/*_test.rb"
6
6
  end
7
7
 
8
- task :default => [:test]
8
+ task default: [:test]
@@ -1,7 +1,6 @@
1
- require 'sequel'
2
- require 'set'
3
-
4
- Sequel.extension :pg_hstore, :pg_hstore_ops
1
+ require "pg"
2
+ require "set"
3
+ require "shoden/model"
5
4
 
6
5
  module Shoden
7
6
  Error = Class.new(StandardError)
@@ -9,56 +8,12 @@ module Shoden
9
8
  NotFound = Class.new(Error)
10
9
  UniqueIndexViolation = Class.new(Error)
11
10
 
12
- Proxy = Struct.new(:klass, :parent) do
13
- def create(args = {})
14
- klass.create(args.merge(key => parent.id))
15
- end
16
-
17
- def all
18
- klass.filter(parent_filter)
19
- end
20
-
21
- def count
22
- klass.count
23
- end
24
-
25
- def any?
26
- count > 0
27
- end
28
-
29
- def first
30
- filter = { order: "id ASC LIMIT 1" }.merge!(parent_filter)
31
- klass.filter(filter).first
32
- end
33
-
34
- def last
35
- filter = { order: "id DESC LIMIT 1" }.merge!(parent_filter)
36
- klass.filter(filter).first
37
- end
38
-
39
- def [](id)
40
- filter = { id: id }.merge!(parent_filter)
41
-
42
- klass.filter(filter).first
43
- end
44
-
45
- private
46
-
47
- def parent_filter
48
- { key => parent.id }
49
- end
50
-
51
- def key
52
- "#{parent.class.to_reference}_id".freeze
53
- end
54
- end
55
-
56
11
  def self.url=(url)
57
12
  @_url = url
58
13
  end
59
14
 
60
15
  def self.url
61
- @_url ||= ENV['DATABASE_URL']
16
+ @_url ||= ENV["DATABASE_URL"]
62
17
  end
63
18
 
64
19
  def self.models
@@ -66,263 +21,17 @@ module Shoden
66
21
  end
67
22
 
68
23
  def self.connection
69
- loggers = []
70
-
71
- if ENV["DEBUG"]
72
- require 'logger'
73
- loggers << Logger.new($stdout)
24
+ @_connection ||= begin
25
+ uri = URI.parse(url)
26
+ PG.connect(uri.hostname, uri.port, nil, nil, uri.path[1..-1], uri.user, uri.password)
74
27
  end
75
-
76
- @_connection ||= Sequel.connect(url, loggers: loggers)
77
28
  end
78
29
 
79
30
  def self.setup
80
- connection.execute("CREATE EXTENSION IF NOT EXISTS hstore")
81
- models.each { |m| m.setup }
31
+ models.each(&:setup)
82
32
  end
83
33
 
84
34
  def self.destroy_tables
85
- models.each { |m| m.destroy_table }
86
- end
87
-
88
- class Model
89
- def initialize(attrs = {})
90
- @_id = attrs.delete(:id) if attrs[:id]
91
- @attributes = {}
92
- update(attrs)
93
- end
94
-
95
- def id
96
- return nil if !defined?(@_id)
97
- @_id.to_i
98
- end
99
-
100
- def destroy
101
- self.class.lookup(id).delete
102
- end
103
-
104
- def update(attrs = {})
105
- attrs.each { |name, value| send(:"#{name}=", value) }
106
- end
107
-
108
- def update_attributes(attrs = {})
109
- update(attrs)
110
- save
111
- end
112
-
113
- def save
114
- self.class.save(self)
115
- self
116
- end
117
-
118
- def load!
119
- ret = self.class.lookup(@_id)
120
- return nil if ret.nil?
121
- update(ret.to_a.first[:data])
122
- self
123
- end
124
-
125
- def self.inherited(model)
126
- Shoden.models.add(model)
127
- end
128
-
129
- def self.save(record)
130
- if record.id
131
- table.where(id: record.id).update(data: record.attributes)
132
- else
133
- begin
134
- id = table.insert(data: record.attributes)
135
- record.instance_variable_set(:@_id, id)
136
- rescue Sequel::UniqueConstraintViolation
137
- raise UniqueIndexViolation
138
- end
139
- end
140
- end
141
-
142
- def self.all
143
- collect
144
- end
145
-
146
- def self.count
147
- size = 0
148
- Shoden.connection.fetch("SELECT COUNT(*) FROM \"#{table_name}\"") do |r|
149
- size = r[:count]
150
- end
151
-
152
- size
153
- end
154
-
155
- def self.first
156
- collect("ORDER BY id ASC LIMIT 1").first
157
- end
158
-
159
- def self.last
160
- collect("ORDER BY id DESC LIMIT 1").first
161
- end
162
-
163
- def self.create(attrs = {})
164
- new(attrs).save
165
- end
166
-
167
- def self.attributes
168
- @attributes ||= []
169
- end
170
-
171
- def self.indices
172
- @indices ||= []
173
- end
174
-
175
- def self.uniques
176
- @uniques ||= []
177
- end
178
-
179
- def self.[](id)
180
- new(id: id).load!
181
- end
182
-
183
- def self.index(name)
184
- indices << name if !indices.include?(name)
185
- end
186
-
187
- def self.unique(name)
188
- uniques << name if !uniques.include?(name)
189
- end
190
-
191
- def self.attribute(name, caster = ->(x) { x })
192
- attributes << name if !attributes.include?(name)
193
-
194
- define_method(name) { caster[@attributes[name]] }
195
- define_method(:"#{name}=") { |value| @attributes[name] = value }
196
- end
197
-
198
- def self.collection(name, model)
199
- define_method(name) do
200
- klass = Kernel.const_get(model)
201
- Proxy.new(klass, self)
202
- end
203
- end
204
-
205
- def self.reference(name, model)
206
- reader = :"#{name}_id"
207
- writer = :"#{name}_id="
208
-
209
- attributes << name if !attributes.include?(name)
210
-
211
- define_method(reader) { @attributes[reader] }
212
- define_method(writer) { |value| @attributes[reader] = value }
213
-
214
- define_method(name) do
215
- klass = Kernel.const_get("Shoden::#{model}")
216
- klass[send(reader)]
217
- end
218
- end
219
-
220
- def self.filter(conditions = {})
221
- query = []
222
- id = conditions.delete(:id)
223
- order = conditions.delete(:order)
224
-
225
- if id && !conditions.any?
226
- rows = table.where(id: id)
227
- else
228
- conditions.each { |k,v| query << "data->'#{k}' = '#{v}'" }
229
- seek_conditions = query.join(" AND ")
230
-
231
- where = "WHERE (#{seek_conditions})"
232
-
233
- where += " AND id = '#{id}'" if id
234
- order_condition = "ORDER BY #{order}" if order
235
-
236
- sql = "#{base_query} #{where} #{order_condition}"
237
-
238
- rows = Shoden.connection.fetch(sql) || []
239
- end
240
-
241
- rows.lazy.map do |row|
242
- attrs = row[:data].merge({ id: row[:id] })
243
-
244
- new(attrs)
245
- end
246
- end
247
-
248
- def attributes
249
- sanitized = @attributes.map do |k, _|
250
- val = send(k)
251
- return if val.nil?
252
- [k, val.to_s]
253
- end.compact
254
-
255
- Sequel::Postgres::HStore.new(sanitized)
256
- end
257
-
258
- private
259
-
260
- def self.base_query
261
- "SELECT * FROM \"#{table_name}\""
262
- end
263
-
264
- def self.collect(condition = '')
265
- records = []
266
- Shoden.connection.fetch("SELECT * FROM \"#{table_name}\" #{condition}") do |r|
267
- attrs = r[:data].merge(id: r[:id])
268
- records << new(attrs)
269
- end
270
- records
271
- end
272
-
273
- def self.table_name
274
- :"Shoden::#{self.name}"
275
- end
276
-
277
- def self.to_reference
278
- name.to_s.
279
- match(/^(?:.*::)*(.*)$/)[1].
280
- gsub(/([a-z\d])([A-Z])/, '\1_\2').
281
- downcase.to_sym
282
- end
283
-
284
- def self.create_index(name, type = '')
285
- conn.execute <<EOS
286
- CREATE #{type.upcase} INDEX index_#{self.name}_#{name}
287
- ON "#{table_name}" (( data -> '#{name}'))
288
- WHERE ( data ? '#{name}' );
289
- EOS
290
- rescue
291
- end
292
-
293
- def self.lookup(id)
294
- row = table.where(id: id)
295
- return nil if !row.any?
296
-
297
- row
298
- end
299
-
300
- def self.setup
301
- conn.create_table? table_name do
302
- primary_key :id
303
- hstore :data
304
- end
305
-
306
- indices.each { |i| create_index(i) }
307
- uniques.each { |i| create_index(i, :unique) }
308
- end
309
-
310
- def self.destroy_all
311
- conn.execute("DELETE FROM \"#{table_name}\"")
312
- rescue Sequel::DatabaseError
313
- end
314
-
315
- def self.destroy_table
316
- conn.drop_table(table_name)
317
- rescue Sequel::DatabaseError
318
- end
319
-
320
- def self.table
321
- conn[table_name]
322
- end
323
-
324
- def self.conn
325
- Shoden.connection
326
- end
35
+ models.each(&:destroy_table)
327
36
  end
328
37
  end
@@ -0,0 +1,259 @@
1
+ require "json"
2
+ require "shoden/proxy"
3
+
4
+ module Shoden
5
+ class Model
6
+ attr_reader :attributes
7
+
8
+ def initialize(attrs = {})
9
+ @_id = attrs.delete(:id) if attrs[:id]
10
+ @attributes = {}
11
+ update(attrs)
12
+ end
13
+
14
+ def id
15
+ return nil unless defined?(@_id)
16
+ @_id.to_i
17
+ end
18
+
19
+ def destroy
20
+ query = "DELETE FROM \"#{self.class.table_name}\" WHERE id = $1 RETURNING id"
21
+ ret = Shoden.connection.exec_params(query, [id])
22
+ ret.first["id"]
23
+ end
24
+
25
+ def update(attrs = {})
26
+ attrs.each { |name, value| send(:"#{name}=", value) }
27
+ end
28
+
29
+ def update_attributes(attrs = {})
30
+ update(attrs)
31
+ save
32
+ end
33
+
34
+ def save
35
+ self.class.save(self)
36
+ self
37
+ end
38
+
39
+ def load!
40
+ ret = self.class.lookup(@_id)
41
+ return nil if ret.nil?
42
+ data = self.class.from_json(ret.first["data"])
43
+ update(data)
44
+
45
+ self
46
+ end
47
+
48
+ def self.inherited(model)
49
+ Shoden.models.add(model)
50
+ end
51
+
52
+ def self.save(record)
53
+ if record.id
54
+ query = "UPDATE \"#{table_name}\" SET data = $1 WHERE id = $2"
55
+ Shoden.connection.exec_params(query, [record.attributes, record.id])
56
+ else
57
+ begin
58
+ query = "INSERT INTO \"#{table_name}\" (data) VALUES ($1) RETURNING id"
59
+ res = Shoden.connection.exec_params(query, [record.attributes.to_json])
60
+ record.instance_variable_set(:@_id, res.first["id"])
61
+ rescue PG::UniqueViolation
62
+ raise Shoden::UniqueIndexViolation
63
+ end
64
+ end
65
+ end
66
+
67
+ def self.all
68
+ collect
69
+ end
70
+
71
+ def self.count
72
+ query = "SELECT COUNT(*) FROM \"#{table_name}\""
73
+ Shoden.connection.exec(query).first["count"].to_i
74
+ end
75
+
76
+ def self.first
77
+ collect(order: "id ASC", limit: 1).first
78
+ end
79
+
80
+ def self.last
81
+ collect(order: "id DESC", limit: 1).first
82
+ end
83
+
84
+ def self.create(attrs = {})
85
+ new(attrs).save
86
+ end
87
+
88
+ def self.attributes
89
+ @attributes ||= []
90
+ end
91
+
92
+ def self.indices
93
+ @indices ||= []
94
+ end
95
+
96
+ def self.uniques
97
+ @uniques ||= []
98
+ end
99
+
100
+ def self.[](id)
101
+ new(id: id).load!
102
+ end
103
+
104
+ def self.index(name)
105
+ indices << name unless indices.include?(name)
106
+ end
107
+
108
+ def self.unique(name)
109
+ uniques << name unless uniques.include?(name)
110
+ end
111
+
112
+ def self.attribute(name, caster = ->(x) { x })
113
+ attributes << name unless attributes.include?(name)
114
+
115
+ define_method(name) { caster[@attributes[name]] }
116
+ define_method(:"#{name}=") { |value| @attributes[name] = value }
117
+ end
118
+
119
+ def self.collection(name, model)
120
+ define_method(name) do
121
+ klass = Kernel.const_get(model)
122
+ Shoden::Proxy.new(klass, self)
123
+ end
124
+ end
125
+
126
+ def self.reference(name, model)
127
+ reader = :"#{name}_id"
128
+ writer = :"#{name}_id="
129
+
130
+ attributes << name unless attributes.include?(name)
131
+
132
+ define_method(reader) { @attributes[reader] }
133
+ define_method(writer) { |value| @attributes[reader] = value }
134
+
135
+ define_method(name) do
136
+ klass = Kernel.const_get("Shoden::#{model}")
137
+ klass[send(reader)]
138
+ end
139
+ end
140
+
141
+ def self.filter(conditions = {})
142
+ rows = query(conditions: conditions)
143
+
144
+ rows.lazy.map do |row|
145
+ data = from_json(row["data"])
146
+ data[:id] = row["id"].to_i
147
+
148
+ new(data)
149
+ end
150
+ end
151
+
152
+ def self.query(fields: "*", conditions: {})
153
+ id = conditions.delete(:id)
154
+ order = conditions.delete(:order)
155
+
156
+ if id && conditions.none?
157
+ sql = "#{base_query(fields)} WHERE id = $1"
158
+ Shoden.connection.exec_params(sql, [id]) || []
159
+ else
160
+ count = conditions.count
161
+ where = count.times.map { |i| "data->>$#{2 * i + 1} = $#{2 * i + 2}" }
162
+ params = conditions.flatten
163
+
164
+ if id
165
+ where << "id = $#{count * 2 + 1}"
166
+ params << id
167
+ end
168
+
169
+ where = where.join(" AND ")
170
+ order_condition = "ORDER BY #{order}" if order
171
+ sql = "#{base_query(fields)} WHERE #{where} #{order_condition}"
172
+
173
+ Shoden.connection.exec_params(sql, params) || []
174
+ end
175
+ end
176
+
177
+ private
178
+
179
+ def self.from_json(string)
180
+ JSON.parse(string, symbolize_names: true)
181
+ end
182
+
183
+ def self.base_query(fields = "*")
184
+ "SELECT #{fields} FROM \"#{table_name}\""
185
+ end
186
+
187
+ def self.collect(order: :id, limit: 0)
188
+ query = base_query("*")
189
+
190
+ params = [].tap do |item|
191
+ item << order
192
+ query << " ORDER BY $1"
193
+
194
+ if limit > 0
195
+ item << limit
196
+ query << " LIMIT $2 "
197
+ end
198
+ end
199
+
200
+ [].tap do |records|
201
+ Shoden.connection.exec_params(query, params).each do |row|
202
+ data = from_json(row["data"])
203
+ data[:id] = row["id"].to_i
204
+
205
+ records << new(data)
206
+ end
207
+ end
208
+ end
209
+
210
+ def self.table_name
211
+ :"Shoden::#{name}"
212
+ end
213
+
214
+ def self.to_reference
215
+ name.to_s
216
+ .match(/^(?:.*::)*(.*)$/)[1]
217
+ .gsub(/([a-z\d])([A-Z])/, '\1_\2')
218
+ .downcase.to_sym
219
+ end
220
+
221
+ def self.create_index(name, type = "")
222
+ query = <<~EOS
223
+ CREATE #{type.upcase} INDEX index_#{self.name}_#{name}
224
+ ON "#{table_name}" (( data ->> '#{name}'))
225
+ WHERE ( data ? '#{name}' );
226
+ EOS
227
+
228
+ Shoden.connection.exec(query)
229
+ end
230
+
231
+ def self.lookup(id)
232
+ query = "SELECT * FROM \"#{table_name}\" WHERE id = $1"
233
+ row = Shoden.connection.exec_params(query, [id])
234
+ return nil if row.none?
235
+
236
+ row
237
+ end
238
+
239
+ def self.setup
240
+ Shoden.connection.exec <<~EOS
241
+ CREATE TABLE IF NOT EXISTS \"#{table_name}\" (
242
+ id SERIAL NOT NULL PRIMARY KEY,
243
+ data JSONB
244
+ )
245
+ EOS
246
+
247
+ indices.each { |i| create_index(i) }
248
+ uniques.each { |i| create_index(i, :unique) }
249
+ end
250
+
251
+ def self.destroy_all
252
+ Shoden.connection.exec("DELETE FROM \"#{table_name}\"")
253
+ end
254
+
255
+ def self.destroy_table
256
+ Shoden.connection.exec("DROP TABLE IF EXISTS \"#{table_name}\"")
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,46 @@
1
+ module Shoden
2
+ Proxy = Struct.new(:klass, :parent) do
3
+ def create(args = {})
4
+ klass.create(args.merge(key => parent.id))
5
+ end
6
+
7
+ def all
8
+ klass.filter(parent_filter)
9
+ end
10
+
11
+ def count
12
+ row = klass.query(fields: "COUNT(id)", conditions: parent_filter)
13
+ row.first["count"].to_i
14
+ end
15
+
16
+ def any?
17
+ count > 0
18
+ end
19
+
20
+ def first
21
+ filter = { order: "id ASC LIMIT 1" }.merge!(parent_filter)
22
+ klass.filter(filter).first
23
+ end
24
+
25
+ def last
26
+ filter = { order: "id DESC LIMIT 1" }.merge!(parent_filter)
27
+ klass.filter(filter).first
28
+ end
29
+
30
+ def [](id)
31
+ filter = { id: id }.merge!(parent_filter)
32
+
33
+ klass.filter(filter).first
34
+ end
35
+
36
+ private
37
+
38
+ def parent_filter
39
+ { key => parent.id }
40
+ end
41
+
42
+ def key
43
+ "#{parent.class.to_reference}_id".freeze
44
+ end
45
+ end
46
+ end
@@ -1,15 +1,17 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "shoden"
3
- s.version = "0.4.0"
3
+ s.version = "1.0"
4
4
  s.summary = "Object hash mapper for postgres"
5
5
  s.description = "Slim postgres models"
6
6
  s.authors = ["elcuervo"]
7
- s.licenses = ["MIT", "HUGWARE"]
7
+ s.licenses = %w[MIT HUGWARE]
8
8
  s.email = ["yo@brunoaguirre.com"]
9
9
  s.homepage = "http://github.com/elcuervo/shoden"
10
10
  s.files = `git ls-files`.split("\n")
11
11
  s.test_files = `git ls-files test`.split("\n")
12
12
 
13
- s.add_dependency("sequel", "~> 4.11.0")
14
- s.add_development_dependency("cutest", "~> 1.2.1")
13
+ s.add_dependency("pg", "~> 1.1")
14
+
15
+ s.add_development_dependency("cutest", "~> 1.2")
16
+ s.add_development_dependency("simplecov", "~> 0.16")
15
17
  end
@@ -1,5 +1,9 @@
1
- require 'cutest'
2
- require 'shoden'
1
+ require "cutest"
2
+ require "simplecov"
3
+
4
+ SimpleCov.start
5
+
6
+ require "shoden"
3
7
 
4
8
  Model = Class.new(Shoden::Model)
5
9
 
@@ -12,8 +16,8 @@ class Person < Shoden::Model
12
16
  end
13
17
 
14
18
  class Tree < Shoden::Model
15
- attribute :name
16
- collection :sprouts, :Sprout
19
+ attribute :name
20
+ collection :sprouts, :Sprout
17
21
  end
18
22
 
19
23
  class Sprout < Shoden::Model
@@ -34,61 +38,70 @@ setup do
34
38
  Shoden.setup
35
39
  end
36
40
 
37
- test 'model' do
41
+ test "url setup" do
42
+ Shoden.url = ENV["DATABASE_URL"]
43
+ end
44
+
45
+ test "model" do
38
46
  model = Model.create
39
- assert_equal model.id.class, Fixnum
47
+
48
+ assert Model.count
49
+ assert_equal model.id.class, Integer
40
50
  end
41
51
 
42
- test 'attributes' do
43
- user = User.create name: 'Michel'
44
- assert_equal user.name, 'Michel'
52
+ test "attributes" do
53
+ user = User.create name: "Michel"
54
+ assert_equal user.name, "Michel"
45
55
  end
46
56
 
47
- test 'update' do
48
- user = User.create name: 'Cyril'
57
+ test "update" do
58
+ user = User.create name: "Cyril"
49
59
  id = user.id
50
60
 
51
- assert_equal user.name, 'Cyril'
61
+ assert_equal user.name, "Cyril"
52
62
 
53
- user.name = 'cyx'
63
+ user.name = "cyx"
54
64
  user.save
55
65
 
56
- assert_equal user.name, 'cyx'
66
+ assert_equal user.name, "cyx"
57
67
  assert_equal user.id, id
58
68
 
59
- user.update_attributes(name: 'Cyril')
60
- assert_equal user.name, 'Cyril'
69
+ user.update_attributes(name: "Cyril")
70
+ assert_equal user.name, "Cyril"
61
71
  end
62
72
 
63
- test 'filtering' do
64
- person = { email: 'elcuervo@elcuervo.net' }
73
+ test "filtering" do
74
+ person = { email: "edgar@poe.com" }
65
75
  Person.create(person)
66
76
  p = Person.filter(person).first
67
77
 
68
- assert p.email == 'elcuervo@elcuervo.net'
78
+ assert p.email == "edgar@poe.com"
69
79
  end
70
80
 
71
- test 'relations' do
72
- tree = Tree.create(name: 'asd')
81
+ test "relations" do
82
+ tree = Tree.create(name: "asd")
83
+ tree2 = Tree.create(name: "qwe")
73
84
 
74
85
  assert tree.id
75
- assert_equal tree.name, 'asd'
86
+ assert_equal tree.name, "asd"
76
87
 
77
88
  sprout = tree.sprouts.create(leaves: 4)
89
+ tree2.sprouts.create(leaves: 5)
78
90
 
79
91
  assert sprout.is_a?(Sprout)
80
92
  assert tree.sprouts.all.each.is_a?(Enumerator)
81
93
 
82
94
  assert tree.sprouts[sprout.id].id == sprout.id
83
95
 
96
+ assert tree.sprouts.any?
84
97
  assert_equal tree.sprouts.count, 1
85
98
  assert_equal sprout.tree.id, tree.id
86
- assert tree.sprouts.first != nil
87
- assert tree.sprouts.last != nil
99
+ assert !tree.sprouts.first.nil?
100
+ assert !tree.sprouts.last.nil?
88
101
  end
89
102
 
90
- test 'deletion' do
91
- user = User.create(name: 'Damian')
103
+ test "deletion" do
104
+ user = User.create(name: "Damian")
92
105
  id = user.id
93
106
 
94
107
  user.destroy
@@ -96,27 +109,28 @@ test 'deletion' do
96
109
  assert_equal User[id], nil
97
110
  end
98
111
 
99
- test 'casting' do
112
+ test "casting" do
100
113
  a = A.create(n: 1)
101
114
  a_prime = A[a.id]
102
115
 
103
116
  assert_equal a_prime.n, 1
104
117
  end
105
118
 
106
- test 'indices' do
107
- person = Person.create(email: 'elcuervo@elcuervo.net', origin: 'The internerd')
119
+ test "indices" do
120
+ person = Person.create(email: "edgar@poe.com", origin: "The internerd")
108
121
 
109
122
  assert person.id
110
123
 
111
124
  assert_raise Shoden::UniqueIndexViolation do
112
- Person.create(email: 'elcuervo@elcuervo.net', origin: 'Montevideo City')
125
+ Person.create(email: "edgar@poe.com", origin: "Montevideo City")
113
126
  end
114
127
  end
115
128
 
116
- test 'basic querying' do
129
+ test "basic querying" do
117
130
  User.destroy_all
118
131
  5.times { User.create }
119
132
 
133
+ assert User.query(conditions: { id: 1 })
134
+ assert User.first != User.last
120
135
  assert_equal User.all.size, 5
121
-
122
136
  end
metadata CHANGED
@@ -1,43 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shoden
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: '1.0'
5
5
  platform: ruby
6
6
  authors:
7
7
  - elcuervo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-15 00:00:00.000000000 Z
11
+ date: 2019-09-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: sequel
14
+ name: pg
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 4.11.0
19
+ version: '1.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 4.11.0
26
+ version: '1.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: cutest
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 1.2.1
33
+ version: '1.2'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 1.2.1
40
+ version: '1.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: simplecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.16'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.16'
41
55
  description: Slim postgres models
42
56
  email:
43
57
  - yo@brunoaguirre.com
@@ -45,13 +59,18 @@ executables: []
45
59
  extensions: []
46
60
  extra_rdoc_files: []
47
61
  files:
48
- - .gems
49
- - .travis.yml
62
+ - ".gems"
63
+ - ".gitignore"
64
+ - ".travis.yml"
65
+ - Gemfile
66
+ - Gemfile.lock
50
67
  - HUGS
51
68
  - LICENSE
52
69
  - README.md
53
70
  - Rakefile
54
71
  - lib/shoden.rb
72
+ - lib/shoden/model.rb
73
+ - lib/shoden/proxy.rb
55
74
  - shoden.gemspec
56
75
  - test/shoden_test.rb
57
76
  homepage: http://github.com/elcuervo/shoden
@@ -65,17 +84,16 @@ require_paths:
65
84
  - lib
66
85
  required_ruby_version: !ruby/object:Gem::Requirement
67
86
  requirements:
68
- - - '>='
87
+ - - ">="
69
88
  - !ruby/object:Gem::Version
70
89
  version: '0'
71
90
  required_rubygems_version: !ruby/object:Gem::Requirement
72
91
  requirements:
73
- - - '>='
92
+ - - ">="
74
93
  - !ruby/object:Gem::Version
75
94
  version: '0'
76
95
  requirements: []
77
- rubyforge_project:
78
- rubygems_version: 2.0.14
96
+ rubygems_version: 3.0.3
79
97
  signing_key:
80
98
  specification_version: 4
81
99
  summary: Object hash mapper for postgres