ibm_db 0.4.6 → 0.6.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.
- data/CHANGES +7 -1
- data/README +46 -43
- data/ext/ibm_db.c +361 -326
- data/lib/active_record/connection_adapters/ibm_db_adapter.rb +208 -77
- data/lib/linux32/ibm_db.so +0 -0
- data/test/associations/eager_test.rb +445 -0
- data/test/associations_test.rb +1839 -0
- data/test/fixtures/db_definitions/luw/ibm_db.drop.sql +1 -0
- data/test/fixtures/db_definitions/luw/ibm_db.sql +6 -0
- data/test/migration_test.rb +104 -65
- metadata +5 -2
@@ -260,13 +260,11 @@ module ActiveRecord
|
|
260
260
|
when /DB2/i
|
261
261
|
case server_info.DBMS_VER
|
262
262
|
when /09/
|
263
|
-
|
263
|
+
@servertype = IBM_DB2_ZOS.new(@connection, self)
|
264
264
|
when /08/
|
265
265
|
@servertype = IBM_DB2_ZOS_8.new(@connection, self)
|
266
|
-
when /07/
|
267
|
-
@servertype = IBM_DB2_ZOS_7.new(@connection, self)
|
268
266
|
else
|
269
|
-
raise "Only DB2 z/OS version
|
267
|
+
raise "Only DB2 z/OS version 8 and above are currently supported"
|
270
268
|
end
|
271
269
|
# DB2 on i5
|
272
270
|
when /AS/i
|
@@ -290,7 +288,7 @@ module ActiveRecord
|
|
290
288
|
unless name == @app_user
|
291
289
|
option = {IBM_DB::SQL_ATTR_INFO_USERID => "#{name}"}
|
292
290
|
if IBM_DB::set_option( @connection, option, 1 )
|
293
|
-
@app_user = IBM_DB::get_option( @connection, IBM_DB::SQL_ATTR_INFO_USERID )
|
291
|
+
@app_user = IBM_DB::get_option( @connection, IBM_DB::SQL_ATTR_INFO_USERID, 1 )
|
294
292
|
end
|
295
293
|
end
|
296
294
|
end
|
@@ -300,7 +298,7 @@ module ActiveRecord
|
|
300
298
|
unless name == @account
|
301
299
|
option = {IBM_DB::SQL_ATTR_INFO_ACCTSTR => "#{name}"}
|
302
300
|
if IBM_DB::set_option( @connection, option, 1 )
|
303
|
-
@account = IBM_DB::get_option( @connection, IBM_DB::SQL_ATTR_INFO_ACCTSTR )
|
301
|
+
@account = IBM_DB::get_option( @connection, IBM_DB::SQL_ATTR_INFO_ACCTSTR, 1 )
|
304
302
|
end
|
305
303
|
end
|
306
304
|
end
|
@@ -310,7 +308,7 @@ module ActiveRecord
|
|
310
308
|
unless name == @application
|
311
309
|
option = {IBM_DB::SQL_ATTR_INFO_APPLNAME => "#{name}"}
|
312
310
|
if IBM_DB::set_option( @connection, option, 1 )
|
313
|
-
@application = IBM_DB::get_option( @connection, IBM_DB::SQL_ATTR_INFO_APPLNAME )
|
311
|
+
@application = IBM_DB::get_option( @connection, IBM_DB::SQL_ATTR_INFO_APPLNAME, 1 )
|
314
312
|
end
|
315
313
|
end
|
316
314
|
end
|
@@ -320,14 +318,16 @@ module ActiveRecord
|
|
320
318
|
unless name == @workstation
|
321
319
|
option = {IBM_DB::SQL_ATTR_INFO_WRKSTNNAME => "#{name}"}
|
322
320
|
if IBM_DB::set_option( @connection, option, 1 )
|
323
|
-
@workstation = IBM_DB::get_option( @connection, IBM_DB::SQL_ATTR_INFO_WRKSTNNAME )
|
321
|
+
@workstation = IBM_DB::get_option( @connection, IBM_DB::SQL_ATTR_INFO_WRKSTNNAME, 1 )
|
324
322
|
end
|
325
323
|
end
|
326
324
|
end
|
327
325
|
|
328
326
|
# This adapter supports migrations.
|
329
|
-
# Current limitations:
|
330
|
-
#
|
327
|
+
# Current limitations:
|
328
|
+
# +rename_column+ is not currently supported by the IBM data servers
|
329
|
+
# +remove_column+ is not currently supported by the DB2 for zOS data server
|
330
|
+
# Tables containing columns of XML data type do not support +remove_column+
|
331
331
|
def supports_migrations?
|
332
332
|
true
|
333
333
|
end
|
@@ -404,13 +404,7 @@ module ActiveRecord
|
|
404
404
|
# and get a IBM_DB::Statement from which is possible to fetch the results
|
405
405
|
if stmt = execute(sql, name)
|
406
406
|
begin
|
407
|
-
|
408
|
-
# an hash for each single record.
|
409
|
-
# The loop stops when there aren't any more valid records to fetch
|
410
|
-
while single_hash = IBM_DB::fetch_assoc(stmt)
|
411
|
-
# Add the record to the +results+ array
|
412
|
-
results << single_hash
|
413
|
-
end
|
407
|
+
@servertype.select_all(sql, name, stmt, results)
|
414
408
|
ensure
|
415
409
|
# Ensures to free the resources associated with the statement
|
416
410
|
IBM_DB::free_result stmt
|
@@ -450,20 +444,7 @@ module ActiveRecord
|
|
450
444
|
# Logs and execute the sql instructions.
|
451
445
|
# The +log+ method is defined in the parent class +AbstractAdapter+
|
452
446
|
log(sql, name) do
|
453
|
-
|
454
|
-
if stmt = IBM_DB::exec(@connection, sql)
|
455
|
-
stmt # Return the statement object
|
456
|
-
else
|
457
|
-
raise IBM_DB::stmt_errormsg
|
458
|
-
end
|
459
|
-
rescue StandardError
|
460
|
-
error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
|
461
|
-
if error_msg && !error_msg.empty?
|
462
|
-
raise "Failed to execute statement due to error: #{error_msg}"
|
463
|
-
else
|
464
|
-
raise
|
465
|
-
end
|
466
|
-
end
|
447
|
+
@servertype.execute(sql, name)
|
467
448
|
end
|
468
449
|
end
|
469
450
|
|
@@ -555,16 +536,7 @@ module ActiveRecord
|
|
555
536
|
# Private method used by +add_limit_offset!+ to create a
|
556
537
|
# sql query given an offset and a limit
|
557
538
|
def query_offset_limit(sql, offset, limit)
|
558
|
-
|
559
|
-
last_record = offset + limit
|
560
|
-
# Transforms the SELECT query in order to retrieve/fetch only
|
561
|
-
# a number of records after the specified offset.
|
562
|
-
# 'select' or 'SELECT' is replaced with the partial query below that adds the sys_row_num column
|
563
|
-
# to select with the condition of this column being between offset+1 and the offset+limit
|
564
|
-
sql.gsub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
|
565
|
-
# The final part of the query is appended to include a WHERE...BETWEEN...AND condition,
|
566
|
-
# and retrieve only a LIMIT number of records starting from the OFFSET+1
|
567
|
-
sql << ") AS I) AS O WHERE sys_row_num BETWEEN #{offset+1} AND #{last_record}"
|
539
|
+
@servertype.query_offset_limit(sql, offset, limit)
|
568
540
|
end
|
569
541
|
private :query_offset_limit
|
570
542
|
|
@@ -600,7 +572,7 @@ module ActiveRecord
|
|
600
572
|
"BLOB('?')"
|
601
573
|
else
|
602
574
|
# Quoting required for the default value of a column
|
603
|
-
|
575
|
+
@servertype.set_blob_default(value)
|
604
576
|
end
|
605
577
|
elsif column && column.type == :text
|
606
578
|
unless caller[0] =~ /add_column_options/i
|
@@ -678,13 +650,14 @@ module ActiveRecord
|
|
678
650
|
}
|
679
651
|
end
|
680
652
|
|
681
|
-
#
|
682
|
-
#
|
683
|
-
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
653
|
+
# IBM data servers do not support limits on certain data types (unlike MySQL)
|
654
|
+
# Limit is supported for the {float, decimal, numeric, varchar, clob, blob} data types.
|
655
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
656
|
+
return super if limit.nil?
|
657
|
+
|
658
|
+
# strip off limits on data types not supporting them
|
659
|
+
if [:integer, :double, :date, :time, :timestamp, :xml].include? type
|
660
|
+
return type.to_s
|
688
661
|
else
|
689
662
|
return super
|
690
663
|
end
|
@@ -938,37 +911,54 @@ module ActiveRecord
|
|
938
911
|
@caller = caller
|
939
912
|
end
|
940
913
|
|
941
|
-
# Implemented by concrete DataServer if applicable
|
942
914
|
def last_generated_id
|
943
915
|
end
|
944
916
|
|
945
|
-
# Implemented by concrete DataServer if applicable
|
946
917
|
def create_index_after_table (table_name, caller)
|
947
918
|
end
|
948
919
|
|
949
|
-
# Implemented by concrete DataServer if applicable
|
950
920
|
def setup_for_lob_table ()
|
951
921
|
end
|
952
922
|
|
953
|
-
# Implemented by concrete DataServer if applicable
|
954
923
|
def reorg_table(table_name)
|
955
924
|
end
|
956
925
|
|
957
|
-
# Implemented by concrete DataServer if applicable
|
958
926
|
def check_reserved_words(col_name)
|
959
927
|
col_name
|
960
928
|
end
|
961
929
|
|
962
|
-
# This is supported by
|
930
|
+
# This is supported by the DB2 for Linux, UNIX, Windows data servers
|
931
|
+
# and by the DB2 for i5 data servers
|
963
932
|
def remove_column(table_name, column_name)
|
964
|
-
|
965
|
-
|
933
|
+
begin
|
934
|
+
@caller.execute "ALTER TABLE #{table_name} DROP #{column_name}"
|
935
|
+
reorg_table(table_name)
|
936
|
+
rescue StandardError => exec_err
|
937
|
+
# Provide details on the current XML columns support
|
938
|
+
if exec_err.message.include?('SQLCODE=-1242') && exec_err.message.include?('42997')
|
939
|
+
raise StatementInvalid, "A column that is part of a table containing an XML column cannot be dropped. To remove the column, the table must be dropped and recreated without the #{column_name} column: #{exec_err}"
|
940
|
+
else
|
941
|
+
raise
|
942
|
+
end
|
943
|
+
end
|
966
944
|
end
|
967
945
|
|
968
946
|
def set_schema(schema)
|
969
947
|
@caller.execute("SET SCHEMA #{schema}")
|
970
948
|
end
|
971
949
|
|
950
|
+
def select_all(sql, name, stmt, results)
|
951
|
+
end
|
952
|
+
|
953
|
+
def execute(sql, name)
|
954
|
+
end
|
955
|
+
|
956
|
+
def query_offset_limit(sql, offset, limit)
|
957
|
+
end
|
958
|
+
|
959
|
+
def set_blob_default(value)
|
960
|
+
"BLOB('#{value}')"
|
961
|
+
end
|
972
962
|
end # class IBM_DataServer
|
973
963
|
|
974
964
|
class IBM_DB2 < IBM_DataServer
|
@@ -1009,6 +999,105 @@ module ActiveRecord
|
|
1009
999
|
@caller.change_column_default(table_name, column_name, options[:default])
|
1010
1000
|
end
|
1011
1001
|
end
|
1002
|
+
|
1003
|
+
# Fetches all the results available. IBM_DB::fetch_assoc(stmt) returns
|
1004
|
+
# an hash for each single record.
|
1005
|
+
# The loop stops when there aren't any more valid records to fetch
|
1006
|
+
def select_all(sql, name, stmt, results)
|
1007
|
+
if (!@offset.nil? && @offset >= 0) || (!@limit.nil? && @limit > 0)
|
1008
|
+
# We know at this point that there is an offset and/or a limit
|
1009
|
+
# Check if the cursor type is set correctly
|
1010
|
+
cursor_type = IBM_DB::get_option stmt, IBM_DB::SQL_ATTR_CURSOR_TYPE, 0
|
1011
|
+
if (cursor_type == IBM_DB::SQL_CURSOR_STATIC)
|
1012
|
+
index = 0
|
1013
|
+
# Get @limit rows starting at @offset
|
1014
|
+
while (index < @limit)
|
1015
|
+
# We increment the offset by 1 because for DB2 the offset of the initial row is 1 instead of 0
|
1016
|
+
if single_hash = IBM_DB::fetch_assoc(stmt, @offset + index + 1)
|
1017
|
+
# Add the record to the +results+ array
|
1018
|
+
results << single_hash
|
1019
|
+
index = index + 1
|
1020
|
+
else
|
1021
|
+
# break from the while loop
|
1022
|
+
break
|
1023
|
+
end
|
1024
|
+
end
|
1025
|
+
else # cursor != IBM_DB::SQL_CURSOR_STATIC
|
1026
|
+
# If the result set contains a LOB, the cursor type will never be SQL_CURSOR_STATIC
|
1027
|
+
# because DB2 does not allow this. We can't use the offset mechanism because the cursor
|
1028
|
+
# is not scrollable. In this case, ignore first @offset rows and return rows starting
|
1029
|
+
# at @offset to @offset + @limit
|
1030
|
+
index = 0
|
1031
|
+
while (index < @offset + @limit)
|
1032
|
+
if single_hash = IBM_DB::fetch_assoc(stmt)
|
1033
|
+
# Add the record to the +results+ array only from row @offset to @offset + @limit
|
1034
|
+
if (index >= @offset)
|
1035
|
+
results << single_hash
|
1036
|
+
end
|
1037
|
+
index = index + 1
|
1038
|
+
else
|
1039
|
+
# break from the while loop
|
1040
|
+
break
|
1041
|
+
end
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
# This is the case where limit is set to zero
|
1045
|
+
# Simply return an empty +results+
|
1046
|
+
elsif (!@limit.nil? && @limit == 0)
|
1047
|
+
results
|
1048
|
+
# No limits or offsets specified
|
1049
|
+
else
|
1050
|
+
while single_hash = IBM_DB::fetch_assoc(stmt)
|
1051
|
+
# Add the record to the +results+ array
|
1052
|
+
results << single_hash
|
1053
|
+
end
|
1054
|
+
end
|
1055
|
+
# Assign the instance variables to nil. We will not be using them again
|
1056
|
+
@offset = nil
|
1057
|
+
@limit = nil
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
def execute(sql, name)
|
1061
|
+
# Check if there is a limit and/or an offset
|
1062
|
+
# If so then make sure and use a static cursor type
|
1063
|
+
if (!@offset.nil? && @offset >= 0) || (!@limit.nil? && @limit > 0)
|
1064
|
+
begin
|
1065
|
+
# Set the cursor type to static so we can later utilize the offset and limit correctly
|
1066
|
+
if stmt = IBM_DB::exec(@connection, sql, {IBM_DB::SQL_ATTR_CURSOR_TYPE => IBM_DB::SQL_CURSOR_STATIC})
|
1067
|
+
stmt # Return the statement object
|
1068
|
+
else
|
1069
|
+
raise StatementInvalid, IBM_DB::stmt_errormsg
|
1070
|
+
end
|
1071
|
+
rescue StandardError
|
1072
|
+
error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
|
1073
|
+
if error_msg && !error_msg.empty?
|
1074
|
+
raise "Failed to execute statement due to error: #{error_msg}"
|
1075
|
+
else
|
1076
|
+
raise
|
1077
|
+
end
|
1078
|
+
end
|
1079
|
+
else
|
1080
|
+
begin
|
1081
|
+
if stmt = IBM_DB::exec(@connection, sql)
|
1082
|
+
stmt # Return the statement object
|
1083
|
+
else
|
1084
|
+
raise StatementInvalid, IBM_DB::stmt_errormsg
|
1085
|
+
end
|
1086
|
+
rescue StandardError
|
1087
|
+
error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
|
1088
|
+
if error_msg && !error_msg.empty?
|
1089
|
+
raise "Failed to execute statement due to error: #{error_msg}"
|
1090
|
+
else
|
1091
|
+
raise
|
1092
|
+
end
|
1093
|
+
end
|
1094
|
+
end
|
1095
|
+
end
|
1096
|
+
|
1097
|
+
def query_offset_limit(sql, offset, limit)
|
1098
|
+
@limit = limit
|
1099
|
+
@offset = offset
|
1100
|
+
end
|
1012
1101
|
end # class IBM_DB2
|
1013
1102
|
|
1014
1103
|
class IBM_DB2_LUW < IBM_DB2
|
@@ -1016,6 +1105,46 @@ module ActiveRecord
|
|
1016
1105
|
def reorg_table(table_name)
|
1017
1106
|
@caller.execute("CALL ADMIN_CMD('REORG TABLE #{table_name}')")
|
1018
1107
|
end
|
1108
|
+
|
1109
|
+
def select_all(sql, name, stmt, results)
|
1110
|
+
# Fetches all the results available. IBM_DB::fetch_assoc(stmt) returns
|
1111
|
+
# an hash for each single record.
|
1112
|
+
# The loop stops when there aren't any more valid records to fetch
|
1113
|
+
while single_hash = IBM_DB::fetch_assoc(stmt)
|
1114
|
+
# Add the record to the +results+ array
|
1115
|
+
results << single_hash
|
1116
|
+
end
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
def execute(sql, name)
|
1120
|
+
begin
|
1121
|
+
if stmt = IBM_DB::exec(@connection, sql)
|
1122
|
+
stmt # Return the statement object
|
1123
|
+
else
|
1124
|
+
raise StatementInvalid, IBM_DB::stmt_errormsg
|
1125
|
+
end
|
1126
|
+
rescue StandardError
|
1127
|
+
error_msg = IBM_DB::conn_errormsg ? IBM_DB::conn_errormsg : IBM_DB::stmt_errormsg
|
1128
|
+
if error_msg && !error_msg.empty?
|
1129
|
+
raise "Failed to execute statement due to error: #{error_msg}"
|
1130
|
+
else
|
1131
|
+
raise
|
1132
|
+
end
|
1133
|
+
end
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
def query_offset_limit(sql, offset, limit)
|
1137
|
+
# Defines what will be the last record
|
1138
|
+
last_record = offset + limit
|
1139
|
+
# Transforms the SELECT query in order to retrieve/fetch only
|
1140
|
+
# a number of records after the specified offset.
|
1141
|
+
# 'select' or 'SELECT' is replaced with the partial query below that adds the sys_row_num column
|
1142
|
+
# to select with the condition of this column being between offset+1 and the offset+limit
|
1143
|
+
sql.gsub!(/SELECT/i,"SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num FROM (SELECT")
|
1144
|
+
# The final part of the query is appended to include a WHERE...BETWEEN...AND condition,
|
1145
|
+
# and retrieve only a LIMIT number of records starting from the OFFSET+1
|
1146
|
+
sql << ") AS I) AS O WHERE sys_row_num BETWEEN #{offset+1} AND #{last_record}"
|
1147
|
+
end
|
1019
1148
|
end # class IBM_DB2_LUW
|
1020
1149
|
|
1021
1150
|
module HostedDataServer
|
@@ -1042,37 +1171,39 @@ module ActiveRecord
|
|
1042
1171
|
caller.add_index(table_name, "id", :unique => true)
|
1043
1172
|
end
|
1044
1173
|
|
1045
|
-
# This call is needed on DB2 z/OS v8 and earlier for the creation of tables
|
1046
|
-
# with LOBs. When issued, this call does the following:
|
1047
|
-
# DB2 creates LOB table spaces, auxiliary tables, and indexes on auxiliary
|
1048
|
-
# tables for LOB columns.
|
1049
|
-
def setup_for_lob_table()
|
1050
|
-
@caller.execute "SET CURRENT RULES = 'STD'"
|
1051
|
-
end
|
1052
|
-
|
1053
1174
|
def remove_column(table_name, column_name)
|
1054
|
-
raise NotImplementedError, "remove_column is not supported for
|
1055
|
-
end
|
1175
|
+
raise NotImplementedError, "remove_column is not supported by the DB2 for zOS data server"
|
1176
|
+
end
|
1056
1177
|
|
1057
|
-
#
|
1058
|
-
#
|
1059
|
-
|
1060
|
-
|
1178
|
+
# DB2 z/OS only allows a "null" or an empty binary string
|
1179
|
+
# as a default for a BLOB column
|
1180
|
+
# if value is not empty or equivalent to the string "null",
|
1181
|
+
# the server will complain
|
1182
|
+
def set_blob_default(value)
|
1183
|
+
"#{value}"
|
1061
1184
|
end
|
1062
|
-
|
1063
1185
|
end # class IBM_DB2_ZOS
|
1064
1186
|
|
1065
1187
|
class IBM_DB2_ZOS_8 < IBM_DB2_ZOS
|
1066
1188
|
include HostedDataServer
|
1189
|
+
# Setting the SQLID on z/OS will also update the CURRENT SCHEMA
|
1190
|
+
# special register, but not vice versa
|
1191
|
+
def set_schema(schema)
|
1192
|
+
@caller.execute("SET CURRENT SQLID ='#{schema.upcase}'")
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
# This call is needed on DB2 z/OS v8 for the creation of tables
|
1196
|
+
# with LOBs. When issued, this call does the following:
|
1197
|
+
# DB2 creates LOB table spaces, auxiliary tables, and indexes on auxiliary
|
1198
|
+
# tables for LOB columns.
|
1199
|
+
def setup_for_lob_table()
|
1200
|
+
@caller.execute "SET CURRENT RULES = 'STD'"
|
1201
|
+
end
|
1067
1202
|
end # class IBM_DB2_ZOS_8
|
1068
1203
|
|
1069
|
-
class IBM_DB2_ZOS_7 < IBM_DB2_ZOS
|
1070
|
-
include HostedDataServer
|
1071
|
-
end # class IBM_DB2_ZOS_7
|
1072
|
-
|
1073
1204
|
class IBM_DB2_I5 < IBM_DB2
|
1074
1205
|
include HostedDataServer
|
1075
1206
|
end # class IBM_DB2_I5
|
1076
1207
|
|
1077
1208
|
end # module ConnectionAdapters
|
1078
|
-
end # module ActiveRecord
|
1209
|
+
end # module ActiveRecord
|
data/lib/linux32/ibm_db.so
CHANGED
Binary file
|
@@ -0,0 +1,445 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
require 'fixtures/post'
|
3
|
+
require 'fixtures/comment'
|
4
|
+
require 'fixtures/author'
|
5
|
+
require 'fixtures/category'
|
6
|
+
require 'fixtures/company'
|
7
|
+
require 'fixtures/person'
|
8
|
+
require 'fixtures/reader'
|
9
|
+
|
10
|
+
class EagerAssociationTest < Test::Unit::TestCase
|
11
|
+
fixtures :posts, :comments, :authors, :categories, :categories_posts,
|
12
|
+
:companies, :accounts, :tags, :people, :readers
|
13
|
+
|
14
|
+
def test_loading_with_one_association
|
15
|
+
posts = Post.find(:all, :include => :comments)
|
16
|
+
post = posts.find { |p| p.id == 1 }
|
17
|
+
assert_equal 2, post.comments.size
|
18
|
+
assert post.comments.include?(comments(:greetings))
|
19
|
+
|
20
|
+
post = Post.find(:first, :include => :comments, :conditions => "posts.title = 'Welcome to the weblog'")
|
21
|
+
assert_equal 2, post.comments.size
|
22
|
+
assert post.comments.include?(comments(:greetings))
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_loading_conditions_with_or
|
26
|
+
posts = authors(:david).posts.find(:all, :include => :comments, :conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE} = 'SpecialComment'")
|
27
|
+
assert_nil posts.detect { |p| p.author_id != authors(:david).id },
|
28
|
+
"expected to find only david's posts"
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_with_ordering
|
32
|
+
list = Post.find(:all, :include => :comments, :order => "posts.id DESC")
|
33
|
+
[:eager_other, :sti_habtm, :sti_post_and_comments, :sti_comments,
|
34
|
+
:authorless, :thinking, :welcome
|
35
|
+
].each_with_index do |post, index|
|
36
|
+
assert_equal posts(post), list[index]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_loading_with_multiple_associations
|
41
|
+
posts = Post.find(:all, :include => [ :comments, :author, :categories ], :order => "posts.id")
|
42
|
+
assert_equal 2, posts.first.comments.size
|
43
|
+
assert_equal 2, posts.first.categories.size
|
44
|
+
assert posts.first.comments.include?(comments(:greetings))
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_loading_from_an_association
|
48
|
+
posts = authors(:david).posts.find(:all, :include => :comments, :order => "posts.id")
|
49
|
+
assert_equal 2, posts.first.comments.size
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_loading_with_no_associations
|
53
|
+
assert_nil Post.find(posts(:authorless).id, :include => :author).author
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_eager_association_loading_with_belongs_to
|
57
|
+
comments = Comment.find(:all, :include => :post)
|
58
|
+
assert_equal 10, comments.length
|
59
|
+
titles = comments.map { |c| c.post.title }
|
60
|
+
assert titles.include?(posts(:welcome).title)
|
61
|
+
assert titles.include?(posts(:sti_post_and_comments).title)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_eager_association_loading_with_belongs_to_and_limit
|
65
|
+
comments = Comment.find(:all, :include => :post, :limit => 5, :order => 'comments.id')
|
66
|
+
assert_equal 5, comments.length
|
67
|
+
assert_equal [1,2,3,5,6], comments.collect { |c| c.id }
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_eager_association_loading_with_belongs_to_and_limit_and_conditions
|
71
|
+
comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :order => 'comments.id')
|
72
|
+
assert_equal 3, comments.length
|
73
|
+
assert_equal [5,6,7], comments.collect { |c| c.id }
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_eager_association_loading_with_belongs_to_and_limit_and_offset
|
77
|
+
comments = Comment.find(:all, :include => :post, :limit => 3, :offset => 2, :order => 'comments.id')
|
78
|
+
assert_equal 3, comments.length
|
79
|
+
assert_equal [3,5,6], comments.collect { |c| c.id }
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions
|
83
|
+
comments = Comment.find(:all, :include => :post, :conditions => 'post_id = 4', :limit => 3, :offset => 1, :order => 'comments.id')
|
84
|
+
assert_equal 3, comments.length
|
85
|
+
assert_equal [6,7,8], comments.collect { |c| c.id }
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_conditions_array
|
89
|
+
comments = Comment.find(:all, :include => :post, :conditions => ['post_id = ?',4], :limit => 3, :offset => 1, :order => 'comments.id')
|
90
|
+
assert_equal 3, comments.length
|
91
|
+
assert_equal [6,7,8], comments.collect { |c| c.id }
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_eager_association_loading_with_belongs_to_and_limit_and_multiple_associations
|
95
|
+
posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :order => 'posts.id')
|
96
|
+
assert_equal 1, posts.length
|
97
|
+
assert_equal [1], posts.collect { |p| p.id }
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_eager_association_loading_with_belongs_to_and_limit_and_offset_and_multiple_associations
|
101
|
+
posts = Post.find(:all, :include => [:author, :very_special_comment], :limit => 1, :offset => 1, :order => 'posts.id')
|
102
|
+
assert_equal 1, posts.length
|
103
|
+
assert_equal [2], posts.collect { |p| p.id }
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_eager_with_has_many_through
|
107
|
+
posts_with_comments = people(:michael).posts.find(:all, :include => :comments)
|
108
|
+
posts_with_author = people(:michael).posts.find(:all, :include => :author )
|
109
|
+
posts_with_comments_and_author = people(:michael).posts.find(:all, :include => [ :comments, :author ])
|
110
|
+
assert_equal 2, posts_with_comments.inject(0) { |sum, post| sum += post.comments.size }
|
111
|
+
assert_equal authors(:david), assert_no_queries { posts_with_author.first.author }
|
112
|
+
assert_equal authors(:david), assert_no_queries { posts_with_comments_and_author.first.author }
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_eager_with_has_many_through_an_sti_join_model
|
116
|
+
author = Author.find(:first, :include => :special_post_comments, :order => 'authors.id')
|
117
|
+
assert_equal [comments(:does_it_hurt)], assert_no_queries { author.special_post_comments }
|
118
|
+
end
|
119
|
+
|
120
|
+
def test_eager_with_has_many_through_an_sti_join_model_with_conditions_on_both
|
121
|
+
author = Author.find(:first, :include => :special_nonexistant_post_comments, :order => 'authors.id')
|
122
|
+
assert_equal [], author.special_nonexistant_post_comments
|
123
|
+
end
|
124
|
+
|
125
|
+
def test_eager_with_has_many_through_join_model_with_conditions
|
126
|
+
assert_equal Author.find(:first, :include => :hello_post_comments,
|
127
|
+
:order => 'authors.id').hello_post_comments.sort_by(&:id),
|
128
|
+
Author.find(:first, :order => 'authors.id').hello_post_comments.sort_by(&:id)
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_eager_with_has_many_and_limit
|
132
|
+
posts = Post.find(:all, :order => 'posts.id asc', :include => [ :author, :comments ], :limit => 2)
|
133
|
+
assert_equal 2, posts.size
|
134
|
+
assert_equal 3, posts.inject(0) { |sum, post| sum += post.comments.size }
|
135
|
+
end
|
136
|
+
|
137
|
+
def test_eager_with_has_many_and_limit_and_conditions
|
138
|
+
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.body = 'hello'", :order => "posts.id")
|
139
|
+
assert_equal 2, posts.size
|
140
|
+
assert_equal [4,5], posts.collect { |p| p.id }
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_eager_with_has_many_and_limit_and_conditions_array
|
144
|
+
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "posts.body = ?", 'hello' ], :order => "posts.id")
|
145
|
+
assert_equal 2, posts.size
|
146
|
+
assert_equal [4,5], posts.collect { |p| p.id }
|
147
|
+
end
|
148
|
+
|
149
|
+
def test_eager_with_has_many_and_limit_and_conditions_array_on_the_eagers
|
150
|
+
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => [ "authors.name = ?", 'David' ])
|
151
|
+
assert_equal 2, posts.size
|
152
|
+
|
153
|
+
count = Post.count(:include => [ :author, :comments ], :limit => 2, :conditions => [ "authors.name = ?", 'David' ])
|
154
|
+
assert_equal count, posts.size
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_eager_with_has_many_and_limit_ond_high_offset
|
158
|
+
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10, :conditions => [ "authors.name = ?", 'David' ])
|
159
|
+
assert_equal 0, posts.size
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_count_eager_with_has_many_and_limit_ond_high_offset
|
163
|
+
posts = Post.count(:all, :include => [ :author, :comments ], :limit => 2, :offset => 10, :conditions => [ "authors.name = ?", 'David' ])
|
164
|
+
assert_equal 0, posts
|
165
|
+
end
|
166
|
+
|
167
|
+
def test_eager_with_has_many_and_limit_with_no_results
|
168
|
+
posts = Post.find(:all, :include => [ :author, :comments ], :limit => 2, :conditions => "posts.title = 'magic forest'")
|
169
|
+
assert_equal 0, posts.size
|
170
|
+
end
|
171
|
+
|
172
|
+
def test_eager_with_has_and_belongs_to_many_and_limit
|
173
|
+
posts = Post.find(:all, :include => :categories, :order => "posts.id", :limit => 3)
|
174
|
+
assert_equal 3, posts.size
|
175
|
+
assert_equal 2, posts[0].categories.size
|
176
|
+
assert_equal 1, posts[1].categories.size
|
177
|
+
assert_equal 0, posts[2].categories.size
|
178
|
+
assert posts[0].categories.include?(categories(:technology))
|
179
|
+
assert posts[1].categories.include?(categories(:general))
|
180
|
+
end
|
181
|
+
|
182
|
+
def test_eager_with_has_many_and_limit_and_conditions_on_the_eagers
|
183
|
+
posts = authors(:david).posts.find(:all,
|
184
|
+
:include => :comments,
|
185
|
+
:conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
|
186
|
+
:limit => 2
|
187
|
+
)
|
188
|
+
assert_equal 2, posts.size
|
189
|
+
|
190
|
+
count = Post.count(
|
191
|
+
:include => [ :comments, :author ],
|
192
|
+
:conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
|
193
|
+
:limit => 2
|
194
|
+
)
|
195
|
+
assert_equal count, posts.size
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_eager_with_has_many_and_limit_and_scoped_conditions_on_the_eagers
|
199
|
+
posts = nil
|
200
|
+
Post.with_scope(:find => {
|
201
|
+
:include => :comments,
|
202
|
+
:conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'"
|
203
|
+
}) do
|
204
|
+
posts = authors(:david).posts.find(:all, :limit => 2)
|
205
|
+
assert_equal 2, posts.size
|
206
|
+
end
|
207
|
+
|
208
|
+
Post.with_scope(:find => {
|
209
|
+
:include => [ :comments, :author ],
|
210
|
+
:conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')"
|
211
|
+
}) do
|
212
|
+
count = Post.count(:limit => 2)
|
213
|
+
assert_equal count, posts.size
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_eager_with_has_many_and_limit_and_scoped_and_explicit_conditions_on_the_eagers
|
218
|
+
Post.with_scope(:find => { :conditions => "1=1" }) do
|
219
|
+
posts = authors(:david).posts.find(:all,
|
220
|
+
:include => :comments,
|
221
|
+
:conditions => "comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment'",
|
222
|
+
:limit => 2
|
223
|
+
)
|
224
|
+
assert_equal 2, posts.size
|
225
|
+
|
226
|
+
count = Post.count(
|
227
|
+
:include => [ :comments, :author ],
|
228
|
+
:conditions => "authors.name = 'David' AND (comments.body like 'Normal%' OR comments.#{QUOTED_TYPE}= 'SpecialComment')",
|
229
|
+
:limit => 2
|
230
|
+
)
|
231
|
+
assert_equal count, posts.size
|
232
|
+
end
|
233
|
+
end
|
234
|
+
def test_eager_association_loading_with_habtm
|
235
|
+
posts = Post.find(:all, :include => :categories, :order => "posts.id")
|
236
|
+
assert_equal 2, posts[0].categories.size
|
237
|
+
assert_equal 1, posts[1].categories.size
|
238
|
+
assert_equal 0, posts[2].categories.size
|
239
|
+
assert posts[0].categories.include?(categories(:technology))
|
240
|
+
assert posts[1].categories.include?(categories(:general))
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_eager_with_inheritance
|
244
|
+
posts = SpecialPost.find(:all, :include => [ :comments ])
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_eager_has_one_with_association_inheritance
|
248
|
+
post = Post.find(4, :include => [ :very_special_comment ])
|
249
|
+
assert_equal "VerySpecialComment", post.very_special_comment.class.to_s
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_eager_has_many_with_association_inheritance
|
253
|
+
post = Post.find(4, :include => [ :special_comments ])
|
254
|
+
post.special_comments.each do |special_comment|
|
255
|
+
assert_equal "SpecialComment", special_comment.class.to_s
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def test_eager_habtm_with_association_inheritance
|
260
|
+
post = Post.find(6, :include => [ :special_categories ])
|
261
|
+
assert_equal 1, post.special_categories.size
|
262
|
+
post.special_categories.each do |special_category|
|
263
|
+
assert_equal "SpecialCategory", special_category.class.to_s
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def test_eager_with_has_one_dependent_does_not_destroy_dependent
|
268
|
+
assert_not_nil companies(:first_firm).account
|
269
|
+
f = Firm.find(:first, :include => :account,
|
270
|
+
:conditions => ["companies.name = ?", "37signals"])
|
271
|
+
assert_not_nil f.account
|
272
|
+
assert_equal companies(:first_firm, :reload).account, f.account
|
273
|
+
end
|
274
|
+
|
275
|
+
def test_eager_with_invalid_association_reference
|
276
|
+
assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
|
277
|
+
post = Post.find(6, :include=> :monkeys )
|
278
|
+
}
|
279
|
+
assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
|
280
|
+
post = Post.find(6, :include=>[ :monkeys ])
|
281
|
+
}
|
282
|
+
assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys") {
|
283
|
+
post = Post.find(6, :include=>[ 'monkeys' ])
|
284
|
+
}
|
285
|
+
assert_raises(ActiveRecord::ConfigurationError, "Association was not found; perhaps you misspelled it? You specified :include => :monkeys, :elephants") {
|
286
|
+
post = Post.find(6, :include=>[ :monkeys, :elephants ])
|
287
|
+
}
|
288
|
+
end
|
289
|
+
|
290
|
+
def find_all_ordered(className, include=nil)
|
291
|
+
className.find(:all, :order=>"#{className.table_name}.#{className.primary_key}", :include=>include)
|
292
|
+
end
|
293
|
+
|
294
|
+
def test_limited_eager_with_order
|
295
|
+
unless current_adapter?(:IBM_DBAdapter)
|
296
|
+
assert_equal [posts(:thinking), posts(:sti_comments)], Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title)', :limit => 2, :offset => 1)
|
297
|
+
assert_equal [posts(:sti_post_and_comments), posts(:sti_comments)], Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title) DESC', :limit => 2, :offset => 1)
|
298
|
+
else
|
299
|
+
# LUW: [IBM][CLI Driver][DB2/LINUX] SQL0214N
|
300
|
+
# An expression in the ORDER BY clause in the following position,
|
301
|
+
# or starting with "UPPER..." in the "ORDER BY" clause is not valid.
|
302
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
303
|
+
# SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num
|
304
|
+
# FROM (SELECT DISTINCT posts.id FROM posts
|
305
|
+
# LEFT OUTER JOIN authors ON authors.id = posts.author_id
|
306
|
+
# LEFT OUTER JOIN comments ON comments.post_id = posts.id
|
307
|
+
# WHERE (authors.name = 'David')
|
308
|
+
# ORDER BY UPPER(posts.title)) AS I) AS O WHERE sys_row_num BETWEEN 2 AND 3
|
309
|
+
#
|
310
|
+
# i5: ActiveRecord::RecordNotFound: Couldn't find Post with ID=2
|
311
|
+
#
|
312
|
+
# zOS v9: ActiveRecord::RecordNotFound: Couldn't find Post with ID=2
|
313
|
+
#
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def test_limited_eager_with_multiple_order_columns
|
318
|
+
unless current_adapter?(:IBM_DBAdapter)
|
319
|
+
assert_equal [posts(:thinking), posts(:sti_comments)], Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title), posts.id', :limit => 2, :offset => 1)
|
320
|
+
assert_equal [posts(:sti_post_and_comments), posts(:sti_comments)], Post.find(:all, :include => [:author, :comments], :conditions => "authors.name = 'David'", :order => 'UPPER(posts.title) DESC, posts.id', :limit => 2, :offset => 1)
|
321
|
+
else
|
322
|
+
# LUW: [IBM][CLI Driver][DB2/LINUX] SQL0214N
|
323
|
+
# An expression in the ORDER BY clause in the following position,
|
324
|
+
# or starting with "UPPER..." in the "ORDER BY" clause is not valid.
|
325
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
326
|
+
# SELECT O.* FROM (SELECT I.*, ROW_NUMBER() OVER () sys_row_num
|
327
|
+
# FROM (SELECT DISTINCT posts.id FROM posts
|
328
|
+
# LEFT OUTER JOIN authors ON authors.id = posts.author_id
|
329
|
+
# LEFT OUTER JOIN comments ON comments.post_id = posts.id
|
330
|
+
# WHERE (authors.name = 'David')
|
331
|
+
# ORDER BY UPPER(posts.title), posts.id) AS I) AS O WHERE sys_row_num BETWEEN 2 AND 3
|
332
|
+
#
|
333
|
+
# i5: [IBM][CLI Driver][AS] SQL0214N
|
334
|
+
# An expression in the ORDER BY clause in the following position,
|
335
|
+
# or starting with "1" in the " OBY0002" clause is not valid.
|
336
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
337
|
+
# SELECT DISTINCT posts.id FROM posts
|
338
|
+
# LEFT OUTER JOIN authors ON authors.id = posts.author_id
|
339
|
+
# LEFT OUTER JOIN comments ON comments.post_id = posts.id
|
340
|
+
# WHERE (authors.name = 'David')
|
341
|
+
# ORDER BY UPPER(posts.title), posts.id
|
342
|
+
#
|
343
|
+
# zOS 9: [IBM][CLI Driver][DB2] SQL0214N
|
344
|
+
# An expression in the ORDER BY clause in the following position,
|
345
|
+
# or starting with "1" in the "ORDER BY" clause is not valid.
|
346
|
+
# Reason code = "2". SQLSTATE=42822 SQLCODE=-214:
|
347
|
+
# SELECT DISTINCT posts.id FROM posts
|
348
|
+
# LEFT OUTER JOIN authors ON authors.id = posts.author_id
|
349
|
+
# LEFT OUTER JOIN comments ON comments.post_id = posts.id
|
350
|
+
# WHERE (authors.name = 'David')
|
351
|
+
# ORDER BY UPPER(posts.title), posts.id
|
352
|
+
#
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
def test_eager_with_multiple_associations_with_same_table_has_many_and_habtm
|
357
|
+
# Eager includes of has many and habtm associations aren't necessarily sorted in the same way
|
358
|
+
def assert_equal_after_sort(item1, item2, item3 = nil)
|
359
|
+
assert_equal(item1.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id})
|
360
|
+
assert_equal(item3.sort{|a,b| a.id <=> b.id}, item2.sort{|a,b| a.id <=> b.id}) if item3
|
361
|
+
end
|
362
|
+
# Test regular association, association with conditions, association with
|
363
|
+
# STI, and association with conditions assured not to be true
|
364
|
+
post_types = [:posts, :other_posts, :special_posts]
|
365
|
+
# test both has_many and has_and_belongs_to_many
|
366
|
+
[Author, Category].each do |className|
|
367
|
+
d1 = find_all_ordered(className)
|
368
|
+
# test including all post types at once
|
369
|
+
d2 = find_all_ordered(className, post_types)
|
370
|
+
d1.each_index do |i|
|
371
|
+
assert_equal(d1[i], d2[i])
|
372
|
+
assert_equal_after_sort(d1[i].posts, d2[i].posts)
|
373
|
+
post_types[1..-1].each do |post_type|
|
374
|
+
# test including post_types together
|
375
|
+
d3 = find_all_ordered(className, [:posts, post_type])
|
376
|
+
assert_equal(d1[i], d3[i])
|
377
|
+
assert_equal_after_sort(d1[i].posts, d3[i].posts)
|
378
|
+
assert_equal_after_sort(d1[i].send(post_type), d2[i].send(post_type), d3[i].send(post_type))
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
def test_eager_with_multiple_associations_with_same_table_has_one
|
385
|
+
d1 = find_all_ordered(Firm)
|
386
|
+
d2 = find_all_ordered(Firm, :account)
|
387
|
+
d1.each_index do |i|
|
388
|
+
assert_equal(d1[i], d2[i])
|
389
|
+
assert_equal(d1[i].account, d2[i].account)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
def test_eager_with_multiple_associations_with_same_table_belongs_to
|
394
|
+
firm_types = [:firm, :firm_with_basic_id, :firm_with_other_name, :firm_with_condition]
|
395
|
+
d1 = find_all_ordered(Client)
|
396
|
+
d2 = find_all_ordered(Client, firm_types)
|
397
|
+
d1.each_index do |i|
|
398
|
+
assert_equal(d1[i], d2[i])
|
399
|
+
firm_types.each { |type| assert_equal(d1[i].send(type), d2[i].send(type)) }
|
400
|
+
end
|
401
|
+
end
|
402
|
+
def test_eager_with_valid_association_as_string_not_symbol
|
403
|
+
assert_nothing_raised { Post.find(:all, :include => 'comments') }
|
404
|
+
end
|
405
|
+
|
406
|
+
def test_preconfigured_includes_with_belongs_to
|
407
|
+
author = posts(:welcome).author_with_posts
|
408
|
+
assert_equal 5, author.posts.size
|
409
|
+
end
|
410
|
+
|
411
|
+
def test_preconfigured_includes_with_has_one
|
412
|
+
comment = posts(:sti_comments).very_special_comment_with_post
|
413
|
+
assert_equal posts(:sti_comments), comment.post
|
414
|
+
end
|
415
|
+
|
416
|
+
def test_preconfigured_includes_with_has_many
|
417
|
+
posts = authors(:david).posts_with_comments
|
418
|
+
one = posts.detect { |p| p.id == 1 }
|
419
|
+
assert_equal 5, posts.size
|
420
|
+
assert_equal 2, one.comments.size
|
421
|
+
end
|
422
|
+
|
423
|
+
def test_preconfigured_includes_with_habtm
|
424
|
+
posts = authors(:david).posts_with_categories
|
425
|
+
one = posts.detect { |p| p.id == 1 }
|
426
|
+
assert_equal 5, posts.size
|
427
|
+
assert_equal 2, one.categories.size
|
428
|
+
end
|
429
|
+
|
430
|
+
def test_preconfigured_includes_with_has_many_and_habtm
|
431
|
+
posts = authors(:david).posts_with_comments_and_categories
|
432
|
+
one = posts.detect { |p| p.id == 1 }
|
433
|
+
assert_equal 5, posts.size
|
434
|
+
assert_equal 2, one.comments.size
|
435
|
+
assert_equal 2, one.categories.size
|
436
|
+
end
|
437
|
+
|
438
|
+
def test_count_with_include
|
439
|
+
if current_adapter?(:SQLServerAdapter, :SybaseAdapter)
|
440
|
+
assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "len(comments.body) > 15")
|
441
|
+
else
|
442
|
+
assert_equal 3, authors(:david).posts_with_comments.count(:conditions => "length(comments.body) > 15")
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|