Organizing Enum Dependent on Another Enum

Trying to wrap my head around organizing my data structures for a particular problem. I am building a search tool that should work across multiple databases. Each database has well defined searchable fields, but these fields are unique to each database. I'd like my search query to have a field for the database and the query term. How can I ensure that only appropriate fields are allowed in the database?

enum DataBase {
    Foo,
    Bar
}

enum FooFields<'a> {
   FooField1(&'a str),
   FooField2(&'a str)
}

enum BarFields<'a> {
    BarField1(&'a str),
    BarField2(&'a str)
}

struct Query<'a> {
    db: DataBase,
    term: ??? // Needs to only allow relevant fields depending upon db value.
}

I would write Query as:

enum Query<'a> {
    Foo {
        term: FooFields<'a>,
    },
    Bar {
        term: BarFields<'a>,
    },
}
1 Like
enum DataBase {
    Foo {fields: FooFields, db: Foo}
    Bar {fields: BarFields, db: Bar}
}

or

trait DatabaseTrait {
   type Fields;
}

struct Database<D: DatabaseTrait> {
    fields: D::Fields,
    db: D,
}
1 Like

@dtolnay this should do the trick but I'd like to be able to implement some functions for the Query struct, which I don't know how to do if it's just an enum.

@kornel can you expand on the second option you gave? For instance, how are the various fields then defined?

The same way as you proposed. The trait is just used to make an association between a database type and its related fields type.

If you want to stick to enums, I like @dtolnay’s suggestion.

If you want something more generic, here’s a similar approach to @kornel’s second option:

trait Db {}

trait Field {
    type Db: Db;
}

struct Foo;
impl Db for Foo {}

struct Bar;
impl Db for Bar {}

struct FooField1<'a>(&'a str);
struct FooField2;

impl<'a> Field for FooField1<'a> {
    type Db = Foo;
}

impl Field for FooField2 {
    type Db = Foo;
}

struct Query<F: Field> {
    db: F::Db,
    term: F,
}

fn main() {
    let q = Query {
        db: Foo,
        term: FooField1("field1"),
    };
}
1 Like