Skip to content

Commit 5b4d988

Browse files
Introduce 'create-init' command to load a new database from schema/data (#303)
## Usage and product changes We introduce a new command `database create-init`, which 1) create the new database 2) loads a provided schema file (from URL, or from local file) 3) loads a provided data file (from URL or from local file) Command format: ``` database create-init <db> <schema file> <data file> <[optional] schema file sha256 (hex or sha256:hex)> <[optional] data file sha256 (hex or sha256:hex)> ``` Usage example to load bookstore example from `typedb-examples`: ``` >> database create-init bookstore https://github.com/typedb/typedb-examples/releases/download/3.5.0/bookstore-schema.tql https://github.com/typedb/typedb-examples/releases/download/3.5.0/bookstore-data.tql ``` You can also optionally provide sha256 checksums to verify your files are correct (these come from the Github releases page): ``` >> database create-init bookstore https://github.com/typedb/typedb-examples/releases/download/3.5.0/bookstore-schema.tql https://github.com/typedb/typedb-examples/releases/download/3.5.0/bookstore-data.tql sha256:b2de488d9f64ccdfdba016029c7932be69ec5d35d18977c85bb12ad4cc97e95f sha256:828806afe1ce939d0ee87d6ae89598f5d7f967155c7757263b151673480bcad1 ``` We've also upgraded the `source` command in a transaction to allow reading from a remote URL, not just local files: ``` bookstore::write >> source https://github.com/typedb/typedb-examples/releases/download/3.5.0/bookstore-data.tql ``` This can also optionally take a sha256 (the `sha256:` prefix optional): ``` bookstore::write >> source https://github.com/typedb/typedb-examples/releases/download/3.5.0/bookstore-data.tql 828806afe1ce939d0ee87d6ae89598f5d7f967155c7757263b151673480bcad1 ``` These commands can also receive local in relative or absolute path formats. ## Implementation Chain together database creation, and schema+data file sourcing. Extend the existing `source` behaviour to allow retriving the file over the network from a remote URL. Refactor the help menu to make it handle the long content more effectively.
1 parent b847513 commit 5b4d988

File tree

8 files changed

+292
-97
lines changed

8 files changed

+292
-97
lines changed

BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ rust_binary(
3333
"@crates//:rustyline",
3434
"@crates//:sentry",
3535
"@crates//:serde_json",
36+
"@crates//:sha2",
37+
"@crates//:ureq",
3638
"@crates//:tokio",
3739
],
3840
compile_data = ["//:VERSION"],

Cargo.lock

Lines changed: 45 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,31 @@ features = {}
2323
version = "1.45.0"
2424
default-features = false
2525

26+
[dependencies.glob]
27+
features = []
28+
version = "0.3.2"
29+
default-features = false
30+
31+
[dependencies.futures]
32+
features = ["alloc", "async-await", "default", "executor", "futures-executor", "std", "thread-pool"]
33+
version = "0.3.31"
34+
default-features = false
35+
36+
[dependencies.rpassword]
37+
features = []
38+
version = "7.4.0"
39+
default-features = false
40+
41+
[dependencies.home]
42+
features = []
43+
version = "0.5.11"
44+
default-features = false
45+
46+
[dependencies.sha2]
47+
features = ["default", "std"]
48+
version = "0.10.9"
49+
default-features = false
50+
2651
[dependencies.rustyline]
2752
features = ["custom-bindings", "fd-lock", "radix_trie", "with-file-history"]
2853
version = "15.0.0"
@@ -33,11 +58,6 @@ features = {}
3358
version = "4.5.38"
3459
default-features = false
3560

36-
[dependencies.glob]
37-
features = []
38-
version = "0.3.2"
39-
default-features = false
40-
4161
[dependencies.typeql]
4262
features = []
4363
git = "https://github.com/typedb/typeql"
@@ -50,31 +70,21 @@ features = {}
5070
tag = "3.4.4"
5171
default-features = false
5272

53-
[dependencies.futures]
54-
features = ["alloc", "async-await", "default", "executor", "futures-executor", "std", "thread-pool"]
55-
version = "0.3.31"
56-
default-features = false
57-
5873
[dependencies.serde_json]
5974
features = ["alloc", "default", "indexmap", "preserve_order", "raw_value", "std"]
6075
version = "1.0.140"
6176
default-features = false
6277

63-
[dependencies.rpassword]
64-
features = []
65-
version = "7.4.0"
66-
default-features = false
67-
68-
[dependencies.home]
69-
features = []
70-
version = "0.5.11"
71-
default-features = false
72-
7378
[dependencies.sentry]
7479
features = ["backtrace", "contexts", "httpdate", "panic", "sentry-backtrace", "sentry-contexts", "sentry-panic", "ureq"]
7580
version = "0.36.0"
7681
default-features = false
7782

83+
[dependencies.ureq]
84+
features = ["default", "gzip", "tls"]
85+
version = "2.12.1"
86+
default-features = false
87+
7888
[[test]]
7989
path = "tests/assembly/test_assembly.rs"
8090
name = "test-assembly-native"

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ platform-specific distribution.
3030

3131
## Command line arguments
3232

33-
You can provide several command arguments when running console in the terminal.
33+
You can provide several command arguments when running console in the terminal, of which the typically-used ones are:
3434

3535
- `--username=<username>` : TypeDB server username to log in with (mandatory).
36-
- `--address=<address>` : TypeDB server address to which the console will connect to (mandatory). Ensure it is prefixed with `https://` when using TLS.
36+
- `--address=<address>` : TypeDB server address to which the console will connect to (mandatory)
3737
- `--script=<path>` : Run commands in the script file in non-interactive mode.
3838
- `--command=<command1> --command=<command2> ...` : Run commands in non-interactive mode.
3939
- `-V, --version` : Print version information and exit.
@@ -54,8 +54,6 @@ Alternatively, you may securely connect by managing your own certificates for bo
5454
and provide your certificate to the console with:
5555
`--tls-root-ca=<path>`
5656

57-
See documentation at https://typedb.com/docs/manual/configure/encryption for further details.
58-
5957
## Console commands
6058

6159
TypeDB Console provides two levels of interaction: server-level commands and transaction-level commands.

src/main.rs

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ use crate::{
2828
cli::{Args, ADDRESS_VALUE_NAME, USERNAME_VALUE_NAME},
2929
completions::{database_name_completer_fn, file_completer},
3030
operations::{
31-
database_create, database_delete, database_export, database_import, database_list, database_schema,
32-
transaction_close, transaction_commit, transaction_query, transaction_read, transaction_rollback,
33-
transaction_schema, transaction_source, transaction_write, user_create, user_delete, user_list,
34-
user_update_password,
31+
database_create, database_create_init, database_delete, database_export, database_import, database_list,
32+
database_schema, transaction_close, transaction_commit, transaction_query, transaction_read,
33+
transaction_rollback, transaction_schema, transaction_source, transaction_write, user_create, user_delete,
34+
user_list, user_update_password,
3535
},
3636
repl::{
3737
command::{get_word, parse_one_query, CommandInput, CommandLeaf, Subcommand},
@@ -318,7 +318,8 @@ fn execute_commands(
318318
match command.execute(context, arguments) {
319319
Ok(_) => &input[next_command_index..],
320320
Err(err) => {
321-
let message = format!("Error executing command: '{}'\n{}", command_string.trim(), err);
321+
let message =
322+
format!("**Error executing command**\n{}\n--> Error\n{}", command_string.trim(), err);
322323
println_error!("{}", message);
323324
return Err(CommandError { message });
324325
}
@@ -340,43 +341,54 @@ fn entry_repl(driver: Arc<TypeDBDriver>, runtime: BackgroundRuntime) -> Repl<Con
340341
.add(CommandLeaf::new_with_input(
341342
"create",
342343
"Create a new database with the given name.",
343-
CommandInput::new("db", get_word, None, None),
344+
CommandInput::new_required("db", get_word, None),
344345
database_create,
345346
))
347+
.add(CommandLeaf::new_with_inputs(
348+
"create-init",
349+
"Create a new database with the given name and load schema and data from files. Files may be HTTP-hosted files, or absolute or relative paths. File contents are treated identically to 'transaction source' commands run explicitly, and may contain multiple queries separated by 'end;' markers. File sha256 sums maybe provided.",
350+
vec![
351+
CommandInput::new_required("db", get_word, None),
352+
CommandInput::new_required("schema file", get_word, None),
353+
CommandInput::new_required("data file", get_word, None),
354+
CommandInput::new_optional("schema file sha256 (hex or sha256:hex)", get_word, None),
355+
CommandInput::new_optional("data file sha256 (hex or sha256:hex)", get_word, None),
356+
],
357+
database_create_init,
358+
))
346359
.add(CommandLeaf::new_with_input(
347360
"delete",
348361
"Delete the database with the given name.",
349-
CommandInput::new("db", get_word, None, Some(database_name_completer_fn(driver.clone(), runtime.clone()))),
362+
CommandInput::new_required("db", get_word, Some(database_name_completer_fn(driver.clone(), runtime.clone()))),
350363
database_delete,
351364
))
352365
.add(CommandLeaf::new_with_input(
353366
"schema",
354367
"Retrieve the TypeQL representation of a database's schema.",
355-
CommandInput::new("db", get_word, None, Some(database_name_completer_fn(driver.clone(), runtime.clone()))),
368+
CommandInput::new_required("db", get_word, Some(database_name_completer_fn(driver.clone(), runtime.clone()))),
356369
database_schema,
357370
))
358371
.add(CommandLeaf::new_with_inputs(
359372
"import",
360-
"Create a database with the given name based on another previously exported database.",
373+
"Create a database with the given name based on another previously exported database. File paths must be absolute or relative paths on the local machine.",
361374
vec![
362-
CommandInput::new("db", get_word, None, None),
363-
CommandInput::new("schema file path", get_word, None, None),
364-
CommandInput::new("data file path", get_word, None, None),
375+
CommandInput::new_required("db", get_word, None),
376+
CommandInput::new_required("schema file path", get_word, None),
377+
CommandInput::new_required("data file path", get_word, None),
365378
],
366379
database_import,
367380
))
368381
.add(CommandLeaf::new_with_inputs(
369382
"export",
370383
"Export a database into a schema definition and a data files.",
371384
vec![
372-
CommandInput::new(
385+
CommandInput::new_required(
373386
"db",
374387
get_word,
375-
None,
376388
Some(database_name_completer_fn(driver.clone(), runtime.clone())),
377389
),
378-
CommandInput::new("schema file path", get_word, None, None),
379-
CommandInput::new("data file path", get_word, None, None),
390+
CommandInput::new_required("schema file path", get_word, None),
391+
CommandInput::new_required("data file path", get_word, None),
380392
],
381393
database_export,
382394
));
@@ -387,23 +399,23 @@ fn entry_repl(driver: Arc<TypeDBDriver>, runtime: BackgroundRuntime) -> Repl<Con
387399
"create",
388400
"Create new user.",
389401
vec![
390-
CommandInput::new("name", get_word, None, None),
391-
CommandInput::new("password", get_word, Some(get_word), None),
402+
CommandInput::new_required("name", get_word, None),
403+
CommandInput::new_hidden("password", get_word, get_word, None),
392404
],
393405
user_create,
394406
))
395407
.add(CommandLeaf::new_with_input(
396408
"delete",
397409
"Delete existing user.",
398-
CommandInput::new("name", get_word, None, None),
410+
CommandInput::new_required("name", get_word, None),
399411
user_delete,
400412
))
401413
.add(CommandLeaf::new_with_inputs(
402414
"update-password",
403415
"Set existing user's password.",
404416
vec![
405-
CommandInput::new("name", get_word, None, None),
406-
CommandInput::new("new password", get_word, Some(get_word), None),
417+
CommandInput::new_required("name", get_word, None),
418+
CommandInput::new_hidden("new password", get_word, get_word, None),
407419
],
408420
user_update_password,
409421
));
@@ -412,19 +424,31 @@ fn entry_repl(driver: Arc<TypeDBDriver>, runtime: BackgroundRuntime) -> Repl<Con
412424
.add(CommandLeaf::new_with_input(
413425
"read",
414426
"Open read transaction.",
415-
CommandInput::new("db", get_word, None, Some(database_name_completer_fn(driver.clone(), runtime.clone()))),
427+
CommandInput::new_required(
428+
"db",
429+
get_word,
430+
Some(database_name_completer_fn(driver.clone(), runtime.clone())),
431+
),
416432
transaction_read,
417433
))
418434
.add(CommandLeaf::new_with_input(
419435
"write",
420436
"Open write transaction.",
421-
CommandInput::new("db", get_word, None, Some(database_name_completer_fn(driver.clone(), runtime.clone()))),
437+
CommandInput::new_required(
438+
"db",
439+
get_word,
440+
Some(database_name_completer_fn(driver.clone(), runtime.clone())),
441+
),
422442
transaction_write,
423443
))
424444
.add(CommandLeaf::new_with_input(
425445
"schema",
426446
"Open schema transaction.",
427-
CommandInput::new("db", get_word, None, Some(database_name_completer_fn(driver.clone(), runtime.clone()))),
447+
CommandInput::new_required(
448+
"db",
449+
get_word,
450+
Some(database_name_completer_fn(driver.clone(), runtime.clone())),
451+
),
428452
transaction_schema,
429453
));
430454

@@ -457,17 +481,20 @@ fn transaction_repl(database: &str, transaction_type: TransactionType) -> Repl<C
457481
"Close the current transaction.",
458482
transaction_close,
459483
))
460-
.add(CommandLeaf::new_with_input(
484+
.add(CommandLeaf::new_with_inputs(
461485
"source",
462-
"Synchronously execute a file containing a sequence of TypeQL queries with full validation. Queries can be explicitly ended with 'end;' if required. Path may be absolute or relative to the invoking script (if there is one) otherwise relative to the current working directory.",
463-
CommandInput::new("file", get_word, None, Some(Box::new(file_completer))),
486+
"Synchronously execute a file containing a sequence of TypeQL queries with full validation. Queries can be explicitly separated with 'end;' if required. May be a HTTP-hosted file, an absolute path, or a relative path. Relative paths are relative to the invoking script (if there is one) or else a path relative to the current working directory. A sha256 may be optionally provided.",
487+
vec![
488+
CommandInput::new_required("file", get_word, Some(Box::new(file_completer))),
489+
CommandInput::new_optional("file sha256 (hex or sha256:hex)", get_word, None),
490+
],
464491
transaction_source,
465492
))
466493
// default: no token
467494
.add(CommandLeaf::new_with_input(
468495
"",
469496
"Execute query string.",
470-
CommandInput::new("query", parse_one_query, None, None),
497+
CommandInput::new_required("query", parse_one_query, None),
471498
transaction_query,
472499
));
473500
repl

0 commit comments

Comments
 (0)