mirror of
https://github.com/nushell/nushell.git
synced 2025-08-18 23:37:50 +02:00
Ability to specify a table name for kv commands (#16450)
Closes #15786 ## Release notes summary - What our users need to know `std-rfc/kv` commands now take an optional `--table (-t)` argument which allows a custom table name to be used. If not specified, the current `std-kv-store` table will be used. ## Tasks after submitting - [x] Added in-help example to `kv set`. Did not add examples to the other `kv` commands since they should be obvious based on the initial `kv set`. ## Additional details Example: ```nushell use std-rfc/kv * kv set -t foo bar 5 kv list # Empty list, since the value was placed in a custom table # => ╭────────────╮ # => │ empty list │ # => ╰────────────╯ kv list -t foo # => ╭───┬─────┬───────╮ # => │ # │ key │ value │ # => ├───┼─────┼───────┤ # => │ 0 │ bar │ 5 │ # => ╰───┴─────┴───────╯ ``` To protect against injection attacks, table names can only include alphanumeric characters with `_` and `-`.
This commit is contained in:
@@ -1,3 +1,5 @@
|
|||||||
|
const default_table_name = 'std_kv_store'
|
||||||
|
const valid_table_regex = '^[a-zA-Z0-9_]+$'
|
||||||
# kv module
|
# kv module
|
||||||
#
|
#
|
||||||
# use std-rfc/kv *
|
# use std-rfc/kv *
|
||||||
@@ -21,6 +23,9 @@
|
|||||||
@example "Store a number" {
|
@example "Store a number" {
|
||||||
kv set foo 5
|
kv set foo 5
|
||||||
}
|
}
|
||||||
|
@example "Store a number in a custom table named foo" {
|
||||||
|
kv set -t foo bar 5
|
||||||
|
}
|
||||||
@example "Update a number and return it" {
|
@example "Update a number and return it" {
|
||||||
let $new_foo = (kv get foo | kv set foo { $in + 1 } --return value)
|
let $new_foo = (kv get foo | kv set foo { $in + 1 } --return value)
|
||||||
}
|
}
|
||||||
@@ -34,6 +39,7 @@ export def "kv set" [
|
|||||||
value_or_closure?: any
|
value_or_closure?: any
|
||||||
--return (-r): string # Whether and what to return to the pipeline output
|
--return (-r): string # Whether and what to return to the pipeline output
|
||||||
--universal (-u) # Store the key-value pair in a universal database
|
--universal (-u) # Store the key-value pair in a universal database
|
||||||
|
--table (-t): string = $default_table_name # Optional table name
|
||||||
] {
|
] {
|
||||||
# Pipeline input is preferred, but prioritize
|
# Pipeline input is preferred, but prioritize
|
||||||
# parameter if present. This allows $in to be
|
# parameter if present. This allows $in to be
|
||||||
@@ -54,15 +60,15 @@ export def "kv set" [
|
|||||||
value: ($value | to nuon)
|
value: ($value | to nuon)
|
||||||
}
|
}
|
||||||
|
|
||||||
let db_open = (db_setup --universal=$universal)
|
let db_open = (db_setup --universal=$universal --table=$table)
|
||||||
try {
|
try {
|
||||||
# Delete the existing key if it does exist
|
# Delete the existing key if it does exist
|
||||||
do $db_open | query db "DELETE FROM std_kv_store WHERE key = :key" --params { key: $key }
|
do $db_open | query db $"DELETE FROM ($table) WHERE key = :key" --params { key: $key }
|
||||||
}
|
}
|
||||||
|
|
||||||
match $universal {
|
match $universal {
|
||||||
true => { $kv_pair | into sqlite (universal_db_path) -t std_kv_store }
|
true => { $kv_pair | into sqlite (universal_db_path) -t $table }
|
||||||
false => { $kv_pair | stor insert -t std_kv_store }
|
false => { $kv_pair | stor insert -t $table }
|
||||||
}
|
}
|
||||||
|
|
||||||
# The value that should be returned from `kv set`
|
# The value that should be returned from `kv set`
|
||||||
@@ -80,8 +86,8 @@ export def "kv set" [
|
|||||||
# ---
|
# ---
|
||||||
# all: The entire contents of the existing kv table are returned
|
# all: The entire contents of the existing kv table are returned
|
||||||
match ($return | default 'input') {
|
match ($return | default 'input') {
|
||||||
'all' => (kv list --universal=$universal)
|
'all' => (kv list --universal=$universal --table=$table)
|
||||||
'a' => (kv list --universal=$universal)
|
'a' => (kv list --universal=$universal --table=$table)
|
||||||
'value' => $value
|
'value' => $value
|
||||||
'v' => $value
|
'v' => $value
|
||||||
'input' => $input
|
'input' => $input
|
||||||
@@ -108,10 +114,11 @@ export def "kv set" [
|
|||||||
export def "kv get" [
|
export def "kv get" [
|
||||||
key: string # Key of the kv-pair to retrieve
|
key: string # Key of the kv-pair to retrieve
|
||||||
--universal (-u) # Whether to use the universal db
|
--universal (-u) # Whether to use the universal db
|
||||||
|
--table (-t): string = $default_table_name # Optional table name
|
||||||
] {
|
] {
|
||||||
let db_open = (db_setup --universal=$universal)
|
let db_open = (db_setup --universal=$universal --table=$table)
|
||||||
do $db_open
|
do $db_open
|
||||||
| query db "SELECT value FROM std_kv_store WHERE key = :key" --params { key: $key }
|
| query db $"SELECT value FROM ($table) WHERE key = :key" --params { key: $key }
|
||||||
| match $in {
|
| match $in {
|
||||||
# Match should be exactly one row
|
# Match should be exactly one row
|
||||||
[$el] => { $el.value | from nuon }
|
[$el] => { $el.value | from nuon }
|
||||||
@@ -125,10 +132,10 @@ export def "kv get" [
|
|||||||
# Returns results as the Nushell value rather than the stored nuon.
|
# Returns results as the Nushell value rather than the stored nuon.
|
||||||
export def "kv list" [
|
export def "kv list" [
|
||||||
--universal (-u) # Whether to use the universal db
|
--universal (-u) # Whether to use the universal db
|
||||||
|
--table (-t): string = $default_table_name # Optional table name
|
||||||
] {
|
] {
|
||||||
let db_open = (db_setup --universal=$universal)
|
let db_open = (db_setup --universal=$universal --table=$table)
|
||||||
|
do $db_open | $in | get -o $table | each {|kv_pair|
|
||||||
do $db_open | $in.std_kv_store? | each {|kv_pair|
|
|
||||||
{
|
{
|
||||||
key: $kv_pair.key
|
key: $kv_pair.key
|
||||||
value: ($kv_pair.value | from nuon )
|
value: ($kv_pair.value | from nuon )
|
||||||
@@ -140,15 +147,16 @@ export def "kv list" [
|
|||||||
export def --env "kv drop" [
|
export def --env "kv drop" [
|
||||||
key: string # Key of the kv-pair to drop
|
key: string # Key of the kv-pair to drop
|
||||||
--universal (-u) # Whether to use the universal db
|
--universal (-u) # Whether to use the universal db
|
||||||
|
--table (-t): string = $default_table_name # Optional table name
|
||||||
] {
|
] {
|
||||||
let db_open = (db_setup --universal=$universal)
|
let db_open = (db_setup --universal=$universal --table=$table)
|
||||||
|
|
||||||
let value = (kv get --universal=$universal $key)
|
let value = (kv get --universal=$universal --table=$table $key)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
do $db_open
|
do $db_open
|
||||||
# Hack to turn a SQLiteDatabase into a table
|
# Hack to turn a SQLiteDatabase into a table
|
||||||
| query db "DELETE FROM std_kv_store WHERE key = :key" --params { key: $key }
|
| query db $"DELETE FROM ($table) WHERE key = :key" --params { key: $key }
|
||||||
}
|
}
|
||||||
|
|
||||||
if $universal and ($env.NU_KV_UNIVERSALS? | default false) {
|
if $universal and ($env.NU_KV_UNIVERSALS? | default false) {
|
||||||
@@ -166,8 +174,20 @@ def universal_db_path [] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def db_setup [
|
def db_setup [
|
||||||
--universal # Whether to use the universal db
|
--universal # Whether to use the universal db
|
||||||
|
--table: string # The table name to use
|
||||||
] : nothing -> closure {
|
] : nothing -> closure {
|
||||||
|
|
||||||
|
if $table not-like $valid_table_regex {
|
||||||
|
error make {
|
||||||
|
msg: "Invalid table name"
|
||||||
|
label: {
|
||||||
|
text: "Table name must match regex: ${valid_table_regex}"
|
||||||
|
span: (metadata $table).span
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
match $universal {
|
match $universal {
|
||||||
true => {
|
true => {
|
||||||
@@ -178,12 +198,12 @@ def db_setup [
|
|||||||
key: $uuid
|
key: $uuid
|
||||||
value: ''
|
value: ''
|
||||||
}
|
}
|
||||||
$dummy_record | into sqlite (universal_db_path) -t std_kv_store
|
$dummy_record | into sqlite (universal_db_path) -t $table
|
||||||
open (universal_db_path) | query db "DELETE FROM std_kv_store WHERE key = :key" --params { key: $uuid }
|
open (universal_db_path) | query db $"DELETE FROM ($table) WHERE key = :key" --params { key: $uuid }
|
||||||
}
|
}
|
||||||
false => {
|
false => {
|
||||||
# Create the stor table if it doesn't exist
|
# Create the stor table if it doesn't exist
|
||||||
stor create -t std_kv_store -c {session: str, key: str, value: str} | ignore
|
stor create -t $table -c {session: str, key: str, value: str} | ignore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -302,3 +302,17 @@ def universal-return_value_only [] {
|
|||||||
kv drop --universal $key
|
kv drop --universal $key
|
||||||
rm $env.NU_UNIVERSAL_KV_PATH
|
rm $env.NU_UNIVERSAL_KV_PATH
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test
|
||||||
|
def simple-local-set-table [] {
|
||||||
|
if ('sqlite' not-in (version).features) { return }
|
||||||
|
|
||||||
|
let key = (random uuid)
|
||||||
|
|
||||||
|
kv set -t foo $key 42
|
||||||
|
let actual = (kv get -t foo $key)
|
||||||
|
let expected = 42
|
||||||
|
assert equal $actual $expected
|
||||||
|
|
||||||
|
kv drop -t foo $key | ignore
|
||||||
|
}
|
Reference in New Issue
Block a user