@@ -1027,69 +1027,14 @@ pub fn prepare_data_with_reader<R: Reader>(query: &str, reader: &R) -> Result<Pr
10271027
10281028 // Detect orientation and flip mappings BEFORE building base queries.
10291029 // This ensures the SQL query uses the correct aesthetic column names.
1030- // The flip must happen here (not in apply_layer_transforms) because
1031- // build_layer_base_query uses layer.mappings to create SQL like
1032- // `column AS __ggsql_aes_pos1__`.
1033- {
1034- use crate :: plot:: layer:: orientation:: {
1035- flip_mappings, geom_has_implicit_orientation, resolve_orientation,
1036- } ;
1037- use crate :: plot:: ParameterValue ;
1038- let scales = specs[ 0 ] . scales . clone ( ) ;
1039- let aesthetic_ctx = specs[ 0 ] . get_aesthetic_context ( ) ;
1040- for ( layer_idx, layer) in specs[ 0 ] . layers . iter_mut ( ) . enumerate ( ) {
1041- // Check if user tried to set orientation
1042- let geom_type = layer. geom . geom_type ( ) ;
1043- if layer. parameters . contains_key ( "orientation" ) {
1044- // Geoms with implicit orientation (bar, histogram, etc.): reject, use auto-detection
1045- if geom_has_implicit_orientation ( & geom_type) {
1046- return Err ( GgsqlError :: ValidationError ( format ! (
1047- "Layer {}: orientation is auto-detected for {} geom and cannot be set via SETTING. \
1048- Use aesthetic mappings to control orientation (e.g., MAPPING category AS y for horizontal bars).",
1049- layer_idx + 1 ,
1050- geom_type
1051- ) ) ) ;
1052- }
1053-
1054- // Geoms without orientation in default_params (point, path, polygon): reject
1055- let has_orientation_default = layer
1056- . geom
1057- . default_params ( )
1058- . iter ( )
1059- . any ( |p| p. name == "orientation" ) ;
1060- if !has_orientation_default {
1061- return Err ( GgsqlError :: ValidationError ( format ! (
1062- "Layer {}: Invalid setting 'orientation' for geom '{}'. \
1063- This geom does not support orientation.",
1064- layer_idx + 1 ,
1065- geom_type
1066- ) ) ) ;
1067- }
1068- // Otherwise (line, linear, area): allow user-provided orientation
1069- }
1070-
1071- let orientation = resolve_orientation ( layer, & scales) ;
1072- // Store resolved orientation in parameters for downstream use (writers need it)
1073- layer. parameters . insert (
1074- "orientation" . to_string ( ) ,
1075- ParameterValue :: String ( orientation. to_string ( ) ) ,
1076- ) ;
1077- if is_transposed ( layer, & scales) {
1078- flip_mappings ( layer) ;
1079- // Also flip column names in type_info to match the flipped mappings
1080- if layer_idx < layer_type_info. len ( ) {
1081- for ( name, _, _) in & mut layer_type_info[ layer_idx] {
1082- if let Some ( aesthetic) = naming:: extract_aesthetic_name ( name) {
1083- let flipped = aesthetic_ctx. flip_positional ( aesthetic) ;
1084- if flipped != aesthetic {
1085- * name = naming:: aesthetic_column ( & flipped) ;
1086- }
1087- }
1088- }
1089- }
1090- }
1091- }
1092- }
1030+ let scales = specs[ 0 ] . scales . clone ( ) ;
1031+ let aesthetic_ctx = specs[ 0 ] . get_aesthetic_context ( ) ;
1032+ layer:: resolve_orientations (
1033+ & mut specs[ 0 ] . layers ,
1034+ & scales,
1035+ & mut layer_type_info,
1036+ & aesthetic_ctx,
1037+ ) ;
10931038
10941039 // Build layer base queries using build_layer_base_query()
10951040 // These include: SELECT with aesthetic renames, casts from type_requirements, filters
@@ -1179,7 +1124,7 @@ pub fn prepare_data_with_reader<R: Reader>(query: &str, reader: &R) -> Result<Pr
11791124 for ( idx, q) in layer_queries. iter ( ) . enumerate ( ) {
11801125 let layer = & mut specs[ 0 ] . layers [ idx] ;
11811126 let remappings_key = serde_json:: to_string ( & layer. remappings ) . unwrap_or_default ( ) ;
1182- let needs_flip = is_transposed ( layer, & scales ) ;
1127+ let needs_flip = is_transposed ( layer) ;
11831128 let config_key = ( q. clone ( ) , remappings_key, needs_flip) ;
11841129
11851130 if let Some ( existing_key) = config_to_key. get ( & config_key) {
@@ -1219,7 +1164,7 @@ pub fn prepare_data_with_reader<R: Reader>(query: &str, reader: &R) -> Result<Pr
12191164 // with ALIGNED orientation names) but BEFORE update_mappings_for_remappings
12201165 // (which uses remapping keys to create mapping entries).
12211166 // Phase 4.5 will then flip the DataFrame columns to match.
1222- if is_transposed ( l, & scales ) {
1167+ if is_transposed ( l) {
12231168 crate :: plot:: layer:: orientation:: flip_remappings ( l) ;
12241169 }
12251170
@@ -1239,7 +1184,7 @@ pub fn prepare_data_with_reader<R: Reader>(query: &str, reader: &R) -> Result<Pr
12391184 // All positional columns (stat-produced and literal) are flipped together.
12401185 let mut flipped_keys: HashSet < String > = HashSet :: new ( ) ;
12411186 for layer in specs[ 0 ] . layers . iter ( ) {
1242- if is_transposed ( layer, & scales ) {
1187+ if is_transposed ( layer) {
12431188 if let Some ( ref key) = layer. data_key {
12441189 if flipped_keys. insert ( key. clone ( ) ) {
12451190 // First time flipping this data key
0 commit comments