DimaD-daylite-models 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.
@@ -0,0 +1,4 @@
1
+ === 0.1.0 / 11.02.2009
2
+
3
+ * Release
4
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2009 Dmitriy Dzema, Infonium Inc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,25 @@
1
+ History.txt
2
+ LICENSE
3
+ Manifest.txt
4
+ README.markdown
5
+ Rakefile
6
+ app/models/daylite.rb
7
+ app/models/daylite/contact.rb
8
+ app/models/daylite/organization.rb
9
+ app/models/daylite/organization_task_join.rb
10
+ app/models/daylite/project.rb
11
+ app/models/daylite/project_task_join.rb
12
+ app/models/daylite/role.rb
13
+ app/models/daylite/role_type.rb
14
+ app/models/daylite/task.rb
15
+ app/models/daylite/user.rb
16
+ config/database.yml.exmp
17
+ daylite_models.gemspec
18
+ daylite_models.rb
19
+ init.rb
20
+ install.rb
21
+ lib/active_record/connection_adapters/openbase_adapter.rb
22
+ tasks/users_plugin_tasks.rake
23
+ test/daylite_models_plugin_test.rb
24
+ test/test_helper.rb
25
+ uninstall.rb
@@ -0,0 +1,47 @@
1
+ DayliteModels
2
+ ===========
3
+
4
+ This is a set of ActiveRecord classes, designed to work with Daylite 3 by [Marketcircle](www.marketcircle.com).
5
+
6
+ All the classes are in namespace Daylite. For example Daylite projects live in the class Daylite::Project.
7
+
8
+ Models attributes are mapped to usual ruby underscore_notation from Daylite cameCase notation.
9
+
10
+ Usage
11
+ =======
12
+
13
+ You can use this module as rails plugin and as a standalone library.
14
+
15
+ Usage as Rails plugin
16
+ ---------------------
17
+
18
+ Install the plugin
19
+
20
+ ./script/plugin install <path_to_repo>
21
+
22
+
23
+ Add _daylite_ section to you database.yml
24
+
25
+ daylite:
26
+ adapter: openbase
27
+ database: MyOrganization
28
+ host: localhost
29
+ username: my_username
30
+ password: my_password
31
+
32
+
33
+ Add the following line to you environment.rb
34
+
35
+ Daylite::Base.establish_connection(:daylite)
36
+
37
+ You are ready to rock! Now you can use Daylite classes in you application as usual Rails models.
38
+
39
+ Usage as a standalone library
40
+ -----------------------------
41
+ The easiest way is to create file config/database.yml relative to you running script and place _daylite_ config in it (see Usage as Rails plugin for example). After this you need to place
42
+
43
+ require 'daylite_models'
44
+
45
+ somewhere in you initialization code and you are done.
46
+
47
+ Another way is to provide connection info directly through Daylite::Base.establish_connection call. You will need to provide adapter, database, host, username and password params. See ActiveRecord::Base.establish_connection and Openbase documentation for more info.
@@ -0,0 +1,42 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+
6
+ desc 'Generate documentation for the daylite_models plugin.'
7
+ Rake::RDocTask.new(:rdoc) do |rdoc|
8
+ rdoc.rdoc_dir = 'rdoc'
9
+ rdoc.title = 'DayliteModels'
10
+ rdoc.options << '--line-numbers' << '--inline-source'
11
+ rdoc.rdoc_files.include('README.markdown')
12
+ rdoc.rdoc_files.include('lib/**/*.rb')
13
+ end
14
+
15
+ begin
16
+ require 'daylite_models'
17
+ require 'hoe'
18
+
19
+ #oh, shit
20
+ class Hoe
21
+ def extra_deps
22
+ @extra_deps.reject do |x|
23
+ Array(x).first == 'hoe'
24
+ end
25
+ end
26
+ end
27
+
28
+ Hoe.new('daylite-models', DayliteModels::VERSION) do |s|
29
+ s.name = "daylite-models"
30
+ s.version = "0.1.0"
31
+ s.author = "Dmitriy Dzema"
32
+ s.email = "dimad.ag@gmail.com"
33
+ s.summary = "Set of ActiveRecord classes to work with the Daylite 3 database"
34
+
35
+ s.rubyforge_name = 'daylite-models'
36
+ s.remote_rdoc_dir = '' # Release to root
37
+ s.need_zip = true
38
+ s.extra_deps = [ ["activesupport", ">= 2.0.0"], ["activerecord", ">= 2.0.0"], ["activerecord", ">= 0.8.3"]]
39
+ end
40
+ rescue LoadError => e
41
+
42
+ end
@@ -0,0 +1,31 @@
1
+ module Daylite
2
+ end
3
+
4
+ class Daylite::Base < ActiveRecord::Base
5
+ self.abstract_class = true
6
+ self.pluralize_table_names = false
7
+
8
+ set_primary_key "_rowid"
9
+ set_table_name do
10
+ self.name.sub("Daylite::", "")
11
+ end
12
+
13
+ # don't allow to save Daylite::Base objects to DB
14
+ def readonly?
15
+ true
16
+ end
17
+
18
+ def method_missing(symbol, *args)
19
+ guess_attribute = symbol.to_s.camelize(:lower).sub("Id", "ID")
20
+ if result = attributes[guess_attribute]
21
+ self.class.class_eval do
22
+ define_method symbol do
23
+ return attributes[guess_attribute]
24
+ end
25
+ end
26
+ result
27
+ else
28
+ super
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ class Daylite::Contact < Daylite::Base
2
+ has_one :user, :foreign_key => "contactID"
3
+ end
@@ -0,0 +1,17 @@
1
+ class Daylite::Organization < Daylite::Base
2
+ belongs_to :owner, :class_name => "User", :foreign_key => "assignedToID"
3
+
4
+ has_many :organization_task_joins, :foreign_key => "organizationID"
5
+ has_many :tasks, :through => :organization_task_joins
6
+
7
+ has_many :roles, :foreign_key => "organizationID"
8
+ has_many :projects, :through => :roles
9
+
10
+ def projects_tasks
11
+ projects.collect { |p| p.tasks }.flatten
12
+ end
13
+
14
+ def all_tasks
15
+ projects_tasks + tasks
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ class Daylite::OrganizationTaskJoin < Daylite::Base
2
+ belongs_to :organization, :class_name => "Organization", :foreign_key => "organizationID"
3
+ belongs_to :task, :class_name => "Task", :foreign_key => "taskID"
4
+ end
@@ -0,0 +1,24 @@
1
+ class Daylite::Project < Daylite::Base
2
+ belongs_to :owner, :class_name => "User", :foreign_key => "assignedToID"
3
+
4
+ has_many :roles, :foreign_key => "projectID"
5
+ has_many :projects, :through => :roles
6
+
7
+ has_many :project_task_joins, :foreign_key => "projectID"
8
+ has_many :tasks, :through => :project_task_joins
9
+
10
+ def status_codes
11
+ @@status_codes ||= {
12
+ 0 => "In Progress",
13
+ 1 => "Deffered",
14
+ 2 => "Canceled",
15
+ 3 => "Abandoned",
16
+ 4 => "New",
17
+ 7 => "Done",
18
+ }
19
+ end
20
+
21
+ def status_string
22
+ status_codes[attributes["statusCode"]] || "Unknown status"
23
+ end
24
+ end
@@ -0,0 +1,4 @@
1
+ class Daylite::ProjectTaskJoin < Daylite::Base
2
+ belongs_to :project, :foreign_key => "projectID"
3
+ belongs_to :task, :foreign_key => "taskID"
4
+ end
@@ -0,0 +1,10 @@
1
+ class Daylite::Role < Daylite::Base
2
+ belongs_to :organization, :foreign_key => "organizationID"
3
+ belongs_to :project, :foreign_key => "projectID"
4
+
5
+ belongs_to :role_type, :foreign_key => "roleTypeID"
6
+
7
+ def type
8
+ role_type.name
9
+ end
10
+ end
@@ -0,0 +1,2 @@
1
+ class Daylite::RoleType < Daylite::Base
2
+ end
@@ -0,0 +1,17 @@
1
+ class Daylite::Task < Daylite::Base
2
+ belongs_to :owner, :class_name => "User", :foreign_key => "assignedToID"
3
+
4
+ has_many :organization_task_joins, :foreign_key => "taskID"
5
+ has_many :organizations, :through => :organization_task_joins
6
+
7
+ has_many :project_task_joins, :foreign_key => "taskID"
8
+ has_many :projects, :through => :project_task_joins
9
+
10
+ def organization
11
+ organizations[0]
12
+ end
13
+
14
+ def to_s
15
+ "#<Daylite::Task:#{title}>"
16
+ end
17
+ end
@@ -0,0 +1,10 @@
1
+ class Daylite::User < Daylite::Base
2
+ belongs_to :contact, :foreign_key => "contactID"
3
+
4
+ has_many :organizations, :foreign_key => "assignedToID"
5
+ has_many :tasks, :class_name => "Task", :foreign_key => "assignedToID"
6
+
7
+ def name
8
+ contact.cachedName
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ #database connection info.
2
+ #Don't touch this file if you use it as rails plugin
3
+ #Specify daylite: settings in you rails database.yml instead
4
+ daylite:
5
+ adapter: openbase
6
+ database: MyOrganization
7
+ host: localhost
8
+ username: user
9
+ password: password
@@ -0,0 +1,38 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{daylite-models}
3
+ s.version = "0.1.0"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Dmitriy Dzema"]
7
+ s.date = %q{2009-02-11}
8
+ s.email = %q{dimad.ag@gmail.com}
9
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt"]
10
+ s.files = ["History.txt", "LICENSE", "Manifest.txt", "README.markdown", "Rakefile", "app/models/daylite.rb", "app/models/daylite/contact.rb", "app/models/daylite/organization.rb", "app/models/daylite/organization_task_join.rb", "app/models/daylite/project.rb", "app/models/daylite/project_task_join.rb", "app/models/daylite/role.rb", "app/models/daylite/role_type.rb", "app/models/daylite/task.rb", "app/models/daylite/user.rb", "config/database.yml.exmp", "daylite_models.gemspec", "daylite_models.rb", "init.rb", "install.rb", "lib/active_record/connection_adapters/openbase_adapter.rb", "tasks/users_plugin_tasks.rake", "test/daylite_models_plugin_test.rb", "test/test_helper.rb", "uninstall.rb"]
11
+ s.has_rdoc = true
12
+ s.rdoc_options = ["--main", "README.markdown"]
13
+ s.require_paths = ["lib"]
14
+ s.rubyforge_project = %q{daylite-models}
15
+ s.rubygems_version = %q{1.3.1}
16
+ s.summary = %q{Set of ActiveRecord classes to work with the Daylite 3 database}
17
+ s.test_files = ["test/test_helper.rb"]
18
+
19
+ if s.respond_to? :specification_version then
20
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
21
+ s.specification_version = 2
22
+
23
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
24
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.0.0"])
25
+ s.add_runtime_dependency(%q<activerecord>, [">= 2.0.0"])
26
+ s.add_runtime_dependency(%q<activerecord>, [">= 0.8.3"])
27
+ s.add_development_dependency(%q<hoe>, [">= 1.8.3"])
28
+ else
29
+ s.add_dependency(%q<activesupport>, [">= 2.0.0"])
30
+ s.add_dependency(%q<activerecord>, [">= 2.0.0"])
31
+ s.add_dependency(%q<activerecord>, [">= 0.8.3"])
32
+ end
33
+ else
34
+ s.add_dependency(%q<activesupport>, [">= 2.0.0"])
35
+ s.add_dependency(%q<activerecord>, [">= 2.0.0"])
36
+ s.add_dependency(%q<activerecord>, [">= 0.8.3"])
37
+ end
38
+ end
@@ -0,0 +1,17 @@
1
+ $: << File.join(File.dirname(__FILE__), 'lib')
2
+ require 'init'
3
+
4
+ module DayliteModels
5
+ VERSION = '0.1.1'
6
+ end
7
+
8
+ DAYLITE_DATABASE_CONFIG = 'config/database.yml'
9
+ DAYLITE_CONFIG_SECTION = 'daylite'
10
+
11
+ if File.exist?(DAYLITE_DATABASE_CONFIG)
12
+ yaml = YAML::load(File.read(DAYLITE_DATABASE_CONFIG))
13
+
14
+ if yaml[DAYLITE_CONFIG_SECTION]
15
+ Daylite::Base.establish_connection( yaml[DAYLITE_CONFIG_SECTION] )
16
+ end
17
+ end
data/init.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'active_record'
2
+ require 'active_support'
3
+
4
+ models_path = File.join(File.dirname(__FILE__), 'app', 'models')
5
+ daylite_path = File.join(models_path, 'daylite')
6
+
7
+ $LOAD_PATH << models_path << daylite_path << './lib'
8
+ ActiveSupport::Dependencies.load_paths << models_path << daylite_path << './lib'
@@ -0,0 +1 @@
1
+ # Install hook code here
@@ -0,0 +1,515 @@
1
+ require 'active_record/connection_adapters/abstract_adapter'
2
+
3
+ module ActiveRecord
4
+ class Base
5
+ # Establishes a connection to the database that's used by all Active Record objects
6
+ def self.openbase_connection(config) # :nodoc:
7
+ require_library_or_gem 'openbase' unless self.class.const_defined?(:OpenBase)
8
+
9
+ config = config.symbolize_keys
10
+ host = config[:host]
11
+ username = config[:username].to_s
12
+ password = config[:password].to_s
13
+
14
+
15
+ if config.has_key?(:database)
16
+ database = config[:database]
17
+ else
18
+ raise ArgumentError, "No database specified. Missing argument: database."
19
+ end
20
+
21
+ oba = ConnectionAdapters::OpenBaseAdapter.new(
22
+ OpenBase.new(database, host, username, password), logger
23
+ )
24
+
25
+ if oba.raw_connection.connected?
26
+ unless oba.tables.include?(ConnectionAdapters::OpenBaseAdapter::COLUMN_SUPPORT_TABLE)
27
+ oba.execute(<<-SQL,"Creating OpenBase Column Support Table")
28
+ CREATE TABLE #{ConnectionAdapters::OpenBaseAdapter::COLUMN_SUPPORT_TABLE} (name char, type char, precision int, scale int)
29
+ SQL
30
+ end
31
+ oba.select_all("SELECT * FROM #{ConnectionAdapters::OpenBaseAdapter::COLUMN_SUPPORT_TABLE}").each do |col|
32
+ ConnectionAdapters::OpenBaseAdapter::DECIMAL_COLUMNS.store(col["name"],[col["precision"],col["scale"]])
33
+ end
34
+ end
35
+
36
+ oba
37
+ end
38
+
39
+ end
40
+
41
+ module ConnectionAdapters
42
+ class OpenBaseColumn < Column #:nodoc:
43
+ private
44
+ def simplified_type(field_type)
45
+ return :integer if field_type.downcase =~ /long/
46
+ return :decimal if field_type.downcase == "money"
47
+ return :binary if field_type.downcase == "object"
48
+ super
49
+ end
50
+ end
51
+ # The OpenBase adapter works with the Ruby/Openbase driver by Tetsuya Suzuki.
52
+ # http://www.spice-of-life.net/ruby-openbase/ (needs version 0.7.3+)
53
+ #
54
+ # Options:
55
+ #
56
+ # * <tt>:host</tt> -- Defaults to localhost
57
+ # * <tt>:username</tt> -- Defaults to nothing
58
+ # * <tt>:password</tt> -- Defaults to nothing
59
+ # * <tt>:database</tt> -- The name of the database. No default, must be provided.
60
+ #
61
+ # The OpenBase adapter will make use of OpenBase's ability to generate unique ids
62
+ # for any column with an unique index applied. Thus, if the value of a primary
63
+ # key is not specified at the time an INSERT is performed, the adapter will prefetch
64
+ # a unique id for the primary key. This prefetching is also necessary in order
65
+ # to return the id after an insert.
66
+ #
67
+ # Caveat: Operations involving LIMIT and OFFSET do not yet work!
68
+ #
69
+ # Maintainer: derrick.spell@gmail.com
70
+ class OpenBaseAdapter < AbstractAdapter
71
+ DECIMAL_COLUMNS = {}
72
+ COLUMN_SUPPORT_TABLE = "rails_openbase_column_support"
73
+ def adapter_name
74
+ 'OpenBase'
75
+ end
76
+
77
+ def native_database_types
78
+ {
79
+ :primary_key => "integer NOT NULL UNIQUE INDEX DEFAULT _rowid",
80
+ :string => { :name => "char", :limit => 4096 },
81
+ :text => { :name => "text" },
82
+ :integer => { :name => "integer" },
83
+ :float => { :name => "float" },
84
+ :decimal => { :name => "decimal" },
85
+ :datetime => { :name => "datetime" },
86
+ :timestamp => { :name => "timestamp" },
87
+ :time => { :name => "time" },
88
+ :date => { :name => "date" },
89
+ :binary => { :name => "object" },
90
+ :boolean => { :name => "boolean" }
91
+ }
92
+ end
93
+
94
+ def supports_migrations?
95
+ true
96
+ end
97
+
98
+ def prefetch_primary_key?(table_name = nil)
99
+ true
100
+ end
101
+
102
+ def default_sequence_name(table_name, primary_key) # :nodoc:
103
+ "#{table_name} #{primary_key}"
104
+ end
105
+
106
+ def next_sequence_value(sequence_name)
107
+ ary = sequence_name.split(' ')
108
+ if (!ary[1]) then
109
+ ary[0] =~ /(\w+)_nonstd_seq/
110
+ ary[0] = $1
111
+ end
112
+ @connection.unique_row_id(ary[0], ary[1])
113
+ end
114
+
115
+
116
+ # QUOTING ==================================================
117
+
118
+ def quote(value, column = nil)
119
+ if value.kind_of?(String) && column && column.type == :binary
120
+ "'#{@connection.insert_binary(value)}'"
121
+ elsif value.kind_of?(BigDecimal)
122
+ return "'#{value.to_s}'"
123
+ elsif column && column.type == :integer && column.sql_type =~ /decimal/
124
+ return "'#{value.to_s}'"
125
+ elsif [Float,Fixnum,Bignum].include?(value.class) && column && column.type == :string
126
+ return "'#{value.to_s}'"
127
+ else
128
+ super
129
+ end
130
+ end
131
+
132
+ def quoted_true
133
+ "1"
134
+ end
135
+
136
+ def quoted_false
137
+ "0"
138
+ end
139
+
140
+
141
+
142
+ # DATABASE STATEMENTS ======================================
143
+
144
+ def add_limit_offset!(sql, options) #:nodoc:
145
+ return if options[:limit].nil?
146
+ limit = options[:limit]
147
+ offset = options[:offset]
148
+ if limit == 0
149
+ # Mess with the where clause to ensure we get no results
150
+ if sql =~ /WHERE/i
151
+ sql.sub!(/WHERE/i, 'WHERE 1 = 2 AND ')
152
+ elsif sql =~ /ORDER\s+BY/i
153
+ sql.sub!(/ORDER\s+BY/i, 'WHERE 1 = 2 ORDER BY')
154
+ else
155
+ sql << 'WHERE 1 = 2'
156
+ end
157
+ elsif offset.nil?
158
+ sql << " RETURN RESULTS #{limit}"
159
+ else
160
+ sql << " RETURN RESULTS #{offset} TO #{limit + offset}"
161
+ end
162
+ end
163
+
164
+ def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
165
+ execute(sql, name)
166
+ update_nulls_after_insert(sql, name, pk, id_value, sequence_name)
167
+ id_value
168
+ end
169
+
170
+ def execute(sql, name = nil) #:nodoc:
171
+ log(sql, name) { @connection.execute(sql) }
172
+ end
173
+
174
+ def direct_execute(sql, name = nil) #:nodoc:
175
+ log(sql, name) { @connection.execute(sql) }
176
+ end
177
+
178
+ def update(sql, name = nil) #:nodoc:
179
+ execute(sql, name).rows_affected
180
+ end
181
+
182
+ alias_method :delete, :update #:nodoc:
183
+
184
+ def begin_db_transaction #:nodoc:
185
+ execute "START TRANSACTION"
186
+ rescue Exception
187
+ # Transactions aren't supported
188
+ end
189
+
190
+ def commit_db_transaction #:nodoc:
191
+ execute "COMMIT"
192
+ rescue Exception
193
+ # Transactions aren't supported
194
+ end
195
+
196
+ def rollback_db_transaction #:nodoc:
197
+ execute "ROLLBACK"
198
+ rescue Exception
199
+ # Transactions aren't supported
200
+ end
201
+
202
+
203
+ # SCHEMA STATEMENTS ========================================
204
+ # Return the list of all tables in the schema search path.
205
+ def tables(name = nil) #:nodoc:
206
+ tables = @connection.tables
207
+ tables.reject! { |t| /\A_SYS_/ === t }
208
+ end
209
+
210
+ def columns(table_name, name = nil) #:nodoc:
211
+ sql = "SELECT * FROM _sys_tables "
212
+ sql << "WHERE tablename='#{table_name}' AND INDEXOF(fieldname,'_')<>0 "
213
+ sql << "ORDER BY columnNumber"
214
+ columns = []
215
+ direct_execute(sql, name).each_hash do |row|
216
+ columns << OpenBaseColumn.new(row["fieldname"],
217
+ default_value(row["defaultvalue"],row["typename"]),
218
+ sql_type_name(table_name,row["fieldname"],row["typename"],row["length"]),
219
+ (row["notnull"] == 1 ? false : true)
220
+ )
221
+ end
222
+ columns
223
+ end
224
+
225
+ def column_names(table_name) #:nodoc:
226
+ sql = "SELECT fieldname FROM _sys_tables "
227
+ sql << "WHERE tablename='#{table_name}' AND INDEXOF(fieldname,'_')<>0 "
228
+ sql << "ORDER BY columnNumber"
229
+ names = direct_execute(sql).fetch_all
230
+ names.flatten! || names
231
+ end
232
+
233
+ def indexes(table_name, name = nil)#:nodoc:
234
+ sql = "SELECT fieldname, notnull, searchindex, uniqueindex, clusteredindex FROM _sys_tables "
235
+ sql << "WHERE tablename='#{table_name}' AND INDEXOF(fieldname,'_')<>0 "
236
+ sql << "AND primarykey=0 "
237
+ sql << "AND (searchindex=1 OR uniqueindex=1 OR clusteredindex=1) "
238
+ sql << "ORDER BY columnNumber"
239
+ indexes = []
240
+ execute(sql, name).each do |row|
241
+ indexes << IndexDefinition.new(table_name,ob_index_name(row),row[3]==1,[row[0]])
242
+ end
243
+ indexes
244
+ end
245
+
246
+ def create_table(name, options = {}) #:nodoc:
247
+ return_value = super
248
+
249
+ # Get my own copy of TableDefinition so that i can detect decimal columns
250
+ table_definition = TableDefinition.new(self)
251
+ yield table_definition
252
+
253
+ table_definition.columns.each do |col|
254
+ if col.type == :decimal
255
+ record_decimal(name, col.name, col.precision, col.scale)
256
+ end
257
+ end
258
+
259
+ unless options[:id] == false
260
+ primary_key = (options[:primary_key] || "id")
261
+ direct_execute("CREATE PRIMARY KEY #{name} (#{primary_key})")
262
+ end
263
+ return_value
264
+ end
265
+
266
+ def rename_table(name, new_name)
267
+ execute "RENAME #{name} #{new_name}"
268
+ end
269
+
270
+ def add_column(table_name, column_name, type, options = {})
271
+ return_value = super(table_name, "COLUMN " + column_name.to_s, type, options)
272
+ if type == :decimal
273
+ record_decimal(table_name, column_name, options[:precision], options[:scale])
274
+ end
275
+ end
276
+
277
+ def remove_column(table_name, column_name)
278
+ execute "ALTER TABLE #{table_name} REMOVE COLUMN #{quote_column_name(column_name)}"
279
+ end
280
+
281
+ def rename_column(table_name, column_name, new_column_name)
282
+ execute "ALTER TABLE #{table_name} RENAME #{quote_column_name(column_name)} TO #{quote_column_name(new_column_name)}"
283
+ end
284
+
285
+ def add_column_options!(sql, options) #:nodoc:
286
+ sql << " NOT NULL" if options[:null] == false
287
+ sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options)
288
+ end
289
+
290
+ def change_column(table_name, column_name, type, options = {}) #:nodoc:
291
+ unless options_include_default?(options)
292
+ options[:default] = select_one("SELECT * FROM _sys_tables WHERE tablename='#{table_name}' AND fieldname='#{column_name}'")["defaultvalue"]
293
+ end
294
+
295
+ change_column_sql = "ALTER TABLE #{table_name} ADD COLUMN #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
296
+ add_column_options!(change_column_sql, options)
297
+ execute(change_column_sql)
298
+ end
299
+
300
+ def change_column_default(table_name, column_name, default)
301
+ execute "ALTER TABLE #{table_name} COLUMN #{column_name} SET DEFAULT #{quote(default)}"
302
+ end
303
+
304
+ def add_index(table_name, column_name, options = {})
305
+ if Hash === options # legacy support, since this param was a string
306
+ index_type = options[:unique] ? "UNIQUE" : ""
307
+ else
308
+ index_type = options
309
+ end
310
+ execute "CREATE #{index_type} INDEX #{table_name} #{column_name}"
311
+ end
312
+
313
+ def remove_index(table_name, options = {})
314
+ execute "DROP INDEX #{table_name} #{options === Hash ? options[:column] : options}"
315
+ end
316
+
317
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
318
+ return super unless type.to_s == 'decimal'
319
+
320
+ if (scale.to_i == 2)
321
+ return 'money'
322
+ elsif (scale.to_i == 0)
323
+ return 'longlong'
324
+ else
325
+ return "char(#{precision.to_i + 1})"
326
+ end
327
+ end
328
+
329
+
330
+
331
+ private
332
+ def select(sql, name = nil)
333
+ decimals = detect_decimals(sql) || []
334
+ sql = add_order_by_rowid(sql)
335
+
336
+ # OpenBase ignores the return results when there is a group by
337
+ # so limit the result set that we return to rails if need be
338
+ if (sql =~ /GROUP BY/i)
339
+ sql.sub!(/RETURN RESULTS (\d+)( TO (\d+))?/i,"")
340
+
341
+ results = execute(sql, name)
342
+ if ($2)
343
+ results.fetch_offset = $1.to_i
344
+ results.fetch_limit = $3.to_i - $1.to_i
345
+ elsif ($1)
346
+ results.fetch_limit = $1.to_i
347
+ end
348
+ else
349
+ results = execute(sql, name)
350
+ end
351
+
352
+ rows = []
353
+ if ( results.rows_affected )
354
+ results.each_hash do |row| # loop through result rows
355
+ # row.delete("_rowid") if row.key?("_rowid")
356
+ decimals.each do |name, precision, scale|
357
+ row[name] = BigDecimal.new(row[name]) if row[name] === String
358
+ end
359
+ rows << row
360
+ end
361
+ end
362
+ rows
363
+ end
364
+
365
+ def default_value(value,type=nil)
366
+ return value if value.nil?
367
+
368
+ # Boolean type values
369
+ return true if value =~ /true/
370
+ return false if value =~ /false/
371
+ # Alternative boolean default declarations
372
+ return true if (value == 1 && type == "boolean")
373
+ return false if (value == 0 && type == "boolean")
374
+
375
+ # Date / Time magic values
376
+ return Time.now.to_s if value =~ /^now\(\)/i
377
+
378
+ # Empty strings should be set to nil
379
+ return nil if value.empty?
380
+
381
+ # Otherwise return what we got from OpenBase
382
+ # and hope for the best...
383
+ # Take off the leading space and unquote
384
+ value.lstrip!
385
+ value = value[1,value.length-2] if value.first.eql?("'") && value.last.eql?("'")
386
+ return nil if value.eql?("NULL")
387
+ return value
388
+ end
389
+
390
+ def sql_type_name(table_name, col_name, type, length)
391
+ full_name = table_name.to_s + "." + col_name.to_s
392
+ if DECIMAL_COLUMNS.include?(full_name) && type != "longlong"
393
+ return "decimal(#{DECIMAL_COLUMNS[full_name][0]},#{DECIMAL_COLUMNS[full_name][1]})"
394
+ end
395
+ return "#{type}(#{length})" if ( type =~ /char/ )
396
+ type
397
+ end
398
+
399
+ def ob_index_name(row = [])
400
+ name = ""
401
+ name << "UNIQUE " if row[3]
402
+ name << "CLUSTERED " if row[4]
403
+ name << "INDEX"
404
+ name
405
+ end
406
+
407
+ def detect_decimals(sql)
408
+ #=begin
409
+ # Detect any decimal columns that will need to be cast when fetched
410
+ decimals = []
411
+ sql =~ /SELECT\s+(.*)\s+FROM\s+(\w+)/i
412
+ select_clause = $1
413
+ main_table = $2
414
+ if select_clause == "*"
415
+ column_names(main_table).each do |col|
416
+ full_name = main_table + "." + col
417
+ if DECIMAL_COLUMNS.include?(full_name)
418
+ decimals << [col,DECIMAL_COLUMNS[full_name][0].to_i,DECIMAL_COLUMNS[full_name][1].to_i]
419
+ end
420
+ end
421
+ end
422
+ return decimals
423
+ =begin {
424
+ # Change table.* to list of columns in table
425
+ while (sql =~ /SELECT.*\s(\w+)\.\*/)
426
+ table = $1
427
+ cols = columns(table)
428
+ if ( cols.size == 0 ) then
429
+ # Maybe this is a table alias
430
+ sql =~ /FROM(.+?)(?:LEFT|OUTER|JOIN|WHERE|GROUP|HAVING|ORDER|RETURN|$)/
431
+ $1 =~ /[\s|,](\w+)\s+#{table}[\s|,]/ # get the tablename for this alias
432
+ cols = columns($1)
433
+ end
434
+ select_columns = []
435
+ cols.each do |col|
436
+ select_columns << table + '.' + col.name
437
+ end
438
+ sql.gsub!(table + '.*',select_columns.join(", ")) if select_columns
439
+ end
440
+
441
+ # Change JOIN clause to table list and WHERE condition
442
+ }
443
+ =begin {
444
+ while (sql =~ /JOIN/)
445
+ sql =~ /((LEFT )?(OUTER )?JOIN (\w+) ON )(.+?)(?:LEFT|OUTER|JOIN|WHERE|GROUP|HAVING|ORDER|RETURN|$)/
446
+ join_clause = $1 + $5
447
+ is_outer_join = $3
448
+ join_table = $4
449
+ join_condition = $5
450
+ join_condition.gsub!(/=/,"*") if is_outer_join
451
+ if (sql =~ /WHERE/)
452
+ sql.gsub!(/WHERE/,"WHERE (#{join_condition}) AND")
453
+ else
454
+ sql.gsub!(join_clause,"#{join_clause} WHERE #{join_condition}")
455
+ end
456
+ sql =~ /(FROM .+?)(?:LEFT|OUTER|JOIN|WHERE|$)/
457
+ from_clause = $1
458
+ sql.gsub!(from_clause,"#{from_clause}, #{join_table} ")
459
+ sql.gsub!(join_clause,"")
460
+ end
461
+
462
+
463
+ # ORDER BY _rowid if no explicit ORDER BY
464
+ # This will ensure that find(:first) returns the first inserted row
465
+ if (sql !~ /(ORDER BY)|(GROUP BY)/)
466
+ if (sql =~ /RETURN RESULTS/)
467
+ sql.sub!(/RETURN RESULTS/,"ORDER BY _rowid RETURN RESULTS")
468
+ else
469
+ sql << " ORDER BY _rowid"
470
+ end
471
+ end
472
+ }
473
+ =end
474
+ end
475
+
476
+ def add_order_by_rowid(sql)
477
+ # ORDER BY _rowid if no explicit ORDER BY
478
+ # This will ensure that find(:first) returns the first inserted row
479
+ if (sql !~ /(ORDER BY)|(GROUP BY)/)
480
+ if (sql =~ /RETURN RESULTS/)
481
+ sql.sub!(/RETURN RESULTS/,"ORDER BY _rowid RETURN RESULTS")
482
+ else
483
+ sql << " ORDER BY _rowid"
484
+ end
485
+ end
486
+ sql
487
+ end
488
+
489
+ def record_decimal(table_name, column_name, precision, scale)
490
+ full_name = table_name.to_s + "." + column_name.to_s
491
+ DECIMAL_COLUMNS.store(full_name, [precision.to_i,scale.to_i])
492
+ direct_execute("INSERT INTO #{COLUMN_SUPPORT_TABLE} (name,type,precision,scale) VALUES ('#{full_name}','decimal',#{precision.to_i},#{scale.to_i})")
493
+ end
494
+
495
+ def update_nulls_after_insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
496
+ sql =~ /INSERT INTO (\w+) \((.*)\) VALUES\s*\((.*)\)/m
497
+ table = $1
498
+ cols = $2
499
+ values = $3
500
+ cols = cols.split(',')
501
+ values.gsub!(/'[^']*'/,"''")
502
+ values.gsub!(/"[^"]*"/,"\"\"")
503
+ values = values.split(',')
504
+ update_cols = []
505
+ values.each_index { |index| update_cols << cols[index] if values[index] =~ /\s*NULL\s*/ }
506
+ update_sql = "UPDATE #{table} SET"
507
+ update_cols.each { |col| update_sql << " #{col}=NULL," unless col.empty? }
508
+ update_sql.chop!()
509
+ update_sql << " WHERE #{pk}=#{quote(id_value)}"
510
+ direct_execute(update_sql,"Null Correction") if update_cols.size > 0
511
+ end
512
+
513
+ end
514
+ end
515
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :users_plugin do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,8 @@
1
+ require 'test_helper'
2
+
3
+ class DayliteModelsPluginTest < ActiveSupport::TestCase
4
+ # Replace this with your real tests.
5
+ test "the truth" do
6
+ assert true
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'active_support/test_case'
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: DimaD-daylite-models
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Dmitriy Dzema
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-02-11 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: activesupport
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.0
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: activerecord
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 2.0.0
32
+ version:
33
+ - !ruby/object:Gem::Dependency
34
+ name: activerecord
35
+ version_requirement:
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 0.8.3
41
+ version:
42
+ description:
43
+ email: dimad.ag@gmail.com
44
+ executables: []
45
+
46
+ extensions: []
47
+
48
+ extra_rdoc_files:
49
+ - History.txt
50
+ - Manifest.txt
51
+ files:
52
+ - History.txt
53
+ - LICENSE
54
+ - Manifest.txt
55
+ - README.markdown
56
+ - Rakefile
57
+ - app/models/daylite.rb
58
+ - app/models/daylite/contact.rb
59
+ - app/models/daylite/organization.rb
60
+ - app/models/daylite/organization_task_join.rb
61
+ - app/models/daylite/project.rb
62
+ - app/models/daylite/project_task_join.rb
63
+ - app/models/daylite/role.rb
64
+ - app/models/daylite/role_type.rb
65
+ - app/models/daylite/task.rb
66
+ - app/models/daylite/user.rb
67
+ - config/database.yml.exmp
68
+ - daylite_models.gemspec
69
+ - daylite_models.rb
70
+ - init.rb
71
+ - install.rb
72
+ - lib/active_record/connection_adapters/openbase_adapter.rb
73
+ - tasks/users_plugin_tasks.rake
74
+ - test/daylite_models_plugin_test.rb
75
+ - test/test_helper.rb
76
+ - uninstall.rb
77
+ has_rdoc: true
78
+ homepage:
79
+ post_install_message:
80
+ rdoc_options:
81
+ - --main
82
+ - README.markdown
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: "0"
90
+ version:
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: "0"
96
+ version:
97
+ requirements: []
98
+
99
+ rubyforge_project: daylite-models
100
+ rubygems_version: 1.2.0
101
+ signing_key:
102
+ specification_version: 2
103
+ summary: Set of ActiveRecord classes to work with the Daylite 3 database
104
+ test_files:
105
+ - test/test_helper.rb