property 0.9.0 → 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +7 -1
- data/lib/property.rb +1 -1
- data/lib/property/behavior.rb +5 -5
- data/lib/property/declaration.rb +1 -1
- data/lib/property/index.rb +27 -22
- data/lib/property/schema.rb +1 -1
- data/property.gemspec +3 -1
- data/test/fixtures.rb +8 -0
- data/test/unit/property/behavior_test.rb +2 -2
- data/test/unit/property/index_complex_test.rb +1 -1
- data/test/unit/property/index_custom_test.rb +100 -0
- data/test/unit/property/index_simple_test.rb +2 -2
- metadata +4 -2
data/History.txt
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
+
== 0.9.1 2010-03-20
|
2
|
+
|
3
|
+
* 1 major enhancement
|
4
|
+
* Added support for custom indexer classes.
|
5
|
+
* Removed after_commit dependency (no need for an after_commit).
|
6
|
+
|
1
7
|
== 0.9.0 2010-03-20
|
2
8
|
|
3
9
|
* 3 major enhancement
|
4
10
|
* Added simple index support.
|
5
11
|
* Added complex index support.
|
6
|
-
* Added simple hooks for
|
12
|
+
* Added simple hooks for indices when properties are stored in a different model.
|
7
13
|
|
8
14
|
* 1 minor enhancement
|
9
15
|
* Added 'has_column?' to schema.
|
data/lib/property.rb
CHANGED
data/lib/property/behavior.rb
CHANGED
@@ -17,7 +17,7 @@ module Property
|
|
17
17
|
def initialize(name)
|
18
18
|
@name = name
|
19
19
|
@included_in_schemas = []
|
20
|
-
@
|
20
|
+
@group_indices = []
|
21
21
|
@accessor_module = build_accessor_module
|
22
22
|
end
|
23
23
|
|
@@ -27,7 +27,7 @@ module Property
|
|
27
27
|
end
|
28
28
|
|
29
29
|
# Return a list of index definitions in the form [type, key, proc_or_nil]
|
30
|
-
def
|
30
|
+
def indices
|
31
31
|
columns.values.select do |c|
|
32
32
|
c.indexed?
|
33
33
|
end.map do |c|
|
@@ -36,7 +36,7 @@ module Property
|
|
36
36
|
else
|
37
37
|
[c.type, c.name, c.index]
|
38
38
|
end
|
39
|
-
end + @
|
39
|
+
end + @group_indices
|
40
40
|
end
|
41
41
|
|
42
42
|
# Return true if the Behavior contains the given column (property).
|
@@ -86,7 +86,7 @@ module Property
|
|
86
86
|
# @internal
|
87
87
|
def add_index(type, proc)
|
88
88
|
# type, key, proc
|
89
|
-
@
|
89
|
+
@group_indices << [type, nil, proc]
|
90
90
|
end
|
91
91
|
|
92
92
|
private
|
@@ -120,7 +120,7 @@ module Property
|
|
120
120
|
behavior.add_column(Property::Column.new(name, nil, klass, options))
|
121
121
|
end
|
122
122
|
|
123
|
-
# This is used to create complex
|
123
|
+
# This is used to create complex indices with the following syntax:
|
124
124
|
#
|
125
125
|
# p.index(:text) do |r| # r = record
|
126
126
|
# {
|
data/lib/property/declaration.rb
CHANGED
@@ -38,7 +38,7 @@ module Property
|
|
38
38
|
schema.behave_like behavior
|
39
39
|
end
|
40
40
|
|
41
|
-
# Use this class method to declare properties and
|
41
|
+
# Use this class method to declare properties and indices that will be used in your models.
|
42
42
|
# Example:
|
43
43
|
# property.string 'phone', :default => '', :indexed => true
|
44
44
|
#
|
data/lib/property/index.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'versions/after_commit' # we need Versions gem's 'after_commit'
|
2
|
-
|
3
1
|
module Property
|
4
2
|
|
5
3
|
# Property::Declaration module is used to declare property definitions in a Class. The module
|
@@ -10,8 +8,8 @@ module Property
|
|
10
8
|
base.class_eval do
|
11
9
|
extend ClassMethods
|
12
10
|
include InstanceMethods
|
13
|
-
|
14
|
-
|
11
|
+
after_save :property_index
|
12
|
+
after_destroy :property_index_destroy
|
15
13
|
end
|
16
14
|
end
|
17
15
|
|
@@ -21,8 +19,8 @@ module Property
|
|
21
19
|
module InstanceMethods
|
22
20
|
|
23
21
|
private
|
24
|
-
# Retrieve the current
|
25
|
-
def
|
22
|
+
# Retrieve the current indices for a given group (:string, :text, etc)
|
23
|
+
def get_indices(group_name)
|
26
24
|
return {} if new_record?
|
27
25
|
res = {}
|
28
26
|
Property::Db.fetch_attributes(['key', 'value'], index_table_name(group_name), index_reader_sql).each do |row|
|
@@ -57,39 +55,44 @@ module Property
|
|
57
55
|
foreign_values = nil
|
58
56
|
|
59
57
|
schema.index_groups.each do |group_name, definitions|
|
60
|
-
|
61
|
-
cur_indexes = {}
|
58
|
+
cur_indices = {}
|
62
59
|
definitions.each do |key, proc|
|
63
60
|
if key
|
64
61
|
value = prop[key]
|
65
62
|
if !value.blank?
|
66
63
|
if proc
|
67
|
-
|
64
|
+
cur_indices.merge!(proc.call(self))
|
68
65
|
else
|
69
|
-
|
66
|
+
cur_indices[key] = value
|
70
67
|
end
|
71
68
|
end
|
72
69
|
else
|
73
|
-
|
70
|
+
cur_indices.merge!(proc.call(self))
|
74
71
|
end
|
75
72
|
end
|
76
73
|
|
77
|
-
|
78
|
-
|
74
|
+
if group_name.kind_of?(Class)
|
75
|
+
# Use a custom indexer
|
76
|
+
group_name.set_property_index(self, cur_indices)
|
77
|
+
else
|
78
|
+
# Add key/value pairs to the default tables
|
79
|
+
old_indices = get_indices(group_name)
|
80
|
+
|
81
|
+
old_keys = old_indices.keys
|
82
|
+
cur_keys = cur_indices.keys
|
79
83
|
|
80
|
-
|
81
|
-
|
82
|
-
|
84
|
+
new_keys = cur_keys - old_keys
|
85
|
+
del_keys = old_keys - cur_keys
|
86
|
+
upd_keys = cur_keys & old_keys
|
83
87
|
|
84
|
-
after_commit do
|
85
88
|
table_name = index_table_name(group_name)
|
86
89
|
|
87
90
|
upd_keys.each do |key|
|
88
|
-
value =
|
91
|
+
value = cur_indices[key]
|
89
92
|
if value.blank?
|
90
93
|
del_keys << key
|
91
94
|
else
|
92
|
-
connection.execute "UPDATE #{table_name} SET value = #{connection.quote(
|
95
|
+
connection.execute "UPDATE #{table_name} SET value = #{connection.quote(cur_indices[key])} WHERE #{reader_sql} AND key = #{connection.quote(key)}"
|
93
96
|
end
|
94
97
|
end
|
95
98
|
|
@@ -97,7 +100,7 @@ module Property
|
|
97
100
|
connection.execute "DELETE FROM #{table_name} WHERE #{reader_sql} AND key IN (#{del_keys.map{|key| connection.quote(key)}.join(',')})"
|
98
101
|
end
|
99
102
|
|
100
|
-
new_keys.reject! {|k|
|
103
|
+
new_keys.reject! {|k| cur_indices[k].blank? }
|
101
104
|
if !new_keys.empty?
|
102
105
|
# we evaluate this now to have the id on record creation
|
103
106
|
foreign_keys ||= index_writer.keys
|
@@ -107,7 +110,7 @@ module Property
|
|
107
110
|
table_name,
|
108
111
|
foreign_keys + ['key', 'value'],
|
109
112
|
new_keys.map do |key|
|
110
|
-
foreign_values + [connection.quote(key), connection.quote(
|
113
|
+
foreign_values + [connection.quote(key), connection.quote(cur_indices[key])]
|
111
114
|
end
|
112
115
|
)
|
113
116
|
end
|
@@ -121,7 +124,9 @@ module Property
|
|
121
124
|
foreign_key = index_foreign_key
|
122
125
|
current_id = self.id
|
123
126
|
schema.index_groups.each do |group_name, definitions|
|
124
|
-
|
127
|
+
if group_name.kind_of?(Class)
|
128
|
+
group_name.delete_property_index(self)
|
129
|
+
else
|
125
130
|
connection.execute "DELETE FROM #{index_table_name(group_name)} WHERE #{foreign_key} = #{current_id}"
|
126
131
|
end
|
127
132
|
end
|
data/lib/property/schema.rb
CHANGED
data/property.gemspec
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{property}
|
8
|
-
s.version = "0.9.
|
8
|
+
s.version = "0.9.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Renaud Kern", "Gaspard Bucher"]
|
@@ -45,6 +45,7 @@ Gem::Specification.new do |s|
|
|
45
45
|
"test/unit/property/declaration_test.rb",
|
46
46
|
"test/unit/property/dirty_test.rb",
|
47
47
|
"test/unit/property/index_complex_test.rb",
|
48
|
+
"test/unit/property/index_custom_test.rb",
|
48
49
|
"test/unit/property/index_foreign_test.rb",
|
49
50
|
"test/unit/property/index_simple_test.rb",
|
50
51
|
"test/unit/property/validation_test.rb",
|
@@ -67,6 +68,7 @@ Gem::Specification.new do |s|
|
|
67
68
|
"test/unit/property/declaration_test.rb",
|
68
69
|
"test/unit/property/dirty_test.rb",
|
69
70
|
"test/unit/property/index_complex_test.rb",
|
71
|
+
"test/unit/property/index_custom_test.rb",
|
70
72
|
"test/unit/property/index_foreign_test.rb",
|
71
73
|
"test/unit/property/index_simple_test.rb",
|
72
74
|
"test/unit/property/validation_test.rb",
|
data/test/fixtures.rb
CHANGED
@@ -92,10 +92,18 @@ begin
|
|
92
92
|
t.string 'key'
|
93
93
|
t.text 'value'
|
94
94
|
end
|
95
|
+
|
96
|
+
# custom or legacy index table
|
97
|
+
create_table 'contacts' do |t|
|
98
|
+
t.integer 'employee_id'
|
99
|
+
t.string 'name'
|
100
|
+
t.string 'other_name'
|
101
|
+
end
|
95
102
|
end
|
96
103
|
end
|
97
104
|
|
98
105
|
ActiveRecord::Base.establish_connection(:adapter=>'sqlite3', :database=>':memory:')
|
106
|
+
# ActiveRecord::Base.logger = Logger.new(STDOUT)
|
99
107
|
ActiveRecord::Migration.verbose = false
|
100
108
|
#PropertyMigration.migrate(:down)
|
101
109
|
PropertyMigration.migrate(:up)
|
@@ -58,10 +58,10 @@ class BehaviorTest < Test::Unit::TestCase
|
|
58
58
|
assert column.indexed?
|
59
59
|
end
|
60
60
|
|
61
|
-
should 'return a list of
|
61
|
+
should 'return a list of indices on indices' do
|
62
62
|
subject.property.string('rolodex', :index => true)
|
63
63
|
subject.property.integer('foobar', :index => true)
|
64
|
-
assert_equal %w{integer string}, subject.
|
64
|
+
assert_equal %w{integer string}, subject.indices.map {|i| i[0].to_s }.sort
|
65
65
|
end
|
66
66
|
end # A Behavior
|
67
67
|
|
@@ -53,7 +53,7 @@ class IndexComplexTest < ActiveSupport::TestCase
|
|
53
53
|
assert_kind_of Hash, subject.index_groups
|
54
54
|
end
|
55
55
|
|
56
|
-
should 'group
|
56
|
+
should 'group indices by type' do
|
57
57
|
assert_equal %w{integer text}, subject.index_groups.keys.map(&:to_s).sort
|
58
58
|
end
|
59
59
|
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'fixtures'
|
3
|
+
|
4
|
+
class IndexCustomTest < ActiveSupport::TestCase
|
5
|
+
class IndexedContact < ActiveRecord::Base
|
6
|
+
set_table_name :contacts
|
7
|
+
|
8
|
+
def self.set_property_index(person, indices)
|
9
|
+
if index = first(:conditions => ['employee_id = ?', person.id])
|
10
|
+
index.update_attributes(indices)
|
11
|
+
else
|
12
|
+
create(indices.merge(:employee_id => person.id))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.delete_property_index(person)
|
17
|
+
delete_all(['employee_id = ?', person.id])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Index definition class with a legacy table for indices
|
22
|
+
class Person < ActiveRecord::Base
|
23
|
+
include Property
|
24
|
+
set_table_name :employees
|
25
|
+
|
26
|
+
property do |p|
|
27
|
+
p.string 'name'
|
28
|
+
p.string 'first_name'
|
29
|
+
|
30
|
+
p.index(IndexedContact) do |r| # r = record
|
31
|
+
{
|
32
|
+
'name' => "#{r.name}!", # just to test renaming
|
33
|
+
'other_name' => r.first_name
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'A schema from a class with a custom indexer' do
|
40
|
+
subject do
|
41
|
+
Person.schema
|
42
|
+
end
|
43
|
+
|
44
|
+
should 'return a Hash on index_groups' do
|
45
|
+
assert_kind_of Hash, subject.index_groups
|
46
|
+
end
|
47
|
+
|
48
|
+
should 'group indices by type' do
|
49
|
+
assert_equal %w{IndexCustomTest::IndexedContact}, subject.index_groups.keys.map(&:to_s).sort
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'A class with complex index definition' do
|
54
|
+
subject do
|
55
|
+
Person
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'on record creation' do
|
59
|
+
should 'create index entries in the custom table' do
|
60
|
+
assert_difference('IndexedContact.count', 1) do
|
61
|
+
Person.create('name' => 'Sadr', 'first_name' => 'Shadi')
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
should 'store key and value pairs linked to the model' do
|
66
|
+
person = Person.create('name' => 'Sadr', 'first_name' => 'Shadi')
|
67
|
+
index = IndexedContact.first(:conditions => {:employee_id => person.id})
|
68
|
+
assert_equal 'Sadr!', index.name
|
69
|
+
assert_equal 'Shadi', index.other_name
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'on record update' do
|
74
|
+
setup do
|
75
|
+
@person = Person.create('name' => 'Sadr', 'first_name' => 'Shadi')
|
76
|
+
end
|
77
|
+
|
78
|
+
should 'update index entries' do
|
79
|
+
index = IndexedContact.first(:conditions => {:employee_id => @person.id})
|
80
|
+
assert_difference('IndexedContact.count', 0) do
|
81
|
+
@person.update_attributes('first_name' => 'Shiva', 'name' => 'Nazar Ahari')
|
82
|
+
end
|
83
|
+
|
84
|
+
index = IndexedContact.find(index.id) # reload (make sure the record has been updated, not recreated)
|
85
|
+
|
86
|
+
assert_equal 'Nazar Ahari!', index.name
|
87
|
+
assert_equal 'Shiva', index.other_name
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'on record destruction' do
|
92
|
+
should 'remove index entry' do
|
93
|
+
person = Person.create('first_name' => 'Gaspard', 'name' => 'Bucher')
|
94
|
+
assert_difference('IndexedContact.count', -1) do
|
95
|
+
person.destroy
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -39,7 +39,7 @@ class IndexSimpleTest < ActiveSupport::TestCase
|
|
39
39
|
assert_kind_of Hash, subject.index_groups
|
40
40
|
end
|
41
41
|
|
42
|
-
should 'group
|
42
|
+
should 'group indices by type' do
|
43
43
|
assert_equal %w{integer string}, subject.index_groups.keys.map(&:to_s).sort
|
44
44
|
end
|
45
45
|
end
|
@@ -116,7 +116,7 @@ class IndexSimpleTest < ActiveSupport::TestCase
|
|
116
116
|
@dog = Dog.create('name' => 'Pavlov')
|
117
117
|
end
|
118
118
|
|
119
|
-
should 'not alter
|
119
|
+
should 'not alter indices' do
|
120
120
|
assert_difference('IndexedIntegerEmp.count', 0) do
|
121
121
|
assert_raises(Exception) do
|
122
122
|
@dog.update_attributes('name' => 'raise')
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 9
|
8
|
-
-
|
9
|
-
version: 0.9.
|
8
|
+
- 1
|
9
|
+
version: 0.9.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Renaud Kern
|
@@ -80,6 +80,7 @@ files:
|
|
80
80
|
- test/unit/property/declaration_test.rb
|
81
81
|
- test/unit/property/dirty_test.rb
|
82
82
|
- test/unit/property/index_complex_test.rb
|
83
|
+
- test/unit/property/index_custom_test.rb
|
83
84
|
- test/unit/property/index_foreign_test.rb
|
84
85
|
- test/unit/property/index_simple_test.rb
|
85
86
|
- test/unit/property/validation_test.rb
|
@@ -125,6 +126,7 @@ test_files:
|
|
125
126
|
- test/unit/property/declaration_test.rb
|
126
127
|
- test/unit/property/dirty_test.rb
|
127
128
|
- test/unit/property/index_complex_test.rb
|
129
|
+
- test/unit/property/index_custom_test.rb
|
128
130
|
- test/unit/property/index_foreign_test.rb
|
129
131
|
- test/unit/property/index_simple_test.rb
|
130
132
|
- test/unit/property/validation_test.rb
|