-
Notifications
You must be signed in to change notification settings - Fork 164
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
SQLite History (third version) #401
Conversation
I haven't looked at the code yet, but from your write up, it sounds like a great start. (later) We may want to add a separate table to capture the one "big" thing that was left out of the HistoryItem struct, run_count, but I'm fine with moving ahead without it at this point. The run_count can be used to understand which commands are used most and be useful in a fuzzy search that takes run_count into consideration, but my biggest reason for wanting it, was to create a replacement for Thanks @phiresky for all your hard work. I look forward to reviewing this a little bit later and playing with it! |
I intentionally left out run_count because (if I'm understanding you correctly) it's not really something that makes sense for a normalized database structure. The SQLite history (as I implemented it) stores duplicates of the same command again every time because the start time, working dir, exit status etc. can all be different even if the command is the same. This means you can compute the run_count column easily by doing a query like To get select hostname, cwd,
count(*) as number_of_commands_run
from history
group by hostname, cwd
order by number_of_commands_run desc
limit 10 That'll give you the 10 most used directories by number of commands run in them |
That seems reasonable to me too. Just want to get @sholderbach's and @elferherrera's buy-in on the changes. Also, I'm usining |
As far as I know |
cargo build --features=sqlite
cargo run --features=sqlite @phiresky so far everything looks good ! |
@elferherrera It looks to me like it is working ! I will let @fdncred give it a whirl as well.... When I hit my ctrl-x key with @phiresky code it brings up the history.... |
open ./history.sqlite3 | get history @rgwood the above command works nicely on the newly created history db 👍 |
I'd rather the filename be |
I'm a fan of .sqlite3 because |
Is there a particular reason why you skipped the partial completion from the history completer? |
Yeah, the reason I omitted it (for now) is that LIMIT+OFFSET-based pagination only works well under certain circumstances in SQLite (as well as most SQL databases https://use-the-index-luke.com/sql/partial-results/fetch-next-page). The reason is that the database engine can only optimize an OFFSET query under very specific circumstances, so in most cases it has to scan through all elements from index 0 up to offset every time. Of course this is still better than actually scanning and actually retrieving all elements from 0 to maxid every time, but it's not great. The better solution for pagination would be pagination tokens: you call So I really just didn't want to add an |
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.
First of all thank you very much for all the effort and patience with us. It really looks promising to have something that both covers the old history and sql.
I collected my thoughts after I finally got time to read through the actual implementation.
Before devolving into my comment furball:
- The feature
bashisms
used by nushell for the!!
bash style history expansion is currently not yet up to date and fails compilation - There are a few design related questions (e.g.
iter_chronologic
or another easy to use iterator, having the ids prominently floating around) that might be worth discussing before addressing the minor stuff. - Yeah the error handling should be able to distinguish between issues resulting from IO fails/version incompatibilities/unsupported features.
/// Chronologic interaction over all entries present in the history | ||
fn iter_chronologic(&self) -> Iter<'_, String>; |
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.
I think the basic iterator is very valuable and should remain for ease of use. (If the implementation would favor having it on HistoryCursor
would be fine as well)
pub fn all_that_contain_rev(contains: String) -> SearchQuery { | ||
SearchQuery { | ||
direction: SearchDirection::Backward, | ||
start_time: None, | ||
end_time: None, | ||
start_id: None, | ||
end_id: None, | ||
limit: None, | ||
filter: SearchFilter::from_text_search(CommandLineSearch::Substring(contains)), | ||
} | ||
} | ||
pub fn last_with_search(filter: SearchFilter) -> SearchQuery { | ||
SearchQuery { | ||
direction: SearchDirection::Backward, | ||
start_time: None, | ||
end_time: None, | ||
start_id: None, | ||
end_id: None, | ||
limit: Some(1), | ||
filter, | ||
} | ||
} | ||
pub fn last_with_prefix(prefix: String) -> SearchQuery { | ||
SearchQuery::last_with_search(SearchFilter::from_text_search(CommandLineSearch::Prefix( | ||
prefix, | ||
))) | ||
} |
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.
Can we get the constructor names more consistent?
/// update an item atomically | ||
fn update( | ||
&mut self, | ||
id: HistoryItemId, | ||
updater: &dyn Fn(HistoryItem) -> HistoryItem, | ||
) -> Result<()>; |
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.
Thinking about it: is this a capability of the base history trait? (would it make sense to lift Reedline::update_last_command_context
to the concrete history type or a subtype trait ExtendableHistory
? [gnarf: can we export it from Reedline
while it has to have a concrete dyn History
trait bound to exist in the struct (in a type generic way it would be possible but messy)])
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.
That's actually pretty much how I had it in #376. The main issue there was that the outside application had to retain a handle to the SqliteHistory so I had to wrap it in a Mutex. This is better now since update
is part of the History trait itself, so the .history() (or .history_mut()
function could work. If you want a more concrete trait then some downcasting needs to happen..
Another issue is that the update_last_command_context requires state (the last_run_command_id
currently stored in Reedline), which the History trait doesn't know (and can't reconstruct because multiple shells could be open).
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.
Sorry, I kind of misread your comment. Multiple parts of the history trait (e.g. parts of the search params) only work on some History types, but I think it would be fairly hard to separate those out (instead of failing at runtime as it does now).
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.
Yeah unless we completely switch over to compiled generics, we will have to do runtime dispatch in some form (if we also want to be able to hotswap some components). This was just spitballing if we could get it a bit neater but for now going for effectively NotImplementedError
s should be fine
todo: fix tests
Thanks for the changes! I think the consensus is that we go ahead and merge it as soon as the tests pass and you are happy with the state. We would try to test it in nushell behind a feature flag to gradually test the more advanced features. I think the On a similar note, the current concurrency tests rely on eviction of entries but I think we might relax the general test to just test for the presence of the relevant entry without enforcing eviction. (Filebacked might have its own more stringent test around eviction related problems with concurrent accesses) (But haven't looked into what is going on with I think error handling in reedline can be improved in general (don't think we should carry anyhow, but defining our Errors and implementing necessary conversions should be done at some point) |
Ok, thanks for the info. I'll fix up the test errors and move the ones related to limiting history size to FileBackedHistory. I'll also move the originals of concurrent histories to FileBackedHistories and modify the generic ones to not require truncation. For errors I'd change the |
Awesome, sounds good to me! |
hey @phiresky, how's it going? |
hey! I've not had time to work on it since the last changes. I think there's two things missing before this can be merged:
Then afterwards we should probably do these things:
|
I've fixed the tests. Please allow the workflow(s) to run |
Awesome! can you give |
sure. i also still need to fix the error handling |
i see some progress has been made. nice! |
hey @phiresky - weekly check-in. i fixed the fmt but there were some errors. can you look into them when you get a chance please? |
hi! i'll be on vacation the next two weeks so won't be able to continue working on it. I think the only thing missing is fixing the bashisms feature |
ok. when i checked, there was a function commented out that seemed to be required. so it wouldn't compile. |
to be clear, this is what i get with
this is what i get with
and this is what i was talking about with
|
Thanks for fixing the bashisms feature @elferherrera ! I've updated it to be a bit more performant in a8d8703 That was the last thing I think, so from my perspective this could be merged now! |
Thank you very much for all the hard work @phiresky. Let's land this bad boy! |
…status metadata (#5721) This PR adds support for an SQLite history via nushell/reedline#401 The SQLite history is enabled by setting history_file_format: "sqlite" in config.nu. * somewhat working sqlite history * Hook up history command * Fix error in SQlitebacked with empty lines When entering an empty line there previously was the "No command run" error with `SqliteBackedHistory` during addition of the metadata May be considered a temporary fix Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
…status metadata (nushell#5721) This PR adds support for an SQLite history via nushell/reedline#401 The SQLite history is enabled by setting history_file_format: "sqlite" in config.nu. * somewhat working sqlite history * Hook up history command * Fix error in SQlitebacked with empty lines When entering an empty line there previously was the "No command run" error with `SqliteBackedHistory` during addition of the metadata May be considered a temporary fix Co-authored-by: sholderbach <sholderbach@users.noreply.github.com>
This is the third version of a history database for reedline, based on the previous discussions on Github and Discord.
The history trait is modified to be more flexible and support all the interesting metadata:
reedline/src/history/base.rs
Lines 116 to 153 in 5fc904e
The FileBackedHistory was rewritten to be based on this new trait, returning errors if the user tries to filter by things it doesn't support.
Each history item stores the command line plus some additional info:
reedline/src/history/item.rs
Lines 44 to 64 in 5fc904e
All the stateful cursor functionality (back, forward) is removed from the History trait and moved to a separate
HistoryCursor
struct that works with any history. I also moved all the history tests in there because they use the cursor.The historical metadata is stored is used by using the new
update_last_command_context
function so as to not make this a breaking change:This can be called multiple times to set values that are only known after the command has run (e.g. duration, exit_status)
Stuff that should be considered (later):
.except("todo: error handling")
right now because I didn't want to change the signature of any public reedline methods.References: