Browse Source

Added postgresql support.

Martin Edenhofer 9 years ago
parent
commit
a00be78195

+ 1 - 0
Gemfile

@@ -54,6 +54,7 @@ gem 'therubyracer'
 
 # e. g. for mysql you need to load mysql
 gem 'mysql2', '~> 0.3.20'
+gem 'pg'
 
 gem 'net-ldap'
 

+ 2 - 0
Gemfile.lock

@@ -194,6 +194,7 @@ GEM
       omniauth-oauth (~> 1.1)
     parser (2.3.0.1)
       ast (~> 2.2)
+    pg (0.18.4)
     pluginator (1.3.0)
     polyglot (0.3.5)
     power_assert (0.2.7)
@@ -355,6 +356,7 @@ DEPENDENCIES
   omniauth-google-oauth2
   omniauth-linkedin
   omniauth-twitter
+  pg
   pre-commit
   puma
   rack-livereload

+ 71 - 13
app/models/application_model.rb

@@ -303,11 +303,12 @@ returns
 
 =begin
 
-lookup model from cache (if exists) or retrieve it from db, id, name or login possible
+lookup model from cache (if exists) or retrieve it from db, id, name, login or email possible
 
   result = Model.lookup(id: 123)
   result = Model.lookup(name: 'some name')
   result = Model.lookup(login: 'some login')
+  result = Model.lookup(email: 'some login')
 
 returns
 
@@ -328,7 +329,11 @@ returns
       return cache if cache
 
       # do lookup with == to handle case insensitive databases
-      records = where(name: data[:name])
+      records = if Rails.application.config.db_case_sensitive
+                  where('LOWER(name) = LOWER(?)', data[:name])
+                else
+                  where(name: data[:name])
+                end
       records.each {|loop_record|
         if loop_record.name == data[:name]
           cache_set(data[:name], loop_record)
@@ -341,17 +346,38 @@ returns
       return cache if cache
 
       # do lookup with == to handle case insensitive databases
-      records = where(login: data[:login])
+      records = if Rails.application.config.db_case_sensitive
+                  where('LOWER(login) = LOWER(?)',  data[:login])
+                else
+                  where(login: data[:login])
+                end
       records.each {|loop_record|
         if loop_record.login == data[:login]
-          cache_set( data[:login], loop_record)
+          cache_set(data[:login], loop_record)
+          return loop_record
+        end
+      }
+      return
+    elsif data[:email]
+      cache = cache_get(data[:email])
+      return cache if cache
+
+      # do lookup with == to handle case insensitive databases
+      records = if Rails.application.config.db_case_sensitive
+                  where('LOWER(email) = LOWER(?)',  data[:email])
+                else
+                  where(email: data[:email])
+                end
+      records.each {|loop_record|
+        if loop_record.email == data[:email]
+          cache_set(data[:email], loop_record)
           return loop_record
         end
       }
       return
     end
 
-    fail 'Need name, id or login for lookup()'
+    fail 'Need name, id, login or email for lookup()'
   end
 
 =begin
@@ -373,28 +399,44 @@ returns
     elsif data[:name]
 
       # do lookup with == to handle case insensitive databases
-      records = where(name: data[:name])
+      records = if Rails.application.config.db_case_sensitive
+                  where('LOWER(name) = LOWER(?)', data[:name])
+                else
+                  where(name: data[:name])
+                end
       records.each {|loop_record|
         return loop_record if loop_record.name == data[:name]
       }
     elsif data[:login]
 
       # do lookup with == to handle case insensitive databases
-      records = where(login: data[:login])
+      records = if Rails.application.config.db_case_sensitive
+                  where('LOWER(login) = LOWER(?)', data[:login])
+                else
+                  where(login: data[:login])
+                end
       records.each {|loop_record|
         return loop_record if loop_record.login == data[:login]
       }
     elsif data[:email]
 
       # do lookup with == to handle case insensitive databases
-      records = where(email: data[:email])
+      records = if Rails.application.config.db_case_sensitive
+                  where('LOWER(email) = LOWER(?)', data[:email])
+                else
+                  where(email: data[:email])
+                end
       records.each {|loop_record|
         return loop_record if loop_record.email == data[:email]
       }
     elsif data[:locale] && data[:source]
 
       # do lookup with == to handle case insensitive databases
-      records = where(locale: data[:locale], source: data[:source])
+      records = if Rails.application.config.db_case_sensitive
+                  where('LOWER(locale) = LOWER(?) AND LOWER(source) = LOWER(?)', data[:locale], data[:source])
+                else
+                  where(locale: data[:locale], source: data[:source])
+                end
       records.each {|loop_record|
         return loop_record if loop_record.source == data[:source]
       }
@@ -427,7 +469,11 @@ returns
     elsif data[:name]
 
       # do lookup with == to handle case insensitive databases
-      records = where(name: data[:name])
+      records = if Rails.application.config.db_case_sensitive
+                  where('LOWER(name) = LOWER(?)', data[:name])
+                else
+                  where(name: data[:name])
+                end
       records.each {|loop_record|
         if loop_record.name == data[:name]
           loop_record.update_attributes(data)
@@ -440,7 +486,11 @@ returns
     elsif data[:login]
 
       # do lookup with == to handle case insensitive databases
-      records = where(login: data[:login])
+      records = if Rails.application.config.db_case_sensitive
+                  where('LOWER(login) = LOWER(?)', data[:login])
+                else
+                  where(login: data[:login])
+                end
       records.each {|loop_record|
         if loop_record.login.casecmp(data[:login]).zero?
           loop_record.update_attributes(data)
@@ -453,7 +503,11 @@ returns
     elsif data[:email]
 
       # do lookup with == to handle case insensitive databases
-      records = where(email: data[:email])
+      records = if Rails.application.config.db_case_sensitive
+                  where('LOWER(email) = LOWER(?)',  data[:email])
+                else
+                  where(email: data[:email])
+                end
       records.each {|loop_record|
         if loop_record.email.casecmp(data[:email]).zero?
           loop_record.update_attributes(data)
@@ -466,7 +520,11 @@ returns
     elsif data[:locale]
 
       # do lookup with == to handle case insensitive databases
-      records = where(locale: data[:locale])
+      records = if Rails.application.config.db_case_sensitive
+                  where('LOWER(locale) = LOWER(?)', data[:locale])
+                else
+                  where(locale: data[:locale])
+                end
       records.each {|loop_record|
         if loop_record.locale.casecmp(data[:locale]).zero?
           loop_record.update_attributes(data)

+ 3 - 2
app/models/ticket.rb

@@ -346,6 +346,7 @@ condition example
     # remember query and bind params
     query = ''
     bind_params = []
+    like = Rails.application.config.db_like
 
     # get tables to join
     tables = ''
@@ -437,11 +438,11 @@ condition example
           bind_params.push selector['value']
         end
       elsif selector['operator'] == 'contains'
-        query += "#{attribute} LIKE (?)"
+        query += "#{attribute} #{like} (?)"
         value = "%#{selector['value']}%"
         bind_params.push value
       elsif selector['operator'] == 'contains not'
-        query += "#{attribute} NOT LIKE (?)"
+        query += "#{attribute} NOT #{like} (?)"
         value = "%#{selector['value']}%"
         bind_params.push value
       elsif selector['operator'] == 'before (absolute)'

+ 17 - 0
config/initializers/db_preferences.rb

@@ -0,0 +1,17 @@
+# set database preferences
+
+# defaults
+Rails.application.config.db_case_sensitive = false
+Rails.application.config.db_like = 'LIKE'
+Rails.application.config.db_4bytes_utf8 = true
+
+# postgresql
+if ActiveRecord::Base.connection_config[:adapter] == 'postgresql'
+  Rails.application.config.db_case_sensitive = true
+  Rails.application.config.db_like = 'ILIKE'
+end
+
+# mysql
+if ActiveRecord::Base.connection_config[:adapter] == 'mysql2'
+  Rails.application.config.db_4bytes_utf8 = false
+end

+ 7 - 0
db/seeds.rb

@@ -3352,6 +3352,13 @@ Scheduler.create_or_update(
   created_by_id: 1,
 )
 
+# reset primary key sequences
+if ActiveRecord::Base.connection_config[:adapter] == 'postgresql'
+  ActiveRecord::Base.connection.tables.each do |t|
+    ActiveRecord::Base.connection.reset_pk_sequence!(t)
+  end
+end
+
 # install locales and translations
 Locale.create_if_not_exists(
   locale: 'en-us',

+ 31 - 0
lib/core_ext/active_record/connection_adapters/postgresql/schema_statements.rb

@@ -0,0 +1,31 @@
+require 'active_record/connection_adapters/postgresql/schema_statements'
+
+module ActiveRecord
+  module ConnectionAdapters
+    module PostgreSQL
+      module SchemaStatements
+
+        # on postgres create lower indexes to support case insensetive wherer conditions
+        def add_index(table_name, column_name, options = {}) #:nodoc:
+          index_name, index_type, index_columns, index_options, index_algorithm, index_using = add_index_options(table_name, column_name, options)
+
+          column_names = index_columns.split ', '
+          if column_names.class == Array
+            index_columns_new = []
+            column_names.each {|i|
+              if i =~ /^"(name|login|locale|alias)"$/ || i =~ /name"$/
+                index_columns_new.push "LOWER(#{i})"
+              else
+                index_columns_new.push i
+              end
+            }
+            index_columns = index_columns_new.join ', '
+          end
+
+          execute "CREATE #{index_type} INDEX #{index_algorithm} #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_using} (#{index_columns})#{index_options}"
+
+        end
+      end
+    end
+  end
+end

+ 1 - 1
lib/core_ext/string.rb

@@ -57,7 +57,7 @@ class String
   # unfortunaly UTF8mb4 will raise other limitaions of max varchar and lower index sizes
   # More details: http://pjambet.github.io/blog/emojis-and-mysql/
   def utf8_to_3bytesutf8
-    return self if ActiveRecord::Base.connection_config[:adapter] != 'mysql2'
+    return self if Rails.application.config.db_4bytes_utf8
     each_char.select {|c|
       if c.bytes.count > 3
         Rails.logger.warn "strip out 4 bytes utf8 chars '#{c}' of '#{self}'"

+ 2 - 1
test/fixtures/seeds.rb

@@ -1,7 +1,8 @@
 # encoding: utf-8
 # inital data set as extention to db/seeds.rb
+
+# create email address and apply it to all groups
 email_address = EmailAddress.create_if_not_exists(
-  id: 1,
   realname: 'Zammad',
   email: 'zammad@localhost',
   updated_by_id: 1,

+ 48 - 48
test/unit/activity_stream_test.rb

@@ -2,8 +2,8 @@
 require 'test_helper'
 
 class ActivityStreamTest < ActiveSupport::TestCase
-  role  = Role.lookup( name: 'Admin' )
-  group = Group.lookup( name: 'Users' )
+  role  = Role.lookup(name: 'Admin')
+  group = Group.lookup(name: 'Users')
   admin_user = User.create_or_update(
     login: 'admin',
     firstname: 'Bob',
@@ -16,7 +16,7 @@ class ActivityStreamTest < ActiveSupport::TestCase
     updated_by_id: 1,
     created_by_id: 1
   )
-  current_user = User.lookup( login: 'nicole.braun@zammad.org' )
+  current_user = User.lookup(email: 'nicole.braun@zammad.org')
 
   test 'ticket+user' do
     tests = [
@@ -25,20 +25,20 @@ class ActivityStreamTest < ActiveSupport::TestCase
       {
         create: {
           ticket: {
-            group_id: Group.lookup( name: 'Users' ).id,
+            group_id: Group.lookup(name: 'Users').id,
             customer_id: current_user.id,
-            owner_id: User.lookup( login: '-' ).id,
+            owner_id: User.lookup(login: '-').id,
             title: 'Unit Test 1 (äöüß)!',
-            state_id: Ticket::State.lookup( name: 'new' ).id,
-            priority_id: Ticket::Priority.lookup( name: '2 normal' ).id,
+            state_id: Ticket::State.lookup(name: 'new').id,
+            priority_id: Ticket::Priority.lookup(name: '2 normal').id,
             updated_by_id: current_user.id,
             created_by_id: current_user.id,
           },
           article: {
             updated_by_id: current_user.id,
             created_by_id: current_user.id,
-            type_id: Ticket::Article::Type.lookup( name: 'phone' ).id,
-            sender_id: Ticket::Article::Sender.lookup( name: 'Customer' ).id,
+            type_id: Ticket::Article::Type.lookup(name: 'phone').id,
+            sender_id: Ticket::Article::Sender.lookup(name: 'Customer').id,
             from: 'Unit Test <unittest@example.com>',
             body: 'Unit Test 123',
             internal: false,
@@ -47,14 +47,14 @@ class ActivityStreamTest < ActiveSupport::TestCase
         update: {
           ticket: {
             title: 'Unit Test 1 (äöüß) - update!',
-            state_id: Ticket::State.lookup( name: 'open' ).id,
-            priority_id: Ticket::Priority.lookup( name: '1 low' ).id,
+            state_id: Ticket::State.lookup(name: 'open').id,
+            priority_id: Ticket::Priority.lookup(name: '1 low').id,
           },
         },
         update2: {
           ticket: {
             title: 'Unit Test 2 (äöüß) - update!',
-            priority_id: Ticket::Priority.lookup( name: '2 normal' ).id,
+            priority_id: Ticket::Priority.lookup(name: '2 normal').id,
           },
         },
         check: [
@@ -85,7 +85,7 @@ class ActivityStreamTest < ActiveSupport::TestCase
     tickets = []
     tests.each { |test|
 
-      ticket = Ticket.create( test[:create][:ticket] )
+      ticket = Ticket.create(test[:create][:ticket])
       test[:check][0][:o_id]          = ticket.id
       test[:check][2][:o_id]          = ticket.id
       test[:check][2][:created_at]    = ticket.created_at
@@ -93,17 +93,17 @@ class ActivityStreamTest < ActiveSupport::TestCase
       sleep 2
 
       test[:create][:article][:ticket_id] = ticket.id
-      article = Ticket::Article.create( test[:create][:article] )
+      article = Ticket::Article.create(test[:create][:article])
       test[:check][1][:o_id]          = article.id
       test[:check][1][:created_at]    = article.created_at
       test[:check][1][:created_by_id] = current_user.id
 
-      assert_equal( ticket.class.to_s, 'Ticket' )
-      assert_equal( article.class.to_s, 'Ticket::Article' )
+      assert_equal(ticket.class.to_s, 'Ticket')
+      assert_equal(article.class.to_s, 'Ticket::Article')
 
       # update ticket
       if test[:update][:ticket]
-        ticket.update_attributes( test[:update][:ticket] )
+        ticket.update_attributes(test[:update][:ticket])
 
         # check updated user
         test[:check][3][:o_id]          = current_user.id
@@ -111,34 +111,34 @@ class ActivityStreamTest < ActiveSupport::TestCase
         test[:check][3][:created_by_id] = current_user.id
       end
       if test[:update2][:ticket]
-        ticket = Ticket.find( ticket.id )
-        ticket.update_attributes( test[:update2][:ticket] )
+        ticket = Ticket.find(ticket.id)
+        ticket.update_attributes(test[:update2][:ticket])
       end
       if test[:update][:article]
-        article.update_attributes( test[:update][:article] )
+        article.update_attributes(test[:update][:article])
       end
 
       sleep 15
       if test[:update][:ticket]
-        ticket.update_attributes( test[:update][:ticket] )
+        ticket.update_attributes(test[:update][:ticket])
       end
       if test[:update2][:ticket]
-        ticket.update_attributes( test[:update2][:ticket] )
+        ticket.update_attributes(test[:update2][:ticket])
       end
 
       # remember ticket
       tickets.push ticket
 
       # check activity_stream
-      activity_stream_check( admin_user.activity_stream(3), test[:check] )
+      activity_stream_check(admin_user.activity_stream(3), test[:check])
     }
 
     # delete tickets
     tickets.each { |ticket|
       ticket_id = ticket.id
       ticket.destroy
-      found = Ticket.where( id: ticket_id ).first
-      assert( !found, 'Ticket destroyed')
+      found = Ticket.where(id: ticket_id).first
+      assert_not(found, 'Ticket destroyed')
     }
   end
 
@@ -181,16 +181,16 @@ class ActivityStreamTest < ActiveSupport::TestCase
     organizations = []
     tests.each { |test|
 
-      organization = Organization.create( test[:create][:organization] )
+      organization = Organization.create(test[:create][:organization])
       test[:check][0][:o_id]          = organization.id
       test[:check][0][:created_at]    = organization.created_at
       test[:check][0][:created_by_id] = current_user.id
       sleep 2
 
-      assert_equal( organization.class.to_s, 'Organization' )
+      assert_equal(organization.class.to_s, 'Organization')
 
       if test[:update1][:organization]
-        organization.update_attributes( test[:update1][:organization] )
+        organization.update_attributes(test[:update1][:organization])
         test[:check][1][:o_id]          = organization.id
         test[:check][1][:updated_at]    = organization.updated_at
         test[:check][1][:created_by_id] = current_user.id
@@ -198,21 +198,21 @@ class ActivityStreamTest < ActiveSupport::TestCase
       end
 
       if test[:update2][:organization]
-        organization.update_attributes( test[:update2][:organization] )
+        organization.update_attributes(test[:update2][:organization])
       end
 
       # remember organization
       organizations.push organization
 
       # check activity_stream
-      activity_stream_check( admin_user.activity_stream(2), test[:check] )
+      activity_stream_check(admin_user.activity_stream(2), test[:check])
     }
 
     # delete tickets
     organizations.each { |organization|
       organization_id = organization.id
       organization.destroy
-      found = Organization.where( id: organization_id ).first
+      found = Organization.where(id: organization_id).first
       assert( !found, 'Organization destroyed')
     }
   end
@@ -253,15 +253,15 @@ class ActivityStreamTest < ActiveSupport::TestCase
     users = []
     tests.each { |test|
 
-      user = User.create( test[:create][:user] )
+      user = User.create(test[:create][:user])
       test[:check][0][:o_id]          = user.id
       test[:check][0][:created_at]    = user.created_at
       test[:check][0][:created_by_id] = current_user.id
 
-      assert_equal( user.class.to_s, 'User' )
+      assert_equal(user.class.to_s, 'User')
 
       if test[:update1][:user]
-        user.update_attributes( test[:update1][:user] )
+        user.update_attributes(test[:update1][:user])
         test[:check][1][:o_id]          = user.id
         test[:check][1][:updated_at]    = user.updated_at
         test[:check][1][:created_by_id] = current_user.id
@@ -271,7 +271,7 @@ class ActivityStreamTest < ActiveSupport::TestCase
       users.push user
 
       # check activity_stream
-      activity_stream_check( admin_user.activity_stream(3), test[:check] )
+      activity_stream_check(admin_user.activity_stream(3), test[:check])
     }
 
     # delete tickets
@@ -279,7 +279,7 @@ class ActivityStreamTest < ActiveSupport::TestCase
       user_id = user.id
       user.destroy
       found = User.where( id: user_id ).first
-      assert( !found, 'User destroyed')
+      assert_not(found, 'User destroyed')
     }
   end
 
@@ -325,15 +325,15 @@ class ActivityStreamTest < ActiveSupport::TestCase
     users = []
     tests.each { |test|
 
-      user = User.create( test[:create][:user] )
+      user = User.create(test[:create][:user])
       test[:check][0][:o_id]          = user.id
       test[:check][0][:created_at]    = user.created_at
       test[:check][0][:created_by_id] = current_user.id
 
-      assert_equal( user.class.to_s, 'User' )
+      assert_equal(user.class.to_s, 'User')
 
       if test[:update1][:user]
-        user.update_attributes( test[:update1][:user] )
+        user.update_attributes(test[:update1][:user])
         test[:check][1][:o_id]          = user.id
         test[:check][1][:updated_at]    = user.updated_at
         test[:check][1][:created_by_id] = current_user.id
@@ -343,26 +343,26 @@ class ActivityStreamTest < ActiveSupport::TestCase
       sleep 14
 
       if test[:update2][:user]
-        user.update_attributes( test[:update2][:user] )
+        user.update_attributes(test[:update2][:user])
       end
 
       # remember organization
       users.push user
 
       # check activity_stream
-      activity_stream_check( admin_user.activity_stream(2), test[:check] )
+      activity_stream_check(admin_user.activity_stream(2), test[:check])
     }
 
     # delete tickets
     users.each { |user|
       user_id = user.id
       user.destroy
-      found = User.where( id: user_id ).first
-      assert( !found, 'User destroyed')
+      found = User.where(id: user_id).first
+      assert(!found, 'User destroyed')
     }
   end
 
-  def activity_stream_check( activity_stream_list, checks )
+  def activity_stream_check(activity_stream_list, checks)
     #activity_stream_list = activity_stream_list.reverse
     #puts 'AS ' + activity_stream_list.inspect
     check_count = 0
@@ -380,11 +380,11 @@ class ActivityStreamTest < ActiveSupport::TestCase
         #puts item.inspect
         #puts check_item.inspect
         if check_item[:result]
-          assert_equal( check_item[:object], item['object'] )
-          assert_equal( check_item[:type], item['type'] )
-          assert_equal( check_item[:o_id], item['o_id'] )
+          assert_equal(check_item[:object], item['object'])
+          assert_equal(check_item[:type], item['type'])
+          assert_equal(check_item[:o_id], item['o_id'])
         elsif check_item[:object] == item['object'] && check_item[:type] == item['type'] && check_item[:o_id] == item['o_id']
-          assert( false, "entry should not exist #{item['object']}/#{item['type']}/#{item['o_id']}" )
+          assert(false, "entry should not exist #{item['object']}/#{item['type']}/#{item['o_id']}")
         end
       }
     }

Some files were not shown because too many files changed in this diff