groovy 0.6.1 → 0.6.4
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 +4 -4
- data/lib/groovy/model.rb +80 -10
- data/lib/groovy/query.rb +0 -1
- data/lib/groovy/schema.rb +37 -8
- data/lib/groovy/vector.rb +24 -3
- data/lib/groovy/version.rb +1 -1
- data/spec/callbacks_spec.rb +58 -0
- data/spec/vector_spec.rb +15 -3
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a622cdd3453e0fee1feeebf798cbcec9f0ef9f68759aec64f65c3d4a500f52af
|
4
|
+
data.tar.gz: be1220642bf299a61ad5900bea1fffa3359725575def843ce233290e26a5b8e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9943e2715a0099f8b1b2795ab66259cbb5b71d5a782e4669b503e61f30a8df56fa57332f88c3592e3b69c0c63638da5d1ea471b102e62511028178886cd5b968
|
7
|
+
data.tar.gz: fa02339637f33c69bb37301f63d8b14b77d61b185f0b3c23d78712fb26159d2d5594dc2bb9bba7bb225211c4ab6a5adef167ddade4ea5b5999dae8ce2d5e5f07
|
data/lib/groovy/model.rb
CHANGED
@@ -13,6 +13,10 @@ module Groovy
|
|
13
13
|
class Error < StandardError; end
|
14
14
|
class RecordNotPersisted < Error; end
|
15
15
|
|
16
|
+
def self.models
|
17
|
+
@models ||= {}
|
18
|
+
end
|
19
|
+
|
16
20
|
module Model
|
17
21
|
|
18
22
|
def self.initialize_from_record(obj)
|
@@ -33,9 +37,14 @@ module Groovy
|
|
33
37
|
base.extend(ClassMethods)
|
34
38
|
base.include(Forwardable)
|
35
39
|
base.table_name = base.name.sub(/y$/, 'ie') + 's'
|
40
|
+
|
41
|
+
# add to global model list
|
42
|
+
# Groovy.models[base.name] = base
|
43
|
+
Groovy.models[base.table_name] = base
|
36
44
|
end
|
37
45
|
|
38
46
|
def self.get_class(table_name)
|
47
|
+
# classify method
|
39
48
|
classified = table_name.gsub(/([A-Z])/, '_\1').split('_').collect! { |w| w.capitalize }.join
|
40
49
|
Kernel.const_get(classified)
|
41
50
|
end
|
@@ -253,10 +262,14 @@ module Groovy
|
|
253
262
|
@callbacks ||= {}
|
254
263
|
end
|
255
264
|
|
256
|
-
[:before_create, :after_create].each do |event|
|
257
|
-
define_method(event) do |*
|
258
|
-
callbacks[
|
259
|
-
|
265
|
+
[:before_create, :after_create, :before_update, :after_update].each do |event|
|
266
|
+
define_method(event) do |*args, &block|
|
267
|
+
callbacks[event] ||= []
|
268
|
+
if block
|
269
|
+
callbacks[event].push(block)
|
270
|
+
else
|
271
|
+
callbacks[event].push(*args)
|
272
|
+
end
|
260
273
|
end
|
261
274
|
end
|
262
275
|
|
@@ -306,6 +319,7 @@ module Groovy
|
|
306
319
|
|
307
320
|
def initialize(attrs = nil, record = nil, key = nil)
|
308
321
|
@attributes, @vectors, @_key = {}, {}, key # key is used on creation only
|
322
|
+
@foreign_refs_to_update = {}
|
309
323
|
|
310
324
|
if set_record(record)
|
311
325
|
# load_attributes_from_record(record)
|
@@ -344,6 +358,10 @@ module Groovy
|
|
344
358
|
# _key.nil?
|
345
359
|
end
|
346
360
|
|
361
|
+
def persisted?
|
362
|
+
!new_record?
|
363
|
+
end
|
364
|
+
|
347
365
|
def [](key)
|
348
366
|
k = key.to_sym
|
349
367
|
@attributes[k] = get_record_attribute(k) unless @attributes.key?(k)
|
@@ -377,6 +395,18 @@ module Groovy
|
|
377
395
|
obj.each { |k,v| public_send("#{k}=", v) }
|
378
396
|
end
|
379
397
|
|
398
|
+
def set_reverse_reference(key, obj, removing = false)
|
399
|
+
if self.class.schema.singular_references.include?(key.to_sym)
|
400
|
+
# puts "setting #{obj} as #{key}"
|
401
|
+
set_ref(key, removing ? nil : obj, true)
|
402
|
+
elsif self.class.schema.plural_references.include?(key.to_sym)
|
403
|
+
# puts "adding #{obj} to #{key}"
|
404
|
+
public_send(key).set_ref(obj, removing)
|
405
|
+
else
|
406
|
+
raise "Invalid reference name: #{name}"
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
380
410
|
def update_attributes(obj)
|
381
411
|
set_attributes(obj)
|
382
412
|
return false if respond_to?(:invalid?) and invalid?
|
@@ -392,7 +422,7 @@ module Groovy
|
|
392
422
|
if new_record?
|
393
423
|
create && true
|
394
424
|
else
|
395
|
-
update
|
425
|
+
update && true
|
396
426
|
end
|
397
427
|
end
|
398
428
|
|
@@ -422,6 +452,7 @@ module Groovy
|
|
422
452
|
|
423
453
|
@attributes = {}
|
424
454
|
@changes = {}
|
455
|
+
@foreign_refs_to_update = {}
|
425
456
|
self
|
426
457
|
end
|
427
458
|
|
@@ -439,6 +470,7 @@ module Groovy
|
|
439
470
|
|
440
471
|
private
|
441
472
|
|
473
|
+
|
442
474
|
def get_record_attribute(key)
|
443
475
|
return if record.nil?
|
444
476
|
val = record[key]
|
@@ -475,12 +507,26 @@ module Groovy
|
|
475
507
|
end
|
476
508
|
end
|
477
509
|
|
478
|
-
|
479
|
-
|
510
|
+
|
511
|
+
def set_ref(name, obj, from_foreign = false)
|
512
|
+
# puts "Setting ref #{name} -> #{obj} (#{obj.class})"
|
513
|
+
|
514
|
+
if !from_foreign && obj.is_a?(Model) && !obj.new_record?
|
515
|
+
if foreign_ref = self.class.schema.reverse_reference_of(name.to_sym)
|
516
|
+
# puts "Found circular ref (#{name} -> #{foreign_ref})"
|
517
|
+
if current = get_ref(name)
|
518
|
+
current.set_reverse_reference(foreign_ref, self, true)
|
519
|
+
end
|
520
|
+
|
521
|
+
@foreign_refs_to_update[name] = [foreign_ref, obj]
|
522
|
+
end
|
523
|
+
end
|
524
|
+
|
525
|
+
if record.nil? # not persisted yet
|
480
526
|
set_attribute(name, obj.id) # obj should be a groovy model or groonga record
|
481
527
|
else
|
482
|
-
|
483
|
-
record[name] =
|
528
|
+
val = obj.respond_to?(:record) ? obj.record : obj
|
529
|
+
record[name] = val
|
484
530
|
end
|
485
531
|
end
|
486
532
|
|
@@ -492,17 +538,28 @@ module Groovy
|
|
492
538
|
def create
|
493
539
|
fire_callbacks(:before_create)
|
494
540
|
set_record(self.class.insert(@attributes, @_key))
|
541
|
+
update_foreign_refs
|
495
542
|
fire_callbacks(:after_create)
|
496
543
|
self
|
497
544
|
end
|
498
545
|
|
499
546
|
def fire_callbacks(name)
|
547
|
+
# puts "Firing #{name} callbacks"
|
500
548
|
if arr = self.class.callbacks[name] and arr.any?
|
501
|
-
arr.each { |fn|
|
549
|
+
arr.each { |fn| fire_callback(fn) }
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
553
|
+
def fire_callback(fn)
|
554
|
+
if fn.is_a?(Proc)
|
555
|
+
fn.call(self)
|
556
|
+
else
|
557
|
+
send(fn)
|
502
558
|
end
|
503
559
|
end
|
504
560
|
|
505
561
|
def update
|
562
|
+
fire_callbacks(:before_update)
|
506
563
|
ensure_persisted!
|
507
564
|
changes.each do |key, values|
|
508
565
|
# puts "Updating #{key} from #{values[0]} to #{values[1]}"
|
@@ -510,9 +567,22 @@ module Groovy
|
|
510
567
|
end
|
511
568
|
self.class.set_timestamp(record, :updated_at)
|
512
569
|
changes = {}
|
570
|
+
update_foreign_refs
|
571
|
+
fire_callbacks(:after_update)
|
513
572
|
self
|
514
573
|
end
|
515
574
|
|
575
|
+
def update_foreign_refs
|
576
|
+
return if @foreign_refs_to_update.empty?
|
577
|
+
|
578
|
+
@foreign_refs_to_update.each do |attr, (ref, obj)|
|
579
|
+
# puts "setting #{obj.class}##{ref} to #{self}"
|
580
|
+
obj.set_reverse_reference(ref, self)
|
581
|
+
end
|
582
|
+
|
583
|
+
@foreign_refs_to_update = {}
|
584
|
+
end
|
585
|
+
|
516
586
|
def ensure_persisted!
|
517
587
|
raise "Not persisted" if new_record?
|
518
588
|
end
|
data/lib/groovy/query.rb
CHANGED
data/lib/groovy/schema.rb
CHANGED
@@ -33,6 +33,11 @@ module Groovy
|
|
33
33
|
@table ||= context[table_name]
|
34
34
|
end
|
35
35
|
|
36
|
+
# def [](key)
|
37
|
+
# # @spec[key.to_sym]
|
38
|
+
# table.columns.select { |c| c.column? && c.name.to_s == "#{table_name}.#{key.to_s}" }
|
39
|
+
# end
|
40
|
+
|
36
41
|
def search_table
|
37
42
|
@cache[:search_table] ||= context[SEARCH_TABLE_NAME]
|
38
43
|
end
|
@@ -69,6 +74,22 @@ module Groovy
|
|
69
74
|
get_names(table.columns.select { |c| c.column? && c.range.name == type })
|
70
75
|
end
|
71
76
|
|
77
|
+
def refs_by_table
|
78
|
+
@refs_by_table ||= {}
|
79
|
+
end
|
80
|
+
|
81
|
+
def refs_by_name
|
82
|
+
@refs_by_name ||= {}
|
83
|
+
end
|
84
|
+
|
85
|
+
def reverse_reference_of(ref_name)
|
86
|
+
if ref_table = refs_by_name[ref_name.to_sym]
|
87
|
+
if foreign_model = Groovy.models[ref_table]
|
88
|
+
foreign_model.schema.refs_by_table[@table_name]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
72
93
|
def reload
|
73
94
|
@cache = {}
|
74
95
|
end
|
@@ -95,6 +116,14 @@ module Groovy
|
|
95
116
|
|
96
117
|
def reference(name, table_name = nil, options = {})
|
97
118
|
table_name = "#{name}s" if table_name.nil?
|
119
|
+
|
120
|
+
unless context[table_name]
|
121
|
+
log "Table #{table_name} doesn't exist yet! Creating now..."
|
122
|
+
create_table!(table_name)
|
123
|
+
end
|
124
|
+
|
125
|
+
refs_by_table[table_name] = name.to_sym
|
126
|
+
refs_by_name[name.to_sym] = table_name
|
98
127
|
@spec[name.to_sym] = { type: :reference, args: [table_name, options] }
|
99
128
|
end
|
100
129
|
|
@@ -188,15 +217,15 @@ module Groovy
|
|
188
217
|
end
|
189
218
|
end
|
190
219
|
|
191
|
-
def create_table!
|
192
|
-
log "Creating table #{
|
193
|
-
Groonga::Schema.create_table(
|
220
|
+
def create_table!(name = table_name)
|
221
|
+
log "Creating table #{name}!"
|
222
|
+
Groonga::Schema.create_table(name, context: context)
|
194
223
|
end
|
195
224
|
|
196
|
-
def remove_table!
|
197
|
-
log "Removing table #{
|
198
|
-
Groonga::Schema.remove_table(
|
199
|
-
@table = nil
|
225
|
+
def remove_table!(name = table_name)
|
226
|
+
log "Removing table #{name}!"
|
227
|
+
Groonga::Schema.remove_table(name, context: context)
|
228
|
+
@table = nil if name == table_name
|
200
229
|
end
|
201
230
|
|
202
231
|
def get_names(columns)
|
@@ -204,7 +233,7 @@ module Groovy
|
|
204
233
|
end
|
205
234
|
|
206
235
|
def log(str)
|
207
|
-
puts "[#{table_name}] #{str}"
|
236
|
+
puts "[#{table_name}] #{str}" if ENV['DEBUG']
|
208
237
|
end
|
209
238
|
end
|
210
239
|
end
|
data/lib/groovy/vector.rb
CHANGED
@@ -50,7 +50,9 @@ module Groovy
|
|
50
50
|
|
51
51
|
def set(new_items)
|
52
52
|
check_parent!
|
53
|
-
obj.record[key] = new_items
|
53
|
+
obj.record[key] = new_items.map do |obj|
|
54
|
+
obj.is_a?(Model) ? obj.record : obj
|
55
|
+
end
|
54
56
|
end
|
55
57
|
|
56
58
|
def has?(item)
|
@@ -61,17 +63,36 @@ module Groovy
|
|
61
63
|
def push(item)
|
62
64
|
raise "Invalid item type: #{item.class}" unless item.is_a?(Model)
|
63
65
|
check_parent!
|
64
|
-
|
66
|
+
if has?(item)
|
67
|
+
# puts "Item already present #{item.inspect}"
|
68
|
+
return false
|
69
|
+
end
|
65
70
|
item.save unless item.record
|
66
71
|
push_record(item.record)
|
72
|
+
# size
|
73
|
+
end
|
74
|
+
|
75
|
+
def push!(item)
|
76
|
+
push or raise "Already in list!"
|
67
77
|
end
|
68
78
|
|
69
79
|
def remove(item)
|
70
80
|
check_parent!
|
71
|
-
raise "Item not saved: #{
|
81
|
+
raise "Item not saved: #{item.inspect}" unless item.record
|
72
82
|
remove_record(item.record)
|
73
83
|
end
|
74
84
|
|
85
|
+
def set_ref(item, removing = false)
|
86
|
+
check_parent!
|
87
|
+
raise "Item not saved: #{item.inspect}" unless item.record
|
88
|
+
|
89
|
+
if removing
|
90
|
+
remove_record(item.record)
|
91
|
+
elsif !has?(item)
|
92
|
+
push_record(item.record)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
75
96
|
alias_method :<<, :push
|
76
97
|
|
77
98
|
[:first, :last, :find_by, :search, :where, :not, :sort_by, :limit, :offset, :paginate, :in_batches].each do |scope_method|
|
data/lib/groovy/version.rb
CHANGED
@@ -0,0 +1,58 @@
|
|
1
|
+
require_relative './spec_helper'
|
2
|
+
|
3
|
+
describe Groovy::Model do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
Groovy.open('tmp/callbacks', 'callbacks_spec')
|
7
|
+
load_callbacks_schema!
|
8
|
+
end
|
9
|
+
|
10
|
+
after :all do
|
11
|
+
Groovy.close('callbacks_spec')
|
12
|
+
end
|
13
|
+
|
14
|
+
def load_callbacks_schema!
|
15
|
+
klass = Class.new
|
16
|
+
Object.const_set("User", klass)
|
17
|
+
User.class_eval do
|
18
|
+
include Groovy::Model
|
19
|
+
|
20
|
+
after_create :created!
|
21
|
+
after_update do |record|
|
22
|
+
record.updated!
|
23
|
+
end
|
24
|
+
|
25
|
+
schema(context: 'callbacks_spec') do |t|
|
26
|
+
t.string :name
|
27
|
+
t.timestamps
|
28
|
+
end
|
29
|
+
|
30
|
+
def created!
|
31
|
+
# puts "created"
|
32
|
+
end
|
33
|
+
|
34
|
+
def updated!
|
35
|
+
# puts "updated"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
User.add_reference :comments, "Comments", type: :vector
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'fires created callbacks' do
|
43
|
+
user = User.new(name: 'John')
|
44
|
+
expect(user).to receive(:created!)
|
45
|
+
expect(user).not_to receive(:updated!)
|
46
|
+
expect(user.save).to eq(true)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'fires updated callbacks' do
|
50
|
+
user = User.new(name: 'John')
|
51
|
+
user.save
|
52
|
+
user.name = 'Josh'
|
53
|
+
expect(user).not_to receive(:created!)
|
54
|
+
expect(user).to receive(:updated!)
|
55
|
+
expect(user.save).to eq(true)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
data/spec/vector_spec.rb
CHANGED
@@ -22,7 +22,7 @@ describe Groovy::Model do
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
klass = Class.new
|
25
|
+
klass = Class.new
|
26
26
|
Object.const_set("User", klass)
|
27
27
|
User.class_eval do
|
28
28
|
include Groovy::Model
|
@@ -42,13 +42,25 @@ describe Groovy::Model do
|
|
42
42
|
load_vector_schema!
|
43
43
|
end
|
44
44
|
|
45
|
-
it 'loads records and
|
45
|
+
it 'loads records and adds reverse relations automatically' do
|
46
46
|
user = User.new(name: 'John')
|
47
47
|
expect(user.save).to eq(true)
|
48
48
|
comment = Comment.new(author: user, content: 'Hello there!')
|
49
49
|
expect(comment.save).to eq(true)
|
50
|
-
user.comments << comment
|
50
|
+
# user.comments << comment
|
51
51
|
expect(user.reload.comments).to eq([comment])
|
52
|
+
|
53
|
+
user2 = User.new(name: 'Paul')
|
54
|
+
expect(user2.save).to eq(true)
|
55
|
+
|
56
|
+
comment.author = user2
|
57
|
+
comment.save
|
58
|
+
|
59
|
+
expect(user.reload.comments).to eq([])
|
60
|
+
expect(user2.reload.comments).to eq([comment])
|
61
|
+
|
62
|
+
comment.delete
|
63
|
+
expect(user2.reload.comments).to eq([])
|
52
64
|
end
|
53
65
|
|
54
66
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: groovy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tomás Pollak
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-11-
|
11
|
+
date: 2023-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rroonga
|
@@ -97,6 +97,7 @@ files:
|
|
97
97
|
- lib/groovy/types.rb
|
98
98
|
- lib/groovy/vector.rb
|
99
99
|
- lib/groovy/version.rb
|
100
|
+
- spec/callbacks_spec.rb
|
100
101
|
- spec/groovy_spec.rb
|
101
102
|
- spec/model_spec.rb
|
102
103
|
- spec/query_spec.rb
|