Skip to content
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

Database queries with Diesel #192

Merged
merged 54 commits into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
3e85aa3
diesel successfully generates a schema.rs
david-crespo Aug 7, 2021
121204b
successfully make a dang query
david-crespo Aug 7, 2021
4ee670e
actually filter by name + test for that
david-crespo Aug 8, 2021
c62a807
placeholder Into<DieselError> for Error so we can be cool
david-crespo Aug 8, 2021
0d418fa
delete datastore project_fetch to show it's been replaced
david-crespo Aug 8, 2021
5c9c727
Project2 -> DieselProject for clarity
david-crespo Aug 8, 2021
644b4d1
diesel 1.4.4 -> 1.4.6 (latest). not sure where I got 1.4.4 from
david-crespo Aug 8, 2021
ad7d5e1
uhhh it's not actually async
david-crespo Aug 8, 2021
ab3ab9e
get projects list works
david-crespo Aug 9, 2021
b353504
Add ToSql/FromSql for Name
smklein Aug 9, 2021
39ed898
Fix pagination order
smklein Aug 11, 2021
efe71ce
Unify 'DieselProject' and 'Project', move connection pool access to d…
smklein Aug 11, 2021
520411f
Avoid leaking DB abstraction into nexus.rs
smklein Aug 11, 2021
880ddd1
Convert Instances to using Diesel
smklein Aug 12, 2021
842314b
Fix tests
smklein Aug 12, 2021
6b34785
Fix error handling, pagination. Tests should ACTUALLY pass now
smklein Aug 13, 2021
fbb56a4
Update time_modified when updating project
smklein Aug 13, 2021
fcf5070
[bugfix] Don't need to set time_modified twice! Already in ProjectUpd…
smklein Aug 13, 2021
3731cf6
delete notes.txt and /migrations
david-crespo Aug 13, 2021
c31b87d
Integrate CTE support for (Update + Query)
smklein Aug 18, 2021
26beb65
Merge branch 'diesel-test' of github.com:oxidecomputer/omicron into d…
smklein Aug 18, 2021
ebcd219
Merge branch 'main' into diesel-test
smklein Aug 18, 2021
3fa55e9
Appease clippy with type aliases
smklein Aug 18, 2021
fa45743
Incorporate feedback from Georg
smklein Aug 18, 2021
1e2bbf0
UpdateCTE -> UpdateAndCheck
smklein Aug 18, 2021
3598f71
Workaround async diesel support
smklein Aug 23, 2021
e715d2b
First revision of disk conversion
smklein Aug 23, 2021
3ac603d
Disk tests passing now
smklein Aug 23, 2021
cacd6c2
Partial pagination compiling
smklein Aug 24, 2021
a6dbbae
WIP paginate
smklein Aug 24, 2021
8f3f3da
more full pagination example
smklein Aug 24, 2021
e38f16e
pagination cleaned up
smklein Aug 24, 2021
318135f
Update UpdateAndQuery to return the queried object
smklein Aug 24, 2021
50f8439
Oximeter migration
smklein Aug 25, 2021
9714572
Convert all Networking-related structures to Diesel
smklein Aug 25, 2021
8c1a237
oops no local steno
smklein Aug 25, 2021
fda02c4
Merge branch 'main' into diesel-test
smklein Aug 25, 2021
b570c9a
Convert all saga types, remove unused SQL utilities
smklein Aug 26, 2021
76ddf44
Async works, but using a breaking change on 1.4.7
smklein Aug 28, 2021
f6de7ca
Diesel 2.0 - building, tests passing
smklein Aug 28, 2021
330c82c
Diesel 2.0, full async support, improved trait bounds
smklein Aug 30, 2021
46548ed
fmt
smklein Aug 30, 2021
c4c5f35
Define steno / DB conversions within Omicron using newtype pattern
smklein Aug 30, 2021
cc824a1
Clippy, newtype wrappers
smklein Aug 30, 2021
ed1f050
... actually fix clippy lints
smklein Aug 30, 2021
43fc587
Merge branch 'main' into diesel-test
smklein Aug 30, 2021
e1baefc
Minor cleanups, docs
smklein Aug 30, 2021
6ce512c
s/instance_state/state
smklein Aug 31, 2021
c59c9fa
Readme
smklein Aug 31, 2021
a68d4ba
fmt
smklein Aug 31, 2021
654ccf6
Improved Mac Address type safety
smklein Sep 1, 2021
f494e77
Simplify connection pool
smklein Sep 1, 2021
0b01683
Clarify TODO in saga_recovery
smklein Sep 1, 2021
de45714
Comment cleanup
smklein Sep 1, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions diesel.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# For documentation on how to configure this file,
# see diesel.rs/guides/configuring-diesel-cli

[print_schema]
file = "omicron-nexus/src/db/diesel_schema.rs"
Empty file added migrations/.gitkeep
Empty file.
5 changes: 5 additions & 0 deletions migrations/00000000000000_diesel_initial_setup/down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- This file was automatically created by Diesel to setup helper functions
-- and other internal bookkeeping. This file is safe to edit, any future
-- changes will be added to existing projects as new migrations.

SELECT 1;
21 changes: 21 additions & 0 deletions migrations/00000000000000_diesel_initial_setup/up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-- This file was automatically created by Diesel to setup helper functions
smklein marked this conversation as resolved.
Show resolved Hide resolved
-- and other internal bookkeeping. This file is safe to edit, any future
-- changes will be added to existing projects as new migrations.




-- Sets up a trigger for the given table to automatically set a column called
-- `updated_at` whenever the row is modified (unless `updated_at` was included
-- in the modified columns)
--
-- # Example
--
-- ```sql
-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
--
-- SELECT diesel_manage_updated_at('users');
-- ```

-- had to replace generated contents with this because it contained syntax CRDB didn't like
SELECT 1;
31 changes: 31 additions & 0 deletions notes.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
there are still issues with CRDB compatibility:
https://github.com/cockroachdb/cockroach/issues/13787#issuecomment-748301955

first install postgres first to fix -lpq linker error:

brew install postgresql
cargo install diesel_cli --no-default-features --features postgres

add diesel to deps

diesel = { version = "1.4.4", features = ["postgres"] }

run DB (imitate console API start script). in two separate terminals:

cargo run --bin=omicron-dev -- db-run --no-populate
cargo run --bin=omicron-dev -- db-populate --database-url postgresql://[email protected]:32221

then run setup

export DATABASE_URL=postgresql://root@localhost:32221/omicron?sslmode=disable
diesel setup

SQL changes for compatibility reasons:
- replace contents of generated up.sql and down.sql with SELECT 1;
- comment out DbMetadata table in dbinit.sql bc it has no primary key

Then run:

diesel migration run

This successfully generates src/schema.rs
1 change: 1 addition & 0 deletions omicron-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2018"
[dependencies]
anyhow = "1.0"
async-trait = "0.1.51"
diesel = { version = "1.4.4", features = ["postgres", "r2d2", "chrono", "uuidv07"] }
futures = "0.3.15"
http = "0.2.0"
hyper = "0.14"
Expand Down
14 changes: 14 additions & 0 deletions omicron-common/src/api/external/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use crate::api::external::Name;
use crate::api::external::ResourceType;
use diesel::result::Error as DieselError;
use dropshot::HttpError;
use dropshot::HttpErrorResponseBody;
use serde::Deserialize;
Expand Down Expand Up @@ -163,6 +164,19 @@ impl Error {
}
}

impl From<DieselError> for Error {
fn from(error: DieselError) -> Self {
match error {
// our not found wants by_id or by_name, which this error doesn't have
// DieselError::NotFound => Error::not_found_other(...),
DieselError::DatabaseError(kind, _info) => {
Error::unavail(format!("Database error: {:?}", kind).as_str())
}
_ => Error::internal_error("Unknown diesel error"),
}
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this probably won't work out because in order to produce our Error, we need other info from context that DieselError can't give us

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that might be okay - just means that we can define more featureful converters from DieselError to Error, depending on the type.

I imagine that NotFound triggers more work for the caller to add context, and everything else is more-or-less passthrough.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've gone ahead and updated these with two explicit constructions that provide enough context to pass all tests.

Copy link
Contributor Author

@david-crespo david-crespo Aug 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! Exactly what I was picturing, but I didn't know how to do it.

impl From<Error> for HttpError {
/**
* Converts an `Error` error into an `HttpError`. This defines how
Expand Down
6 changes: 6 additions & 0 deletions omicron-common/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ pub struct PostgresConfigWithUrl {
config: tokio_postgres::config::Config,
}

impl PostgresConfigWithUrl {
pub fn url(&self) -> String {
self.url_raw.clone()
}
}

impl FromStr for PostgresConfigWithUrl {
type Err = tokio_postgres::Error;

Expand Down
22 changes: 11 additions & 11 deletions omicron-common/src/sql/dbinit.sql
Original file line number Diff line number Diff line change
Expand Up @@ -417,15 +417,15 @@ CREATE TABLE omicron.public.SagaNodeEvent (
* nothing to ensure it gets bumped when it should be, but it's a start.
*/

CREATE TABLE omicron.public.DbMetadata (
name STRING(63) NOT NULL,
value STRING(1023) NOT NULL
);
-- CREATE TABLE omicron.public.DbMetadata (
-- name STRING(63) NOT NULL,
-- value STRING(1023) NOT NULL
-- );

INSERT INTO omicron.public.DbMetadata (
name,
value
) VALUES (
'schema_version',
'1.0.0'
);
-- INSERT INTO omicron.public.DbMetadata (
-- name,
-- value
-- ) VALUES (
-- 'schema_version',
-- '1.0.0'
-- );
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment this out because the table doesn't have a primary key and diesel doesn't like that. real solution would be to just give it a primary key

1 change: 1 addition & 0 deletions omicron-nexus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ edition = "2018"
anyhow = "1.0"
async-trait = "0.1.51"
bb8 = "0.7.0"
diesel = { version = "1.4.4", features = ["postgres", "r2d2", "chrono", "uuidv07"] }
bb8-postgres = "0.7.0"
futures = "0.3.15"
http = "0.2.0"
Expand Down
4 changes: 4 additions & 0 deletions omicron-nexus/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use slog::Logger;
use std::sync::Arc;
use uuid::Uuid;

use diesel::{r2d2, PgConnection};

/**
* Shared state available to all API request handlers
*/
Expand All @@ -27,13 +29,15 @@ impl ServerContext {
rack_id: &Uuid,
log: Logger,
pool: db::Pool,
dpool: r2d2::Pool<r2d2::ConnectionManager<PgConnection>>,
nexus_id: &Uuid,
) -> Arc<ServerContext> {
Arc::new(ServerContext {
nexus: Nexus::new_with_id(
rack_id,
log.new(o!("component" => "nexus")),
pool,
dpool,
nexus_id,
),
log,
Expand Down
14 changes: 0 additions & 14 deletions omicron-nexus/src/db/datastore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,20 +84,6 @@ impl DataStore {
.await
}

/// Fetch metadata for a project
pub async fn project_fetch(
&self,
project_name: &Name,
) -> LookupResult<db::model::Project> {
let client = self.pool.acquire().await?;
sql_fetch_row_by::<LookupByUniqueName, Project>(
&client,
(),
project_name,
)
.await
}

/// Delete a project
/*
* TODO-correctness This needs to check whether there are any resources that
Expand Down
Loading