-
Notifications
You must be signed in to change notification settings - Fork 30
fix: save button in Mix Studio does not work properly #286
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Reviewer's GuideThis PR addresses a bug in Mix Studio save functionality by changing query deduplication from using operator-only keys to composite (operator, parameter) keys in the database layer, and refactors both handler and UI code to extract and consistently pass query mappings. Sequence diagram for Mix Studio save operation with composite query keyssequenceDiagram
actor User
participant MixStudioDialog
participant MixStudioController
participant MixEditorData
participant HubHandler
participant Database
User->>MixStudioDialog: Clicks Save
MixStudioDialog->>MixStudioController: getData()
MixStudioController->>MixEditorData: Returns editor data
MixStudioDialog->>MixStudioDialog: mixEditorDataToQuery(editorData)
MixStudioDialog->>HubHandler: updateMix(..., queries)
HubHandler->>Database: replace_mix_queries(..., queries)
Database->>Database: Deduplicate by (operator, parameter)
Database-->>HubHandler: Save result
HubHandler-->>MixStudioDialog: Save result
MixStudioDialog-->>User: Save complete
Class diagram for updated Mix Query deduplication logicclassDiagram
class MixQuery {
+String operator
+String parameter
+String group
+String hlc_uuid
+String updated_at_hlc_ts
+int updated_at_hlc_ver
+String updated_at_hlc_nid
}
class MixQueryEntity {
+update(ActiveModel)
+delete_by_id(id)
}
class replace_mix_queries {
+replace_mix_queries(db, node_id, mix_id, mix_hlc_uuid, operator_parameters, group)
}
MixQueryEntity <|-- MixQuery
replace_mix_queries --> MixQueryEntity
replace_mix_queries --> MixQuery
class HashMap_of_String_String_MixQuery {
+insert((operator, parameter), MixQuery)
+get((operator, parameter))
}
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey there - I've reviewed your changes - here's some feedback:
Blocking issues:
- Detected a Generic API Key, potentially exposing access to various services and sensitive operations. (link)
General comments:
- For changed queries, consider updating the existing record (incrementing its HLC version) instead of delete+insert to preserve history.
- Use a named struct or type alias for the (operator, parameter) key rather than raw tuples to improve readability.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- For changed queries, consider updating the existing record (incrementing its HLC version) instead of delete+insert to preserve history.
- Use a named struct or type alias for the (operator, parameter) key rather than raw tuples to improve readability.
## Individual Comments
### Comment 1
<location> `database/src/actions/mixes.rs:324` </location>
<code_context>
- for (operator, parameter) in &operator_parameters {
- new_operator_params.insert(operator.clone(), parameter.clone());
- }
+ // Create a set of new query keys for easy lookup
+ let new_query_keys: HashSet<(String, String)> = operator_parameters
+ .iter()
</code_context>
<issue_to_address>
**issue (complexity):** Consider replacing manual contains checks and loop nesting with set-difference iterations for clearer intent and simpler logic.
```markdown
You can collapse the two “contains + loop” phases into a pair of set‐difference iterations—this makes the intent clearer (insert what’s new, delete what’s gone) and removes manual `contains` checks inside loops:
```rust
// 1) build a map of existing (op,param) → Model
let existing_by_key = existing_queries
.into_iter()
.map(|q| ((q.operator.clone(), q.parameter.clone()), q))
.collect::<HashMap<_, _>>();
// 2) collect sets of keys
let new_keys = operator_parameters
.iter()
.cloned()
.collect::<HashSet<(String, String)>>();
let existing_keys = existing_by_key.keys().cloned().collect::<HashSet<_>>();
// 3) insert missing entries
for (operator, parameter) in new_keys.difference(&existing_keys) {
let new_query = mix_queries::ActiveModel {
mix_id: ActiveValue::Set(mix_id),
operator: ActiveValue::Set(operator.clone()),
parameter: ActiveValue::Set(parameter.clone()),
/* … */
};
MixQueryEntity::insert(new_query)
.exec(&txn).await
.with_context(|| format!("Failed to insert `{operator}({parameter})`"))?;
}
// 4) delete stale entries
for key in existing_keys.difference(&new_keys) {
let existing = &existing_by_key[key];
MixQueryEntity::delete_by_id(existing.id)
.exec(&txn).await
.with_context(|| format!("Failed to delete `{}`", format!("{}({})", key.0, key.1)))?;
}
```
This drops the extra `new_query_keys` map and the `if/else` nesting. You still build exactly the same inserts/deletes, and you preserve all functionality.
</issue_to_address>
### Comment 2
<location> `database/src/actions/mixes.rs:382` </location>
<code_context>
existing_key.1
</code_context>
<issue_to_address>
**security (generic-api-key):** Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
*Source: gitleaks*
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| for (operator, parameter) in &operator_parameters { | ||
| new_operator_params.insert(operator.clone(), parameter.clone()); | ||
| } | ||
| // Create a set of new query keys for easy lookup |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue (complexity): Consider replacing manual contains checks and loop nesting with set-difference iterations for clearer intent and simpler logic.
You can collapse the two “contains + loop” phases into a pair of set‐difference iterations—this makes the intent clearer (insert what’s new, delete what’s gone) and removes manual `contains` checks inside loops:
```rust
// 1) build a map of existing (op,param) → Model
let existing_by_key = existing_queries
.into_iter()
.map(|q| ((q.operator.clone(), q.parameter.clone()), q))
.collect::<HashMap<_, _>>();
// 2) collect sets of keys
let new_keys = operator_parameters
.iter()
.cloned()
.collect::<HashSet<(String, String)>>();
let existing_keys = existing_by_key.keys().cloned().collect::<HashSet<_>>();
// 3) insert missing entries
for (operator, parameter) in new_keys.difference(&existing_keys) {
let new_query = mix_queries::ActiveModel {
mix_id: ActiveValue::Set(mix_id),
operator: ActiveValue::Set(operator.clone()),
parameter: ActiveValue::Set(parameter.clone()),
/* … */
};
MixQueryEntity::insert(new_query)
.exec(&txn).await
.with_context(|| format!("Failed to insert `{operator}({parameter})`"))?;
}
// 4) delete stale entries
for key in existing_keys.difference(&new_keys) {
let existing = &existing_by_key[key];
MixQueryEntity::delete_by_id(existing.id)
.exec(&txn).await
.with_context(|| format!("Failed to delete `{}`", format!("{}({})", key.0, key.1)))?;
}This drops the extra new_query_keys map and the if/else nesting. You still build exactly the same inserts/deletes, and you preserve all functionality.
|
Oh gosh! Thank you! |
Currently in 2.0.0alpha9, I've noticed a bug that Mix Studio will have a high possibility to fail to save correctly.
Reproduce the issue
What this PR fix
Through some investigations, I think Mix Studio save button cannot properly handle query scenarios where the same operator has multiple different parameters
I've attempted to operate a fix, and I've tested that it works on my machine, without breaking other functions.
Summary by Sourcery
Improve mix query persistence by switching to a compound operator-parameter key in the database operations, updating identifier generation, and ensuring the front-end correctly passes query data to the save endpoint.
Bug Fixes:
Enhancements: