hgimenez-peegee 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +14 -5
- data/VERSION.yml +1 -1
- data/lib/peegee.rb +8 -6
- data/lib/peegee/clustering.rb +15 -15
- data/lib/peegee/configuration.rb +23 -0
- data/lib/peegee/table.rb +69 -11
- data/lib/peegee/table_does_not_exist_error.rb +4 -0
- data/peegee.gemspec +16 -7
- data/spec/factories.rb +9 -0
- data/spec/fixtures/activerecord_models.rb +8 -0
- data/spec/fixtures/structure.sql +62 -0
- data/spec/peegee_helper.rb +71 -0
- data/spec/spec_helper.rb +5 -1
- data/spec/unit/peegee_table_spec.rb +95 -0
- metadata +13 -4
- data/spec/peegee_spec.rb +0 -7
data/README.textile
CHANGED
@@ -7,8 +7,6 @@ h1. Why?
|
|
7
7
|
This project started with the need to improve the performance of PostgreSQL's CLUSTER command. While clustering your database tables improves query performance significantly, the actual process of clustering takes unacceptable amounts of time. For instance, it may take roughly 20 hours on a moderately big set of tables (around 60GB). Your milage may vary, of course.
|
8
8
|
Refactoring the clustering functionality surfaced a clean set of utilities that resulted in the creation of this gem. Some are useful, and some are just pointless.
|
9
9
|
|
10
|
-
The initial code for this gem was created during the Boston.rb hackfest at Thoughtbot, on April 7th, 2009.
|
11
|
-
|
12
10
|
h1. Example usage
|
13
11
|
|
14
12
|
Assuming we're in a Rails app, you can simply do:
|
@@ -27,12 +25,11 @@ After the call to drop, the @dependent_foreign_keys instance variable on the peo
|
|
27
25
|
The strategy used for clustering a table is to store all dependencies in order to restore them later (as viewed above), and move all of the table's data on the order given by a certain index. This is all executed in a database transaction in case it blows up. The result should be just like the pgsql native CLUSTER command:
|
28
26
|
<pre><code>people_table.cluster('people_pk') #must specify an index by which to cluster</code></pre>
|
29
27
|
|
30
|
-
|
28
|
+
h1. Todo
|
31
29
|
|
32
30
|
The first order of business will be to create specs where applicable.
|
33
31
|
|
34
|
-
Then, the idea is to keep adding functionality that may be useful for DBAs or application developers and other PostgreSQL users. Some that come to mind are:
|
35
|
-
|
32
|
+
Then, the idea is to keep adding functionality that may be useful for DBAs or application developers and other PostgreSQL users. Some that come to mind are:
|
36
33
|
* Ability to clean out all of table's index and foreign key names, following a given pattern. On occasions, table names are altered leaving behind pesky legacy names for related objects.
|
37
34
|
* Ability to identify database stinks. For instance:
|
38
35
|
** tables without primary keys, or indexes (which are not pure join tables)
|
@@ -49,6 +46,18 @@ I would also like to make this code ORM agnostic. Right now, it depends on Activ
|
|
49
46
|
|
50
47
|
Please fork away and help improve it.
|
51
48
|
|
49
|
+
h1. Revision History
|
50
|
+
|
51
|
+
* Version 0.1.1 (April 13th, 2009):
|
52
|
+
** Set up RSpec testing environment. Started creating test suite.
|
53
|
+
** Added the Configuration singleton class, which for now allows the user to specify which indexes to cluster each table by.
|
54
|
+
** Added exists? class method to Peegee::Table class. Creating a Peegee::Table instance now fails if the table does not exist in the database.
|
55
|
+
** Added bang (!) methods to Peegee::Table class, which force the lookup of foreign_keys!, constraints!, indexes!, etc, even when they're already cached.
|
56
|
+
** Fixed bug in cluster method.
|
57
|
+
|
58
|
+
* Version 0.1.0 (April 10th, 2009):
|
59
|
+
** First release.
|
60
|
+
|
52
61
|
h1. License
|
53
62
|
|
54
63
|
Copyright (c) 2009 Harold A. Gimenez, released under the MIT license.
|
data/VERSION.yml
CHANGED
data/lib/peegee.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
require 'peegee/table'
|
2
|
-
require 'peegee/constraint'
|
3
|
-
require 'peegee/unique_constraint'
|
4
|
-
require 'peegee/primary_key'
|
5
|
-
require 'peegee/foreign_key'
|
6
|
-
require 'peegee/index'
|
1
|
+
require File.dirname(__FILE__) + '/peegee/table'
|
2
|
+
require File.dirname(__FILE__) + '/peegee/constraint'
|
3
|
+
require File.dirname(__FILE__) + '/peegee/unique_constraint'
|
4
|
+
require File.dirname(__FILE__) + '/peegee/primary_key'
|
5
|
+
require File.dirname(__FILE__) + '/peegee/foreign_key'
|
6
|
+
require File.dirname(__FILE__) + '/peegee/index'
|
7
|
+
require File.dirname(__FILE__) + '/peegee/configuration'
|
8
|
+
require File.dirname(__FILE__) + '/peegee/table_does_not_exist_error'
|
data/lib/peegee/clustering.rb
CHANGED
@@ -3,32 +3,34 @@ module Peegee
|
|
3
3
|
|
4
4
|
# Clusters this table. See http://www.postgresql.org/docs/8.3/interactive/sql-cluster.html
|
5
5
|
# Optionally specify the index to cluster by (by name or Peegee::Index object).
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
6
|
+
# The index to use would ideally be specified using the <tt>Peegee::Configuration</tt>
|
7
|
+
# instance. If the index is not specified, it will try to induce which index to
|
8
|
+
# use by looking at postgresql's internals.
|
9
|
+
# If a proper index can't be found, an exception will be raised.
|
9
10
|
def cluster(cluster_index = nil)
|
10
11
|
cluster_index = find_cluster_index(cluster_index)
|
11
12
|
puts "Cluster index is: #{cluster_index.inspect}"
|
12
13
|
puts "Cluster index type is: #{cluster_index.class.name}"
|
13
|
-
dependencies = remember_dependencies
|
14
|
+
dependencies, dependent_foreign_keys = remember_dependencies
|
14
15
|
ActiveRecord::Base.transaction do
|
15
|
-
|
16
|
-
dependencies.map { |dep| dep.drop }
|
16
|
+
dependent_foreign_keys.map { |dfk| dfk.drop }
|
17
17
|
create_tmp_table
|
18
18
|
move_data(cluster_index)
|
19
19
|
drop_original_and_rename_tmp_table
|
20
20
|
dependencies.reverse.map { |dep| dep.create }
|
21
|
+
dependent_foreign_keys.map { |dfk| dfk.create }
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
25
|
private
|
25
26
|
|
26
|
-
# Retrieves the Peegee::Index object that will be used
|
27
|
-
# for clustering this table. The cluster_index parameter can
|
28
|
-
# be either a string representing the index name, or a Peegee::Index object.
|
27
|
+
# Retrieves the <tt>Peegee::Index</tt> object that will be used
|
28
|
+
# for clustering this table. The <tt>cluster_index</tt> parameter can
|
29
|
+
# be either a string representing the index name, or a <tt>Peegee::Index</tt> object.
|
29
30
|
# Raises an exception if either a proper index was not found
|
30
|
-
# or more than one index was found given a cluster_index name.
|
31
|
+
# or more than one index was found given a <tt>cluster_index</tt> name.
|
31
32
|
def find_cluster_index(cluster_index)
|
33
|
+
cluster_index = Peegee::Configuration.instance.cluster_indexes[self.table_name.to_sym].to_s if cluster_index.nil?
|
32
34
|
return cluster_index if cluster_index.kind_of?(Peegee::Index)
|
33
35
|
the_index = nil
|
34
36
|
if cluster_index #cluster_index is specified
|
@@ -67,7 +69,7 @@ module Peegee
|
|
67
69
|
# drop the table being clustered (to clean out the dependency on
|
68
70
|
# the sequence).
|
69
71
|
# This method is called after having created the tmp table, otherwise it will fail.
|
70
|
-
|
72
|
+
#--
|
71
73
|
# The method for finding a table's sequence is hackish.
|
72
74
|
# TODO: Find a better method for finding a table's sequence.
|
73
75
|
def reasign_sequence_to_tmp_table
|
@@ -89,8 +91,6 @@ module Peegee
|
|
89
91
|
seq[2].match /nextval\('[\"']{0,2}(\w*)[\"']{0,2}.*'::regclass\)/
|
90
92
|
sequence_name = $1 #the match above...
|
91
93
|
ActiveRecord::Base.connection.execute("ALTER SEQUENCE \"#{sequence_name}\" OWNED BY #{@table_name}_tmp.#{seq[0]}")
|
92
|
-
else
|
93
|
-
puts "\n\n\t*****#{@table_name} apparently doesn't have a sequence"
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
@@ -110,8 +110,8 @@ module Peegee
|
|
110
110
|
# dependent foreign keys, and indexes.
|
111
111
|
def remember_dependencies
|
112
112
|
dependencies = []
|
113
|
-
dependencies << foreign_keys <<
|
114
|
-
dependencies.flatten
|
113
|
+
dependencies << foreign_keys << indexes
|
114
|
+
return dependencies.flatten, dependent_foreign_keys
|
115
115
|
end
|
116
116
|
|
117
117
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
module Peegee
|
3
|
+
|
4
|
+
class Configuration
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
# The mappings between tables and indexes, used
|
8
|
+
# for executing Peegee's implementation of the Postgres CLUSTER command.
|
9
|
+
# The hash maps tables to indexes. You may pass
|
10
|
+
# either a 'string' or a :symbol.
|
11
|
+
# For example:
|
12
|
+
# <tt>cluster_indexes = {:posts => :ix_posts_on_active_and_created_at,
|
13
|
+
# 'users' => 'ix_user_on_active_and_person_id'}</tt>
|
14
|
+
@cluster_indexes = {}
|
15
|
+
attr_accessor :cluster_indexes
|
16
|
+
|
17
|
+
def self.run(&block)
|
18
|
+
yield Configuration.instance
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
data/lib/peegee/table.rb
CHANGED
@@ -3,35 +3,93 @@ module Peegee
|
|
3
3
|
|
4
4
|
class Table
|
5
5
|
include Peegee::Clustering
|
6
|
+
|
7
|
+
attr_accessor :table_name
|
6
8
|
|
9
|
+
# Creates a new instance of Peegee::Table.
|
10
|
+
# Receives an +opts+ hash paramater, which expects
|
11
|
+
# to contain a key called <tt>:table_name</tt>.
|
12
|
+
# A TableDoesNotExistError is thrown if the table
|
13
|
+
# with the supplied name is not found in the database.
|
7
14
|
def initialize(opts = {})
|
8
|
-
|
15
|
+
if Peegee::Table.exists?(opts[:table_name])
|
16
|
+
@table_name = opts[:table_name]
|
17
|
+
else
|
18
|
+
raise TableDoesNotExistError, "Table #{opts[:table_name]} does not exist", caller
|
19
|
+
end
|
9
20
|
end
|
10
21
|
|
22
|
+
# Class method that finds out if a given table name exists in the database.
|
23
|
+
def self.exists?(table_name)
|
24
|
+
sql = "select * from pg_class where relname = '#{table_name}' and relkind = 'r'"
|
25
|
+
!(ActiveRecord::Base.connection.execute(sql).entries.flatten.size == 0)
|
26
|
+
end
|
27
|
+
|
28
|
+
# The postgresql OID for this table.
|
11
29
|
def oid
|
12
30
|
@oid ||= fetch_oid
|
13
31
|
end
|
14
32
|
|
33
|
+
# Returns an array of all foreign keys for this table, as <tt>Peegee::ForeignKey</tt> objects.
|
34
|
+
# The first time this method is called, foreign keys are retrieved from the database
|
35
|
+
# and cached in an instance variable. Subsequence calls will use the cached values.
|
36
|
+
# To force a lookup of foreign keys use the <tt>foreign_keys!</tt> method instead.
|
15
37
|
def foreign_keys
|
16
38
|
@foreign_keys ||= fetch_foreign_keys
|
17
39
|
end
|
18
40
|
|
41
|
+
def foreign_keys!
|
42
|
+
fetch_foreign_keys
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns an array of all dependent foreign keys for this table, as <tt>Peegee::ForeignKey</tt> objects.
|
46
|
+
# The first time this method is called, dependent foreign keys are retrieved from the database
|
47
|
+
# and cached in an instance variable. Subsequence calls will use the cached values.
|
48
|
+
# To force a lookup of dependent foreign keys use the <tt>dependent_foreign_keys!</tt> method instead.
|
19
49
|
def dependent_foreign_keys
|
20
50
|
@dependent_foreign_keys ||= fetch_dependent_foreign_keys
|
21
51
|
end
|
22
52
|
|
23
|
-
def
|
24
|
-
|
53
|
+
def dependent_foreign_keys!
|
54
|
+
fetch_dependent_foreign_keys
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns an array of primary keys for this table, as <tt>Peegee::PrimaryKey</tt> objects.
|
58
|
+
# The first time this method is called, primary keys are retrieved from the database
|
59
|
+
# and cached in an instance variable. Subsequence calls will use the cached values.
|
60
|
+
# To force a lookup of primary keys use the <tt>primary_key!</tt> method instead.
|
61
|
+
def primary_key
|
62
|
+
@primary_key ||= fetch_primary_key
|
63
|
+
end
|
64
|
+
|
65
|
+
def primary_key!
|
66
|
+
fetch_primary_key
|
25
67
|
end
|
26
68
|
|
69
|
+
# Returns an array of unique constraints for this table, as <tt>Peegee::UniqueConstraint</tt> objects.
|
70
|
+
# The first time this method is called, unique constraints are retrieved from the database
|
71
|
+
# and cached in an instance variable. Subsequence calls will use the cached values.
|
72
|
+
# To force a lookup of unique constraints use the <tt>unique_constraints!</tt> method instead.
|
27
73
|
def unique_constraints
|
28
74
|
@unique_constraints ||= fetch_unique_constraints
|
29
75
|
end
|
30
76
|
|
77
|
+
def unique_constraints!
|
78
|
+
fetch_unique_constraints
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns an array of indexes for this table, as <tt>Peegee::indexes</tt> objects.
|
82
|
+
# The first time this method is called, unique constraints are retrieved from the database
|
83
|
+
# and cached in an instance variable. Subsequence calls will use the cached values.
|
84
|
+
# To force a lookup of unique constraints use the <tt>indexes!</tt> method instead.
|
31
85
|
def indexes
|
32
86
|
@indexes ||= fetch_indexes
|
33
87
|
end
|
34
88
|
|
89
|
+
def indexes!
|
90
|
+
fetch_indexes
|
91
|
+
end
|
92
|
+
|
35
93
|
# Returns the DDL for this table as a string.
|
36
94
|
def ddl
|
37
95
|
sql = 'SELECT a.attname, ' +
|
@@ -62,8 +120,8 @@ module Peegee
|
|
62
120
|
ddl.gsub('\\','')
|
63
121
|
end
|
64
122
|
|
65
|
-
|
66
123
|
private
|
124
|
+
# Retrieves this table's OID from the database.
|
67
125
|
def fetch_oid
|
68
126
|
sql = 'SELECT c.oid ' +
|
69
127
|
' FROM pg_catalog.pg_class c ' +
|
@@ -73,9 +131,8 @@ module Peegee
|
|
73
131
|
return ActiveRecord::Base.connection.execute(sql).entries[0]
|
74
132
|
end
|
75
133
|
|
76
|
-
|
77
|
-
|
78
|
-
def fetch_primary_keys
|
134
|
+
# Retrieves this table's primary key from the database.
|
135
|
+
def fetch_primary_key
|
79
136
|
sql = 'select conname ' +
|
80
137
|
' , pg_get_constraintdef(pk.oid, true) as foreign_key ' +
|
81
138
|
' from pg_catalog.pg_constraint pk ' +
|
@@ -92,7 +149,7 @@ module Peegee
|
|
92
149
|
end
|
93
150
|
end
|
94
151
|
|
95
|
-
|
152
|
+
# Retrieves this table's unique constraints from the database.
|
96
153
|
def fetch_unique_constraints
|
97
154
|
sql = 'select conname ' +
|
98
155
|
' , pg_get_constraintdef(uc.oid, true) as foreign_key ' +
|
@@ -110,6 +167,7 @@ module Peegee
|
|
110
167
|
end
|
111
168
|
end
|
112
169
|
|
170
|
+
# Retrieves this table's foreign keys from the database.
|
113
171
|
def fetch_foreign_keys
|
114
172
|
sql = 'select conname ' +
|
115
173
|
' , pg_get_constraintdef(fk.oid, true) as foreign_key ' +
|
@@ -128,6 +186,8 @@ module Peegee
|
|
128
186
|
|
129
187
|
end
|
130
188
|
|
189
|
+
# Retrieves this table's dependent foreign keys from the database.
|
190
|
+
# A dependent foreign key, is any foreign key that references this table.
|
131
191
|
def fetch_dependent_foreign_keys
|
132
192
|
sql = 'select pg_constraint.conname,' +
|
133
193
|
'dep_table.relname, ' +
|
@@ -144,6 +204,7 @@ module Peegee
|
|
144
204
|
end
|
145
205
|
end
|
146
206
|
|
207
|
+
# Retrieves indexes for this table from the database.
|
147
208
|
def fetch_indexes
|
148
209
|
sql = "SELECT pg_get_indexdef(i.indexrelid, 0, true) as index_definition " +
|
149
210
|
", c2.relname as index_name " +
|
@@ -151,7 +212,6 @@ module Peegee
|
|
151
212
|
"FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i " +
|
152
213
|
"WHERE c.oid = '#{@table_name}'::regclass AND c.oid = i.indrelid AND i.indexrelid = c2.oid " #+
|
153
214
|
#"AND i.indisprimary = false" #don't get primary key constraints...
|
154
|
-
#indexes = ActiveRecord::Base.connection.execute(sql).entries.collect{ |i| i[0] + ';'}
|
155
215
|
indexes = ActiveRecord::Base.connection.execute(sql).entries
|
156
216
|
return indexes.collect do |i|
|
157
217
|
Peegee::Index.new(:table_name => @table_name,
|
@@ -161,8 +221,6 @@ module Peegee
|
|
161
221
|
end
|
162
222
|
end
|
163
223
|
|
164
|
-
|
165
|
-
|
166
224
|
end
|
167
225
|
|
168
226
|
end
|
data/peegee.gemspec
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
|
-
Gem::Specification.new do |s|
|
3
|
+
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{peegee}
|
5
|
-
s.version = "0.1.
|
5
|
+
s.version = "0.1.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Harold A. Gimenez"]
|
9
|
-
s.date = %q{2009-04-
|
9
|
+
s.date = %q{2009-04-13}
|
10
10
|
s.email = %q{harold.gimenez@gmail.com}
|
11
11
|
s.extra_rdoc_files = [
|
12
12
|
"README.textile"
|
@@ -17,15 +17,21 @@ Gem::Specification.new do |s|
|
|
17
17
|
"VERSION.yml",
|
18
18
|
"lib/peegee.rb",
|
19
19
|
"lib/peegee/clustering.rb",
|
20
|
+
"lib/peegee/configuration.rb",
|
20
21
|
"lib/peegee/constraint.rb",
|
21
22
|
"lib/peegee/foreign_key.rb",
|
22
23
|
"lib/peegee/index.rb",
|
23
24
|
"lib/peegee/primary_key.rb",
|
24
25
|
"lib/peegee/table.rb",
|
26
|
+
"lib/peegee/table_does_not_exist_error.rb",
|
25
27
|
"lib/peegee/unique_constraint.rb",
|
26
28
|
"peegee.gemspec",
|
27
|
-
"spec/
|
28
|
-
"spec/
|
29
|
+
"spec/factories.rb",
|
30
|
+
"spec/fixtures/activerecord_models.rb",
|
31
|
+
"spec/fixtures/structure.sql",
|
32
|
+
"spec/peegee_helper.rb",
|
33
|
+
"spec/spec_helper.rb",
|
34
|
+
"spec/unit/peegee_table_spec.rb"
|
29
35
|
]
|
30
36
|
s.has_rdoc = true
|
31
37
|
s.homepage = %q{http://github.com/hgimenez/peegee}
|
@@ -35,8 +41,11 @@ Gem::Specification.new do |s|
|
|
35
41
|
s.rubygems_version = %q{1.3.1}
|
36
42
|
s.summary = %q{A set of utilities for doing PostgreSQL database related stuffs from ruby.}
|
37
43
|
s.test_files = [
|
38
|
-
"spec/
|
39
|
-
"spec/
|
44
|
+
"spec/factories.rb",
|
45
|
+
"spec/fixtures/activerecord_models.rb",
|
46
|
+
"spec/peegee_helper.rb",
|
47
|
+
"spec/spec_helper.rb",
|
48
|
+
"spec/unit/peegee_table_spec.rb"
|
40
49
|
]
|
41
50
|
|
42
51
|
if s.respond_to? :specification_version then
|
data/spec/factories.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
class User < ActiveRecord::Base
|
2
|
+
has_many :posts#, :foreign_key => 'created_by_id'
|
3
|
+
end
|
4
|
+
|
5
|
+
class Post < ActiveRecord::Base
|
6
|
+
belongs_to :created_by, :class_name => User, :foreign_key => 'created_by_id'
|
7
|
+
belongs_to :updated_by, :class_name => User, :foreign_key => 'updated_by_id'
|
8
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
DROP TABLE IF EXISTS posts;
|
2
|
+
DROP TABLE IF EXISTS users;
|
3
|
+
|
4
|
+
-- Table: users
|
5
|
+
CREATE TABLE users
|
6
|
+
(
|
7
|
+
id serial NOT NULL,
|
8
|
+
"name" character varying(100),
|
9
|
+
email character varying(255) NOT NULL,
|
10
|
+
"login" character varying(40) NOT NULL DEFAULT ''::character varying,
|
11
|
+
"password" character varying(40),
|
12
|
+
"admin" boolean NOT NULL DEFAULT false,
|
13
|
+
notes text,
|
14
|
+
lock_version integer DEFAULT 0,
|
15
|
+
salt character varying(255),
|
16
|
+
created_at timestamp without time zone,
|
17
|
+
updated_at timestamp without time zone,
|
18
|
+
CONSTRAINT users_pkey PRIMARY KEY (id)
|
19
|
+
)
|
20
|
+
WITH (OIDS=FALSE);
|
21
|
+
ALTER TABLE users OWNER TO peegee;
|
22
|
+
|
23
|
+
-- Index: "login"
|
24
|
+
DROP INDEX IF EXISTS "login";
|
25
|
+
|
26
|
+
CREATE UNIQUE INDEX "login"
|
27
|
+
ON users
|
28
|
+
USING btree
|
29
|
+
(login);
|
30
|
+
|
31
|
+
-- Table: posts
|
32
|
+
|
33
|
+
|
34
|
+
CREATE TABLE posts
|
35
|
+
(
|
36
|
+
id serial NOT NULL,
|
37
|
+
title character varying(255),
|
38
|
+
body text,
|
39
|
+
status_id integer NOT NULL DEFAULT 1,
|
40
|
+
created_at timestamp without time zone NOT NULL,
|
41
|
+
updated_at timestamp without time zone NOT NULL,
|
42
|
+
published_at timestamp without time zone,
|
43
|
+
created_by_id integer NOT NULL,
|
44
|
+
updated_by_id integer NOT NULL,
|
45
|
+
CONSTRAINT posts_pkey PRIMARY KEY (id),
|
46
|
+
CONSTRAINT fk_posts_created_by_id FOREIGN KEY (created_by_id)
|
47
|
+
REFERENCES users (id) MATCH SIMPLE
|
48
|
+
ON UPDATE NO ACTION ON DELETE NO ACTION,
|
49
|
+
CONSTRAINT fk_posts_updated_by_id FOREIGN KEY (updated_by_id)
|
50
|
+
REFERENCES users (id) MATCH SIMPLE
|
51
|
+
ON UPDATE NO ACTION ON DELETE NO ACTION
|
52
|
+
)
|
53
|
+
WITH (OIDS=FALSE);
|
54
|
+
|
55
|
+
ALTER TABLE posts OWNER TO peegee;
|
56
|
+
|
57
|
+
-- Index: ix_posts_on_status_id
|
58
|
+
|
59
|
+
CREATE INDEX ix_posts_on_status_id
|
60
|
+
ON posts
|
61
|
+
USING btree
|
62
|
+
(status_id);
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
prefix = defined?(JRUBY_VERSION) ? 'jdbc' : ''
|
3
|
+
require "active_record/connection_adapters/#{prefix}postgresql_adapter"
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
class PeegeeHelper
|
7
|
+
|
8
|
+
attr_accessor :host, :username, :password
|
9
|
+
#attr_reader :path
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@path = File.expand_path(File.dirname(__FILE__))
|
13
|
+
@host = 'localhost'
|
14
|
+
@username = 'peegee'
|
15
|
+
@password = 'peegee'
|
16
|
+
|
17
|
+
# if you want to overwrite defaults for testing,
|
18
|
+
# do it on spec/fixtures/database.yml
|
19
|
+
if File.exist?('spec/fixtures/database.yml')
|
20
|
+
config = YAML.load(File.open('spec/fixtures/database.yml'))
|
21
|
+
@host = config['host']
|
22
|
+
@username = config['username']
|
23
|
+
@password = config['password']
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup_pgsql
|
28
|
+
#Adapter => http://raa.ruby-lang.org/project/postgres-pr/
|
29
|
+
ActiveRecord::Base.establish_connection(
|
30
|
+
:adapter => 'postgresql',
|
31
|
+
:database => 'peegee_test',
|
32
|
+
:username => @username,
|
33
|
+
:password => @password,
|
34
|
+
:host => @host
|
35
|
+
)
|
36
|
+
|
37
|
+
ActiveRecord::Base.logger = Logger.new(active_record_log_file)
|
38
|
+
|
39
|
+
structure = File.open('spec/fixtures/structure.sql') { |f| f.read.chomp }
|
40
|
+
structure.split(';').each { |sql|
|
41
|
+
ActiveRecord::Base.connection.execute sql unless sql.start_with? '--'
|
42
|
+
}
|
43
|
+
|
44
|
+
#File.open('spec/fixtures/data.sql') { |f|
|
45
|
+
#while line = f.gets
|
46
|
+
#ActiveRecord::Base.connection.execute line unless line.blank?
|
47
|
+
#end
|
48
|
+
#}
|
49
|
+
end
|
50
|
+
|
51
|
+
def configure_peegee
|
52
|
+
Peegee::Configuration.run do |config|
|
53
|
+
config.cluster_indexes = {
|
54
|
+
:users => :users_pkey,
|
55
|
+
:posts => :ix_posts_on_status_id
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def reset
|
61
|
+
setup_pgsql
|
62
|
+
end
|
63
|
+
|
64
|
+
AR_LOGFILE = 'tmp/active_record.log'
|
65
|
+
private
|
66
|
+
def active_record_log_file
|
67
|
+
FileUtils.mkdir_p 'tmp'
|
68
|
+
File.new(AR_LOGFILE, 'a') unless File.exists?(AR_LOGFILE)
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,6 +4,10 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
4
4
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
5
5
|
require 'peegee'
|
6
6
|
|
7
|
+
require 'spec/peegee_helper'
|
8
|
+
require 'factory_girl'
|
9
|
+
|
7
10
|
Spec::Runner.configure do |config|
|
8
|
-
|
11
|
+
Kernel.const_set :RAILS_ROOT, "#{Dir.pwd}/tmp" unless defined?(RAILS_ROOT)
|
12
|
+
require 'spec/fixtures/activerecord_models'
|
9
13
|
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe 'Peegee::Table' do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
@peegee_helper = PeegeeHelper.new
|
7
|
+
@peegee_helper.reset
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'when creating a Peegee::Table object' do
|
11
|
+
describe 'when the table does not exist in the DB' do
|
12
|
+
it 'should raise an error' do
|
13
|
+
lambda {
|
14
|
+
Peegee::Table.new(:table_name => 'foo')
|
15
|
+
}.should raise_error(
|
16
|
+
Peegee::TableDoesNotExistError
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'when the table exists on the DB' do
|
22
|
+
before :each do
|
23
|
+
@users_table = Peegee::Table.new(:table_name => 'users')
|
24
|
+
end
|
25
|
+
it 'should create a Peegee::Table instance' do
|
26
|
+
@users_table.should be_kind_of(Peegee::Table)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'clustering a table' do
|
32
|
+
|
33
|
+
def do_cluster
|
34
|
+
@users_table.cluster
|
35
|
+
end
|
36
|
+
|
37
|
+
before :each do
|
38
|
+
@peegee_helper.configure_peegee
|
39
|
+
3.times { Factory.create(:user) }
|
40
|
+
@users = User.all
|
41
|
+
@users_table = Peegee::Table.new(:table_name => 'users')
|
42
|
+
@foreign_keys = @users_table.foreign_keys
|
43
|
+
@dependent_foreign_keys = @users_table.dependent_foreign_keys
|
44
|
+
@primary_key = @users_table.primary_key
|
45
|
+
@unique_constraints = @users_table.unique_constraints
|
46
|
+
@indexes = @users_table.indexes
|
47
|
+
end
|
48
|
+
|
49
|
+
after :each do
|
50
|
+
User.delete_all
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should maintain all foreign keys on the resulting table' do
|
54
|
+
do_cluster
|
55
|
+
@users_table.foreign_keys!
|
56
|
+
@foreign_keys.each do |fk|
|
57
|
+
@users_table.foreign_keys.should include(fk)
|
58
|
+
end
|
59
|
+
@users_table.foreign_keys.size.should == @foreign_keys.size
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'should maintain all dependent foreign keys on the resulting table' do
|
63
|
+
do_cluster
|
64
|
+
@users_table.dependent_foreign_keys!
|
65
|
+
@dependent_foreign_keys.each do |dpf|
|
66
|
+
@users_table.dependent_foreign_keys.should include(dpf)
|
67
|
+
end
|
68
|
+
@users_table.dependent_foreign_keys.size.should == @dependent_foreign_keys.size
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should maintain all primary key on the resulting table' do
|
72
|
+
do_cluster
|
73
|
+
@users_table.primary_key!
|
74
|
+
@primary_key.each do |pk|
|
75
|
+
@users_table.primary_key.should include(pk)
|
76
|
+
end
|
77
|
+
@users_table.primary_key.size.should == @primary_key.size
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'should maintain all indexes on the resulting table' do
|
81
|
+
do_cluster
|
82
|
+
@users_table.indexes!
|
83
|
+
@indexes.each do |i|
|
84
|
+
@users_table.indexes.should include(i)
|
85
|
+
end
|
86
|
+
@users_table.indexes.size.should == @indexes.size
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should maintain all of the data on the resulting table' do
|
90
|
+
do_cluster
|
91
|
+
@users.should == User.all
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hgimenez-peegee
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Harold A. Gimenez
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-13 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -36,15 +36,21 @@ files:
|
|
36
36
|
- VERSION.yml
|
37
37
|
- lib/peegee.rb
|
38
38
|
- lib/peegee/clustering.rb
|
39
|
+
- lib/peegee/configuration.rb
|
39
40
|
- lib/peegee/constraint.rb
|
40
41
|
- lib/peegee/foreign_key.rb
|
41
42
|
- lib/peegee/index.rb
|
42
43
|
- lib/peegee/primary_key.rb
|
43
44
|
- lib/peegee/table.rb
|
45
|
+
- lib/peegee/table_does_not_exist_error.rb
|
44
46
|
- lib/peegee/unique_constraint.rb
|
45
47
|
- peegee.gemspec
|
46
|
-
- spec/
|
48
|
+
- spec/factories.rb
|
49
|
+
- spec/fixtures/activerecord_models.rb
|
50
|
+
- spec/fixtures/structure.sql
|
51
|
+
- spec/peegee_helper.rb
|
47
52
|
- spec/spec_helper.rb
|
53
|
+
- spec/unit/peegee_table_spec.rb
|
48
54
|
has_rdoc: true
|
49
55
|
homepage: http://github.com/hgimenez/peegee
|
50
56
|
post_install_message:
|
@@ -72,5 +78,8 @@ signing_key:
|
|
72
78
|
specification_version: 2
|
73
79
|
summary: A set of utilities for doing PostgreSQL database related stuffs from ruby.
|
74
80
|
test_files:
|
75
|
-
- spec/
|
81
|
+
- spec/factories.rb
|
82
|
+
- spec/fixtures/activerecord_models.rb
|
83
|
+
- spec/peegee_helper.rb
|
76
84
|
- spec/spec_helper.rb
|
85
|
+
- spec/unit/peegee_table_spec.rb
|