1+ require File . expand_path ( '../../../test_helper' , __FILE__ )
2+
3+ class CrossSchemaTest < ActiveSupport ::TestCase
4+ class Organization < ActiveRecord ::Base
5+ self . table_name = 'companies'
6+ has_many :employees , class_name : 'CrossSchemaTest::Employee'
7+ end
8+
9+ class Employee < ActiveRecord ::Base
10+ self . table_name = 'people'
11+ belongs_to :organization , class_name : 'CrossSchemaTest::Organization' , foreign_key : 'company_id'
12+ end
13+
14+ class OrganizationResource < JSONAPI ::ActiveRelationResource
15+ model_name 'CrossSchemaTest::Organization'
16+ attributes :name
17+
18+ has_many :employees
19+
20+ # Define cross-schema relationship using the module method
21+ self . _cross_schema_relationships = { employees : { schema : 'hr_schema' } }
22+ end
23+
24+ class EmployeeResource < JSONAPI ::Resource
25+ model_name 'CrossSchemaTest::Employee'
26+ attributes :name , :email
27+
28+ has_one :organization
29+ end
30+
31+ def setup
32+ @original_cross_schema = OrganizationResource . _cross_schema_relationships
33+ end
34+
35+ def teardown
36+ OrganizationResource . _cross_schema_relationships = @original_cross_schema
37+ end
38+
39+ def test_cross_schema_relationship_registration
40+ OrganizationResource . _cross_schema_relationships = { test_relation : { schema : 'test_schema' } }
41+
42+ assert_not_nil OrganizationResource . _cross_schema_relationships
43+ assert_equal 'test_schema' , OrganizationResource . _cross_schema_relationships [ :test_relation ] [ :schema ]
44+ end
45+
46+ def test_cross_schema_relationship_with_custom_table
47+ OrganizationResource . _cross_schema_relationships = {
48+ custom_employees : {
49+ schema : 'custom_schema' ,
50+ table : 'custom_table'
51+ }
52+ }
53+
54+ assert_equal 'custom_schema' , OrganizationResource . _cross_schema_relationships [ :custom_employees ] [ :schema ]
55+ assert_equal 'custom_table' , OrganizationResource . _cross_schema_relationships [ :custom_employees ] [ :table ]
56+ end
57+
58+ def test_handle_cross_schema_to_one
59+ skip "Requires database setup for cross-schema testing"
60+ # This test would require actual cross-schema database setup
61+ # It's here as documentation of expected behavior
62+
63+ # Setup mock data
64+ org = Organization . create! ( name : 'Test Org' )
65+ employee = Employee . create! ( name : 'Test Employee' , company_id : org . id )
66+
67+ # Create resource instance
68+ org_resource = OrganizationResource . new ( org , nil )
69+
70+ # Test finding related fragments
71+ source_rids = [ JSONAPI ::ResourceIdentity . new ( OrganizationResource , org . id ) ]
72+ fragments = OrganizationResource . find_related_fragments ( source_rids , :employees , { } )
73+
74+ assert_equal 1 , fragments . size
75+ assert_equal employee . id , fragments . keys . first . id
76+ end
77+
78+ def test_handle_cross_schema_to_many
79+ skip "Requires database setup for cross-schema testing"
80+ # This test would require actual cross-schema database setup
81+ # It's here as documentation of expected behavior
82+
83+ # Setup mock data
84+ org = Organization . create! ( name : 'Test Org' )
85+ employee1 = Employee . create! ( name : 'Employee 1' , company_id : org . id )
86+ employee2 = Employee . create! ( name : 'Employee 2' , company_id : org . id )
87+
88+ # Create resource instance
89+ org_resource = OrganizationResource . new ( org , nil )
90+
91+ # Test finding related fragments
92+ source_rids = [ JSONAPI ::ResourceIdentity . new ( OrganizationResource , org . id ) ]
93+ fragments = OrganizationResource . find_related_fragments ( source_rids , :employees , { } )
94+
95+ assert_equal 2 , fragments . size
96+ employee_ids = fragments . keys . map ( &:id )
97+ assert_includes employee_ids , employee1 . id
98+ assert_includes employee_ids , employee2 . id
99+ end
100+
101+ def test_cross_schema_included_fragments
102+ skip "Requires database setup for cross-schema testing"
103+ # This test would require actual cross-schema database setup
104+
105+ org = Organization . create! ( name : 'Test Org' )
106+ employee = Employee . create! ( name : 'Test Employee' , company_id : org . id )
107+
108+ # Create resource fragments
109+ org_rid = JSONAPI ::ResourceIdentity . new ( OrganizationResource , org . id )
110+ org_fragment = JSONAPI ::ResourceFragment . new ( org_rid )
111+
112+ source = { org_rid => org_fragment }
113+ fragments = OrganizationResource . find_included_fragments ( source , :employees , { } )
114+
115+ assert_equal 1 , fragments . size
116+ assert_equal employee . id , fragments . keys . first . id
117+ end
118+
119+ def test_cross_schema_with_filters
120+ skip "Requires database setup for cross-schema testing"
121+ # This test would require actual cross-schema database setup
122+
123+ org = Organization . create! ( name : 'Test Org' )
124+ employee1 = Employee . create! ( name : 'Alice' , company_id : org . id )
125+ employee2 = Employee . create! ( name : 'Bob' , company_id : org . id )
126+
127+ source_rids = [ JSONAPI ::ResourceIdentity . new ( OrganizationResource , org . id ) ]
128+
129+ # Test with filters
130+ filters = { name : 'Alice' }
131+ fragments = OrganizationResource . find_related_fragments ( source_rids , :employees , { filters : filters } )
132+
133+ assert_equal 1 , fragments . size
134+ assert_equal employee1 . id , fragments . keys . first . id
135+ end
136+
137+ def test_cross_schema_sql_injection_protection
138+ # Test that SQL is properly escaped
139+ OrganizationResource . _cross_schema_relationships = {
140+ dangerous : { schema : "'; DROP TABLE users; --" }
141+ }
142+
143+ # The schema should be stored but properly escaped when used
144+ assert_equal "'; DROP TABLE users; --" , OrganizationResource . _cross_schema_relationships [ :dangerous ] [ :schema ]
145+
146+ # When actually used in queries, it should be properly quoted
147+ # This is handled by ActiveRecord::Base.connection.quote_table_name
148+ end
149+
150+ def test_cross_schema_with_context
151+ skip "Requires database setup for cross-schema testing"
152+
153+ org = Organization . create! ( name : 'Test Org' )
154+ employee = Employee . create! ( name : 'Test Employee' , company_id : org . id )
155+
156+ # Test with context
157+ context = { current_user : 'test_user' }
158+ source_rids = [ JSONAPI ::ResourceIdentity . new ( OrganizationResource , org . id ) ]
159+ fragments = OrganizationResource . find_related_fragments ( source_rids , :employees , { context : context } )
160+
161+ assert_equal 1 , fragments . size
162+ # Verify context was passed through
163+ fragment = fragments . values . first
164+ assert_equal context , fragment . resource . context if fragment . resource
165+ end
166+
167+ def test_module_inclusion
168+ # Test that the module is properly included
169+ assert OrganizationResource . respond_to? ( :find_related_fragments )
170+ assert OrganizationResource . respond_to? ( :find_included_fragments )
171+ end
172+
173+ def test_fallback_to_normal_relationship
174+ # Test that non-cross-schema relationships still work
175+ OrganizationResource . _cross_schema_relationships = nil
176+
177+ # This should not raise an error and should call the original implementation
178+ assert_nothing_raised do
179+ source_rids = [ ]
180+ OrganizationResource . find_related_fragments ( source_rids , :employees , { } )
181+ end
182+ end
183+ end
0 commit comments