Skip to content

Commit

Permalink
nexus shattering 3 of 3: Extract nexus-db-model crate from nexus::db:…
Browse files Browse the repository at this point in the history
…:model (#1478)
  • Loading branch information
jgallagher authored Jul 26, 2022
1 parent 4f86901 commit 5e835f1
Show file tree
Hide file tree
Showing 71 changed files with 524 additions and 408 deletions.
27 changes: 27 additions & 0 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ members = [
"nexus",
"nexus/authz-macros",
"nexus/db-macros",
"nexus/db-model",
"nexus/defaults",
"nexus/test-utils",
"nexus/test-utils-macros",
Expand Down Expand Up @@ -47,6 +48,7 @@ default-members = [
"nexus",
"nexus/authz-macros",
"nexus/db-macros",
"nexus/db-model",
"nexus/defaults",
"nexus/types",
"package",
Expand Down
1 change: 1 addition & 0 deletions nexus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ usdt = "0.3.1"
authz-macros = { path = "authz-macros" }
db-macros = { path = "db-macros" }
nexus-defaults = { path = "defaults" }
nexus-db-model = { path = "db-model" }
nexus-types = { path = "types" }

[dependencies.chrono]
Expand Down
4 changes: 2 additions & 2 deletions nexus/db-macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ fn build_resource_impl(
}
};

impl crate::db::identity::Resource for #struct_name {
impl ::nexus_types::identity::Resource for #struct_name {
fn id(&self) -> ::uuid::Uuid {
self.identity.id
}
Expand Down Expand Up @@ -381,7 +381,7 @@ fn build_asset_impl(
}
};

impl crate::db::identity::Asset for #struct_name {
impl ::nexus_types::identity::Asset for #struct_name {
fn id(&self) -> ::uuid::Uuid {
self.identity.id
}
Expand Down
18 changes: 9 additions & 9 deletions nexus/db-macros/src/lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ fn generate_misc_helpers(config: &Config) -> TokenStream {
/// Build the `authz` object for this resource
fn make_authz(
authz_parent: &authz::#parent_resource_name,
db_row: &model::#resource_name,
db_row: &nexus_db_model::#resource_name,
lookup_type: LookupType,
) -> authz::#resource_name {
authz::#resource_name::new(
Expand Down Expand Up @@ -533,7 +533,7 @@ fn generate_lookup_methods(config: &Config) -> TokenStream {
/// This is equivalent to `fetch_for(authz::Action::Read)`.
pub async fn fetch(
&self,
) -> LookupResult<(#(authz::#path_types,)* model::#resource_name)> {
) -> LookupResult<(#(authz::#path_types,)* nexus_db_model::#resource_name)> {
self.fetch_for(authz::Action::Read).await
}

Expand All @@ -549,7 +549,7 @@ fn generate_lookup_methods(config: &Config) -> TokenStream {
pub async fn fetch_for(
&self,
action: authz::Action,
) -> LookupResult<(#(authz::#path_types,)* model::#resource_name)> {
) -> LookupResult<(#(authz::#path_types,)* nexus_db_model::#resource_name)> {
let lookup = self.lookup_root();
let opctx = &lookup.opctx;
let datastore = &lookup.datastore;
Expand Down Expand Up @@ -712,7 +712,7 @@ fn generate_database_functions(config: &Config) -> TokenStream {
#parent_lookup_arg_formal
name: &Name,
action: authz::Action,
) -> LookupResult<(authz::#resource_name, model::#resource_name)> {
) -> LookupResult<(authz::#resource_name, nexus_db_model::#resource_name)> {
let (#resource_authz_name, db_row) =
Self::lookup_by_name_no_authz(
opctx,
Expand All @@ -738,15 +738,15 @@ fn generate_database_functions(config: &Config) -> TokenStream {
#parent_lookup_arg_formal
name: &Name,
) -> LookupResult<
(authz::#resource_name, model::#resource_name)
(authz::#resource_name, nexus_db_model::#resource_name)
> {
use db::schema::#resource_as_snake::dsl;

dsl::#resource_as_snake
#soft_delete_filter
.filter(dsl::name.eq(name.clone()))
#lookup_filter
.select(model::#resource_name::as_select())
.select(nexus_db_model::#resource_name::as_select())
.get_result_async(
datastore.pool_authorized(opctx).await?
)
Expand Down Expand Up @@ -804,7 +804,7 @@ fn generate_database_functions(config: &Config) -> TokenStream {
datastore: &DataStore,
#(#pkey_names: &#pkey_types,)*
action: authz::Action,
) -> LookupResult<(#(authz::#path_types,)* model::#resource_name)> {
) -> LookupResult<(#(authz::#path_types,)* nexus_db_model::#resource_name)> {
let (#(#path_authz_names,)* db_row) =
Self::lookup_by_id_no_authz(
opctx,
Expand All @@ -826,13 +826,13 @@ fn generate_database_functions(config: &Config) -> TokenStream {
opctx: &OpContext,
datastore: &DataStore,
#(#pkey_names: &#pkey_types,)*
) -> LookupResult<(#(authz::#path_types,)* model::#resource_name)> {
) -> LookupResult<(#(authz::#path_types,)* nexus_db_model::#resource_name)> {
use db::schema::#resource_as_snake::dsl;

let db_row = dsl::#resource_as_snake
#soft_delete_filter
#(.filter(dsl::#pkey_column_names.eq(#pkey_names.clone())))*
.select(model::#resource_name::as_select())
.select(nexus_db_model::#resource_name::as_select())
.get_result_async(datastore.pool_authorized(opctx).await?)
.await
.map_err(|e| {
Expand Down
29 changes: 29 additions & 0 deletions nexus/db-model/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
[package]
name = "nexus-db-model"
version = "0.1.0"
edition = "2021"
license = "MPL-2.0"

[dependencies]
anyhow = "1.0"
chrono = { version = "0.4", features = ["serde"] }
diesel = { version = "2.0.0-rc.1", features = ["postgres", "r2d2", "chrono", "serde_json", "network-address", "uuid"] }
hex = "0.4.3"
ipnetwork = "0.18"
macaddr = { version = "1.0.1", features = [ "serde_std" ]}
newtype_derive = "0.1.6"
parse-display = "0.5.4"
rand = "0.8.5"
ref-cast = "1.0"
schemars = { version = "0.8.10", features = ["chrono", "uuid1"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
uuid = { version = "1.1.0", features = ["serde", "v4"] }

steno = { git = "https://github.com/oxidecomputer/steno", branch = "main" }

db-macros = { path = "../db-macros" }
omicron-common = { path = "../../common" }
nexus-defaults = { path = "../defaults" }
nexus-types = { path = "../types" }
sled-agent-client = { path = "../../sled-agent-client" }
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use super::impl_enum_type;
use crate::external_api::params;
use nexus_types::external_api::params;
use omicron_common::api::external;
use serde::{Deserialize, Serialize};

Expand Down
File renamed without changes.
155 changes: 155 additions & 0 deletions nexus/db-model/src/collection.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use diesel::pg::Pg;
use diesel::Column;
use diesel::ExpressionMethods;
use diesel::Selectable;
use std::fmt::Debug;

/// Trait to be implemented by any structs representing a collection.
/// For example, since Organizations have a one-to-many relationship with
/// Projects, the Organization datatype should implement this trait.
/// ```
/// # use diesel::prelude::*;
/// # use nexus_db_model::DatastoreCollectionConfig;
/// # use nexus_db_model::Generation;
/// #
/// # table! {
/// # test_schema.organization (id) {
/// # id -> Uuid,
/// # time_deleted -> Nullable<Timestamptz>,
/// # rcgen -> Int8,
/// # }
/// # }
/// #
/// # table! {
/// # test_schema.project (id) {
/// # id -> Uuid,
/// # time_deleted -> Nullable<Timestamptz>,
/// # organization_id -> Uuid,
/// # }
/// # }
///
/// #[derive(Queryable, Insertable, Debug, Selectable)]
/// #[diesel(table_name = project)]
/// struct Project {
/// pub id: uuid::Uuid,
/// pub time_deleted: Option<chrono::DateTime<chrono::Utc>>,
/// pub organization_id: uuid::Uuid,
/// }
///
/// #[derive(Queryable, Insertable, Debug, Selectable)]
/// #[diesel(table_name = organization)]
/// struct Organization {
/// pub id: uuid::Uuid,
/// pub time_deleted: Option<chrono::DateTime<chrono::Utc>>,
/// pub rcgen: Generation,
/// }
///
/// impl DatastoreCollectionConfig<Project> for Organization {
/// // Type of Organization::identity::id and Project::organization_id
/// type CollectionId = uuid::Uuid;
///
/// type GenerationNumberColumn = organization::dsl::rcgen;
/// type CollectionTimeDeletedColumn = organization::dsl::time_deleted;
///
/// type CollectionIdColumn = project::dsl::organization_id;
/// }
/// ```
pub trait DatastoreCollectionConfig<ResourceType> {
/// The Rust type of the collection id (typically Uuid for us)
type CollectionId: Copy + Debug;

/// The column in the CollectionTable that acts as a generation number.
/// This is the "child-resource-generation-number" in RFD 192.
type GenerationNumberColumn: Column + Default;

/// The time deleted column in the CollectionTable
// We enforce that this column comes from the same table as
// GenerationNumberColumn when defining insert_resource() below.
type CollectionTimeDeletedColumn: Column + Default;

/// The column in the ResourceTable that acts as a foreign key into
/// the CollectionTable
type CollectionIdColumn: Column;
}

/// Trait to be implemented by structs representing an attachable collection.
///
/// For example, since Instances have a one-to-many relationship with
/// Disks, the Instance datatype should implement this trait.
/// ```
/// # use diesel::prelude::*;
/// # use nexus_db_model::DatastoreAttachTargetConfig;
/// #
/// # table! {
/// # test_schema.instance (id) {
/// # id -> Uuid,
/// # time_deleted -> Nullable<Timestamptz>,
/// # }
/// # }
/// #
/// # table! {
/// # test_schema.disk (id) {
/// # id -> Uuid,
/// # time_deleted -> Nullable<Timestamptz>,
/// # instance_id -> Nullable<Uuid>,
/// # }
/// # }
///
/// #[derive(Queryable, Debug, Selectable)]
/// #[diesel(table_name = disk)]
/// struct Disk {
/// pub id: uuid::Uuid,
/// pub time_deleted: Option<chrono::DateTime<chrono::Utc>>,
/// pub instance_id: Option<uuid::Uuid>,
/// }
///
/// #[derive(Queryable, Debug, Selectable)]
/// #[diesel(table_name = instance)]
/// struct Instance {
/// pub id: uuid::Uuid,
/// pub time_deleted: Option<chrono::DateTime<chrono::Utc>>,
/// }
///
/// impl DatastoreAttachTargetConfig<Disk> for Instance {
/// // Type of instance::id and disk::id.
/// type Id = uuid::Uuid;
///
/// type CollectionIdColumn = instance::dsl::id;
/// type CollectionTimeDeletedColumn = instance::dsl::time_deleted;
///
/// type ResourceIdColumn = disk::dsl::id;
/// type ResourceCollectionIdColumn = disk::dsl::instance_id;
/// type ResourceTimeDeletedColumn = disk::dsl::time_deleted;
/// }
/// ```
pub trait DatastoreAttachTargetConfig<ResourceType>:
Selectable<Pg> + Sized
{
/// The Rust type of the collection and resource ids (typically Uuid).
type Id: Copy + Debug + PartialEq + Send + 'static;

/// The primary key column of the collection.
type CollectionIdColumn: Column;

/// The time deleted column in the CollectionTable
type CollectionTimeDeletedColumn: Column<Table = <Self::CollectionIdColumn as Column>::Table>
+ Default
+ ExpressionMethods;

/// The primary key column of the resource
type ResourceIdColumn: Column;

/// The column in the resource acting as a foreign key into the Collection
type ResourceCollectionIdColumn: Column<Table = <Self::ResourceIdColumn as Column>::Table>
+ Default
+ ExpressionMethods;

/// The time deleted column in the ResourceTable
type ResourceTimeDeletedColumn: Column<Table = <Self::ResourceIdColumn as Column>::Table>
+ Default
+ ExpressionMethods;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use crate::db::schema::console_session;
use crate::schema::console_session;
use chrono::{DateTime, Utc};
use uuid::Uuid;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use super::{DatasetKind, Generation, Region, SqlU16};
use crate::db::collection_insert::DatastoreCollection;
use crate::db::schema::{dataset, region};
use crate::collection::DatastoreCollectionConfig;
use crate::schema::{dataset, region};
use chrono::{DateTime, Utc};
use db_macros::Asset;
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -75,7 +75,7 @@ impl Dataset {
}

// Datasets contain regions
impl DatastoreCollection<Region> for Dataset {
impl DatastoreCollectionConfig<Region> for Dataset {
type CollectionId = Uuid;
type GenerationNumberColumn = dataset::dsl::rcgen;
type CollectionTimeDeletedColumn = dataset::dsl::time_deleted;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use super::impl_enum_type;
use crate::internal_api;
use nexus_types::internal_api;
use serde::{Deserialize, Serialize};

impl_enum_type!(
Expand Down
Loading

0 comments on commit 5e835f1

Please sign in to comment.