@@ -27,12 +27,14 @@ export def "kv set" [
2727 key : string
2828 value_or_closure ?: any
2929 -- return (- r ): string # Whether and what to return to the pipeline output
30+ -- universal (- u )
3031] {
3132 # Pipeline input is preferred, but prioritize
3233 # parameter if present. This allows $in to be
3334 # used in the parameter if needed.
3435 let input = $in
3536
37+ # If passed a closure, execute it
3638 let arg_type = ($value_or_closure | describe )
3739 let value = match $arg_type {
3840 closure => { $input | do $value_or_closure }
@@ -41,63 +43,56 @@ export def "kv set" [
4143
4244 # Store values as nuons for type-integrity
4345 let kv_pair = {
46+ session : ' ' # Placeholder
4447 key : $key
4548 value : ($value | to nuon )
4649 }
4750
48- # Create the table if it doesn't exist
51+ let db_open = ( db_setup -- universal =$universal )
4952 try {
50- stor create - t std_kv_store - c {key : str , value: str } | ignore
53+ # Delete the existing key if it does exist
54+ do $db_open | query db $" DELETE FROM std_kv_store WHERE key = '($key )'"
5155 }
5256
53- # Does the key exist yet?
54- let key_exists = ( $key in (stor open | $in.std_kv_store ?.key? ))
55-
56- # If so, we need an update rather than an insert
57- let stor_action = match $key_exists {
58- true => {{stor update - t std_kv_store -- where-clause $" key = '($key )'" }}
59- false => {{stor insert - t std_kv_store }}
57+ match $universal {
58+ true => { $kv_pair | into sqlite (universal_db_path ) - t std_kv_store }
59+ false => { $kv_pair | stor insert - t std_kv_store }
6060 }
6161
62- # Execute the update-or-insert action
63- $kv_pair | do $stor_action
64-
65- # Returns the kv table itself in case it's
66- # useful in the pipeline
67- match ($return | default ' value' ) {
68- ' all' => (kv list )
69- ' a' => (kv list )
62+ # The value that should be returned from `kv set`
63+ # By default, this is the input to `kv set`, even if
64+ # overridden by a positional parameter.
65+ # This can also be:
66+ # input: (Default) The pipeline input to `kv set`, even if
67+ # overridden by a positional parameter. `null` if no
68+ # pipeline input was used.
69+ # ---
70+ # value: If a positional parameter was used for the value, then
71+ # return it, otherwise return the input (whatever was set).
72+ # If the positional was a closure, return the result of the
73+ # closure on the pipeline input.
74+ # ---
75+ # all: The entire contents of the existing kv table are returned
76+ match ($return | default ' input' ) {
77+ ' all' => (kv list -- universal=$universal )
78+ ' a' => (kv list -- universal=$universal )
7079 ' value' => $value
7180 ' v' => $value
7281 ' input' => $input
7382 ' in' => $input
74- ' ignore' => null
75- ' i' => null
83+ ' i' => $input
7684 _ => {
7785 error make {
7886 msg : " Invalid --return option"
7987 label : {
80- text : " Must be 'all'/'a', 'value'/'v', 'input'/'in', or 'ignore '/'i'"
88+ text : " Must be 'all'/'a', 'value'/'v', or 'input'/'in'/'i'"
8189 span : (metadata $return ).span
8290 }
8391 }
8492 }
8593 }
8694}
8795
88- def kv_key_completions [] {
89- try {
90- stor open
91- # Hack to turn a SQLiteDatabase into a table
92- | $in.std_kv_store | wrap temp | get temp
93- | get key?
94- } catch {
95- # Return no completions
96- []
97- }
98-
99- }
100-
10196# Retrieves a stored value by key
10297#
10398# Counterpart of "kv set". Returns null
@@ -106,18 +101,16 @@ def kv_key_completions [] {
106101# Usage:
107102# kv get <key> | <pipeline>
108103export def "kv get" [
109- key : string @kv_key_completions # Key of the kv-pair to retrieve
104+ key : string # Key of the kv-pair to retrieve
105+ -- universal (- u )
110106] {
111- try {
112- stor create - t std_kv_store - c {key : str , value: str } | ignore
113- }
114-
115- stor open
107+ let db_open = (db_setup -- universal=$universal )
108+ do $db_open
116109 # Hack to turn a SQLiteDatabase into a table
117110 | $in.std_kv_store | wrap temp | get temp
118111 | where key == $key
119112 # Should only be one occurence of each key in the stor
120- | get - i value | first
113+ | get - i value.0
121114 | match $in {
122115 # Key not found
123116 null => null
@@ -130,13 +123,12 @@ export def "kv get" [
130123#
131124# Returns results as the Nushell value rather
132125# than the stored nuon.
133- export def "kv list" [] {
134- # Create the table if it doesn't exist
135- try {
136- stor create - t std_kv_store - c {key : str , value: str } | ignore
137- }
126+ export def "kv list" [
127+ -- universal (- u )
128+ ] {
129+ let db_open = (db_setup -- universal=$universal )
138130
139- stor open | $in.std_kv_store | each {|kv_pair |
131+ do $db_open | $in.std_kv_store ? | each {|kv_pair |
140132 {
141133 key : $kv_pair.key
142134 value : ($kv_pair.value | from nuon )
@@ -145,35 +137,74 @@ export def "kv list" [] {
145137}
146138
147139# Returns and removes a key-value pair
148- export def "kv drop" [
149- key : string @kv_key_completions # Key of the kv-pair to drop
140+ export def --env "kv drop" [
141+ key : string # Key of the kv-pair to drop
142+ -- universal (- u )
150143] {
151- # Create the table if it doesn't exist
144+ let db_open = (db_setup -- universal=$universal )
145+
146+ let value = (kv get -- universal=$universal $key )
147+
152148 try {
153- stor create - t std_kv_store - c {key : str , value: str } | ignore
149+ do $db_open
150+ # Hack to turn a SQLiteDatabase into a table
151+ | query db $" DELETE FROM std_kv_store WHERE key = '($key )'"
152+ }
153+
154+ if $universal and $env .NU_KV_UNIVERSALS ? {
155+ hide-env $key
154156 }
155157
158+ $value
159+ }
160+
161+ def universal_db_path [] {
162+ $env .NU_UNIVERSAL_KV_PATH ?
163+ | default (
164+ $nu .data-dir | path join " std_kv_variables.sqlite3"
165+ )
166+ }
167+
168+ def db_setup [
169+ -- universal
170+ ] : nothing -> closure {
156171 try {
157- stor open
158- # Hack to turn a SQLiteDatabase into a table
159- | $in.std_kv_store | wrap temp | get temp
160- | where key == $key
161- # Should only be one occurrence of each key in the stor
162- | get - i value | first
163- | match $in {
164- # Key not found
165- null => null
166-
167- # Key found
168- _ => {
169- let value = $in
170- stor delete -- table-name std_kv_store -- where-clause $" key = '($key )'"
171- $value | from nuon
172+ match $universal {
173+ true => {
174+ # Ensure universal sqlite db and table exists
175+ let uuid = (random uuid )
176+ let dummy_record = {
177+ session : ' '
178+ key : $uuid
179+ value : ' '
172180 }
181+ $dummy_record | into sqlite (universal_db_path ) - t std_kv_store
182+ open (universal_db_path ) | query db $" DELETE FROM std_kv_store WHERE key = '($uuid )'"
183+ }
184+ false => {
185+ # Create the stor table if it doesn't exist
186+ stor create - t std_kv_store - c {session : str , key: str , value: str } | ignore
187+ }
173188 }
189+ }
174190
175- } catch {
176- # If value not found or other error, don't return anything
177- null
191+ # Return the correct closure for opening on-disk vs. in-memory
192+ match $universal {
193+ true => {|| {|| open (universal_db_path )}}
194+ false => {|| {|| stor open }}
178195 }
179- }
196+ }
197+
198+ # This hook can be added to $env.config.hooks.pre_execution to enable
199+ # "universal variables" similar to the Fish shell. Adding, changing, or
200+ # removing a universal variable will immediately update the corresponding
201+ # environment variable in all running Nushell sessions.
202+ export def "kv universal-variable-hook" [] {
203+ {||
204+ kv list -- universal
205+ | transpose - dr
206+ | load-env
207+
208+ $env .NU_KV_UNIVERSALS = true
209+ }
210+ }
0 commit comments