hotfix: relationship tweak for LLM

This commit is contained in:
dal 2025-05-30 16:54:49 -06:00
parent f98e23f15f
commit 86c275e70d
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
4 changed files with 34 additions and 52 deletions

View File

@ -21,25 +21,25 @@ models:
description: Minimum number of logins
description: Customers with logins above threshold and active subscription
metrics:
# Metric using entity columns, requires deduplication for many-to-many
# Metric using relationship columns, requires deduplication for many-to-many
- name: popular_product_revenue
expr: SUM(revenue) WHERE culture_products.product_count > 5
description: Revenue from cultures with popular products
entities:
relationships:
- name: logins
primary_key: cultureid
foreign_key: cultureid
source_col: cultureid
ref_col: cultureid
type: LEFT # Explicitly set, but LLM could override
cardinality: one-to-many
description: Links to login activity
- name: subscriptions
primary_key: cultureid
foreign_key: cultureid
source_col: cultureid
ref_col: cultureid
cardinality: one-to-one
description: Links to subscription data (no type, LLM decides)
- name: culture_products
primary_key: cultureid
foreign_key: cultureid
source_col: cultureid
ref_col: cultureid
cardinality: many-to-many
description: Links to product associations (many-to-many via junction)
@ -52,10 +52,10 @@ models:
measures:
- name: login_count
description: Number of logins
entities:
relationships:
- name: culture
primary_key: cultureid
foreign_key: cultureid
source_col: cultureid
ref_col: cultureid
cardinality: many-to-one
# Model for subscriptions
@ -67,10 +67,10 @@ models:
- name: subscription_status
description: Current subscription status
options: ["active", "inactive"]
entities:
relationships:
- name: culture
primary_key: cultureid
foreign_key: cultureid
source_col: cultureid
ref_col: cultureid
cardinality: one-to-one
# Junction model for many-to-many between culture and products
@ -84,12 +84,12 @@ models:
measures:
- name: product_count
description: Number of products in this association
entities:
relationships:
- name: culture
primary_key: cultureid
foreign_key: cultureid
source_col: cultureid
ref_col: cultureid
cardinality: many-to-many
- name: products
primary_key: productid
foreign_key: productid
source_col: productid
ref_col: productid
cardinality: many-to-many

View File

@ -13,7 +13,7 @@
type: string # Optional, inferred if omitted
metrics:
- name: string # Required
expr: string # Required, can use model.column from entities
expr: string # Required, can use model.column from relationships
description: string # Optional
args: # Optional, required only if expr contains arguments, default: null
- name: string # Required
@ -21,16 +21,16 @@
description: string # Optional
filters:
- name: string # Required
expr: string # Required, can use model.column from entities
expr: string # Required, can use model.column from relationships
description: string # Optional
args: # Optional, required only if expr contains arguments, default: null
- name: string # Required
type: string # Required
description: string # Optional
entities:
relationships:
- name: string # Required
primary_key: string # Required
foreign_key: string # Required
source_col: string # Required
ref_col: string # Required
type: string # Optional, e.g., "LEFT", "INNER"; LLM decides if omitted
cardinality: string # Optional, e.g., "one-to-many", "many-to-many"
description: string # Optional

View File

@ -18,7 +18,7 @@ pub struct Model {
pub metrics: Vec<Metric>,
#[serde(default)]
pub filters: Vec<Filter>,
#[serde(rename = "entities", default)] // Added default
#[serde(default)] // Added default
pub relationships: Vec<Relationship>,
}

View File

@ -439,23 +439,9 @@ fn to_deploy_request(model: &Model, sql_content: String) -> DeployDatasetsReques
});
}
// Convert entity relationships
let entity_relationships: Option<Vec<DeployDatasetsEntityRelationshipsRequest>> =
if !model.relationships.is_empty() {
Some(
model
.relationships
.iter()
.map(|rel| DeployDatasetsEntityRelationshipsRequest {
name: rel.name.clone(),
expr: rel.source_col.clone(), // Assuming foreign_key is the expression for the relationship for now
type_: rel.type_.clone().unwrap_or_else(|| "LEFT".to_string()), // Default to LEFT if not specified
})
.collect(),
)
} else {
None
};
// Note: Relationships are now preserved in the yml_file field rather than being converted to entity_relationships.
// This allows the full semantic model structure (including relationships with all their metadata like
// cardinality, descriptions, etc.) to be preserved and processed by the backend.
let data_source_name = model.data_source_name.clone()
.expect("data_source_name missing after validation, should be resolved by resolve_model_configurations");
@ -464,7 +450,7 @@ fn to_deploy_request(model: &Model, sql_content: String) -> DeployDatasetsReques
);
// Serialize the input Model to YAML to be stored in the yml_file field of the request.
// This captures the full semantic definition as sent.
// This captures the full semantic definition as sent, including relationships with all their metadata.
let yml_content_for_request = serde_yaml::to_string(&model).unwrap_or_else(|e| {
eprintln!(
"Error serializing model {} to YAML for deploy request: {}. Using empty string.",
@ -484,7 +470,7 @@ fn to_deploy_request(model: &Model, sql_content: String) -> DeployDatasetsReques
database: model.database.clone(),
description: model.description.clone().unwrap_or_default(),
sql_definition: Some(sql_content),
entity_relationships,
entity_relationships: None, // Relationships are now preserved in yml_file instead
columns,
yml_file: Some(yml_content_for_request), // Store the YAML of the model being deployed
}
@ -1191,7 +1177,7 @@ mod tests {
name: test_model
description: "Test model"
dimension:
dimensions:
- name: dim1
description: "First dimension"
type: "string"
@ -1362,19 +1348,15 @@ models:
};
let sql_content = "SELECT * FROM test_schema.test_model";
let request = to_deploy_request(&model, sql_content.to_string()); // Call the restored function
let request = to_deploy_request(&model, sql_content.to_string());
assert_eq!(request.name, "test_model");
assert_eq!(request.columns.len(), 2); // 1 dim, 1 measure
assert_eq!(request.columns[0].name, "dim1");
assert_eq!(request.columns[0].searchable, true);
assert_eq!(request.columns[1].name, "measure1");
assert!(request.entity_relationships.is_some());
assert_eq!(request.entity_relationships.as_ref().unwrap().len(), 1);
assert_eq!(
request.entity_relationships.as_ref().unwrap()[0].name,
"related_model"
);
// The model has empty relationships, so entity_relationships should be None
assert!(request.entity_relationships.is_none());
let expected_yml_content = serde_yaml::to_string(&model)?;
assert_eq!(request.yml_file, Some(expected_yml_content));