groovy 0.6.1 → 0.6.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|