///|
/// Entry point for the CLI program.
fn main {
let argv = @env.args()
if argv.length() < 3 {
print_usage()
return
}
let dir = argv[1]
let cmd = argv[2]
// Set default maximum file size to 10MB
let max_file_size = 10 * 1024 * 1024
try {
let db = @moonkv.DB::open(dir, max_file_size)
if cmd == "put" {
if argv.length() < 5 {
println("Error: put command requires key and value arguments.")
println("Usage: moon run cmd/main -- put ")
return
}
let key = argv[3]
let value_str = argv[4]
let value = @moonkv.string_to_bytes(value_str)
db.put(key, value)
println("OK")
} else if cmd == "put-ttl" {
if argv.length() < 6 {
println(
"Error: put-ttl command requires key, value, and ttl arguments.",
)
println(
"Usage: moon run cmd/main -- put-ttl ",
)
return
}
let key = argv[3]
let value_str = argv[4]
let value = @moonkv.string_to_bytes(value_str)
let ttl = parse_int64(argv[5])
db.put_ttl(key, value, ttl)
println("OK")
} else if cmd == "get" {
if argv.length() < 4 {
println("Error: get command requires key argument.")
println("Usage: moon run cmd/main -- get ")
return
}
let key = argv[3]
let val = db.get(key)
println(@moonkv.bytes_to_string(val))
} else if cmd == "delete" {
if argv.length() < 4 {
println("Error: delete command requires key argument.")
println("Usage: moon run cmd/main -- delete ")
return
}
let key = argv[3]
db.delete(key)
println("OK")
} else if cmd == "delete-prefix" {
if argv.length() < 5 {
println(
"Error: delete-prefix command requires prefix and limit arguments.",
)
println(
"Usage: moon run cmd/main -- delete-prefix ",
)
return
}
let deleted = db.delete_prefix(argv[3], parse_int(argv[4]))
println("deleted=\{deleted}")
} else if cmd == "merge" {
db.merge()
println("Compaction completed successfully.")
} else if cmd == "scan" {
if argv.length() < 5 {
println("Error: scan command requires prefix and limit arguments.")
println("Usage: moon run cmd/main -- scan ")
return
}
let prefix = argv[3]
let limit = parse_int(argv[4])
let rows = db.scan_prefix(prefix, limit)
for row in rows {
println("\{row.0}\t\{@moonkv.bytes_to_string(row.1)}")
}
} else if cmd == "stats" {
let stats = db.stats()
println("keys=\{stats.key_count}")
println("live_value_bytes=\{stats.live_value_bytes}")
println("active_file_id=\{stats.active_file_id}")
println("active_file_offset=\{stats.active_file_offset}")
println("max_file_size=\{stats.max_file_size}")
println("logical_clock=\{stats.logical_clock}")
} else if cmd == "verify" {
let verified = db.verify()
println("verified_keys=\{verified}")
} else if cmd == "fingerprint" {
println("fingerprint=\{db.fingerprint()}")
} else {
println("Unknown command: \{cmd}")
print_usage()
}
db.close()
} catch {
@moonkv.MoonKVError::KeyNotFound(k) => println("Error: Key not found: \{k}")
@moonkv.MoonKVError::IOError(msg) => println("IO Error: \{msg}")
@moonkv.MoonKVError::CorruptedDatabase(msg) =>
println("Corrupted Database: \{msg}")
@moonkv.MoonKVError::InvalidRecord(msg) => println("Invalid Record: \{msg}")
}
}
///|
/// Prints CLI usage instructions.
fn print_usage() -> Unit {
println("moonkv - High-performance Log-Structured Key-Value Store in MoonBit")
println("")
println("Usage:")
println(" moon run cmd/main -- [args]")
println("")
println("Commands:")
println(" put Write a key-value pair")
println(
" put-ttl Write a key-value pair with Time-To-Live (logical clocks)",
)
println(" get Retrieve the value of a key")
println(" delete Delete a key")
println(
" delete-prefix Atomically delete up to n matching keys",
)
println(" merge Compact the database logs")
println(" scan Scan visible keys in sorted order")
println(" stats Show key count and storage metadata")
println(" verify Read and validate all visible values")
println(
" fingerprint Print a deterministic keyspace fingerprint",
)
}
///|
/// Basic 64-bit integer parser.
fn parse_int64(s : String) -> Int64 {
let mut val = 0L
let len = s.length()
let mut start = 0
let is_neg = if len > 0 && s[0] == '-' {
start = 1
true
} else {
false
}
for i = start; i < len; i = i + 1 {
let ch = s[i]
if ch >= '0' && ch <= '9' {
let digit = (ch.to_int() - '0'.to_int()).to_int64()
val = val * 10L + digit
}
}
if is_neg {
-val
} else {
val
}
}
///|
/// Basic signed integer parser used by scan limits.
fn parse_int(s : String) -> Int {
let mut val = 0
let len = s.length()
let mut start = 0
let is_neg = if len > 0 && s[0] == '-' {
start = 1
true
} else {
false
}
for i = start; i < len; i = i + 1 {
let ch = s[i]
if ch >= '0' && ch <= '9' {
val = val * 10 + ch.to_int() - '0'.to_int()
}
}
if is_neg {
-val
} else {
val
}
}