Skip to content

Typesafe primary keys #3472

@drdozer

Description

@drdozer

As it stands, we choose a type for primary keys from a closed set of possibilities, e.g. u32. This makes foreign keys non-typesafe.

#[table(name = foo, public)]
struct Foo {
  #[primary_key],
  #[auto_inc],
  pub id: u32,
}

#[table(name = bar, public)]
struct Bar {
  pub foo_id: u32;
}

This prevents the compiler from preventing mistakes where a u32 that did not come from a Foo.id is used as a value for Bar.foo_id. I did try to manually implement something, but it seems some of the traits needed to make this work aren't accessible to mortals. My proposal is something like this:

#[table(name = foo, public)]
struct Foo {
  #[primary_key(key_type=u32],
  #[auto_inc],
  pub id: Foo::ID,
}

#[table(name = bar, public)]
struct Bar {
  #[derive(Default)]
  pub foo_id: Foo::ID;
}

This would generate:

mod Foo {
struct ID(u32);

... glue to box/unbox u32 through the SpacetimeType, Filterable, and other required machinery
}

The semantics would be that if a key_type is provided to primary_key, it must be a single-member tuple struct where the contained value is itself valid as a primary key type. The Default value would always be the "not set" flag value, to be replaced in an auto_inc field. The wrapping ID type would not appear in the wire protocol and probably not in the schema, but it may be glued back in for the client facades.

I hope I didn't fumble the rust snippets - I haven't run this through an IDE first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions