Last active
June 18, 2017 16:35
-
-
Save YetAnotherMinion/4d6d9207182848b9ef297c26b269a3f0 to your computer and use it in GitHub Desktop.
Composite Foreign Key implementation attempt with Diesel
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#[macro_use] | |
extern crate diesel; | |
#[macro_use] | |
extern crate diesel_codegen; | |
table! { | |
table_a (tennant_id, part_number) { | |
tennant_id -> Int8, | |
part_number -> Int8, | |
} | |
} | |
table! { | |
table_b (id) { | |
id -> Int8, | |
foo_tennant_id -> Int8, | |
foo_part_number -> Int8, | |
order_quantity -> Int8, | |
} | |
} | |
#[derive(Queryable, Insertable, Identifiable)] | |
#[table_name = "table_a"] | |
#[primary_key(tennant_id, part_number)] | |
pub struct TableA { | |
pub tennant_id : i64, | |
pub part_number : i64, | |
} | |
impl diesel::JoinTo<table_b::table> for table_a::table { | |
type JoinOnClause = | |
diesel::expression::helper_types::Eq< | |
diesel::expression::nullable::Nullable<(table_b::foo_tennant_id, table_b::foo_part_number)>, | |
diesel::expression::nullable::Nullable< | |
<table_a::table as diesel::query_source::Table>::PrimaryKey> | |
>; | |
fn join_on_clause() -> Self::JoinOnClause { | |
use diesel::ExpressionMethods; | |
// original code: | |
// table_b::foo_tennant_id.nullable().eq(diesel::Table::primary_key(&table_a::table).nullable()) | |
(table_b::columns::foo_tennant_id, table_b::columns::foo_part_number).nullable().eq(diesel::Table::primary_key(&table_a::table).nullable()) | |
} | |
} | |
#[derive(Identifiable)] | |
#[table_name = "table_b"] | |
#[primary_key(id)] | |
pub struct TableB { | |
pub id : i64, | |
pub foo_tennant_id : i64, | |
pub foo_part_number : i64, | |
pub order_quantity : i64, | |
// storage for computed foreign key required because foreign_key() returns | |
// a reference to a field on the struct | |
pub parent_id : (i64, i64), | |
} | |
impl <__DB, __ST> diesel::Queryable<__ST, __DB> for TableB where | |
__DB: diesel::backend::Backend + diesel::types::HasSqlType<__ST>, | |
(i64, i64, i64, i64): diesel::types::FromSqlRow<__ST, __DB> | |
{ | |
type Row = (i64, i64, i64, i64); | |
fn build((id, foo_tennant_id, foo_part_number, order_quantity): | |
Self::Row) -> Self { | |
TableB{id: id, | |
foo_tennant_id: foo_tennant_id, | |
foo_part_number: foo_part_number, | |
order_quantity: order_quantity, | |
parent_id : (foo_tennant_id, foo_part_number),} | |
} | |
} | |
use diesel::insertable::{ColumnInsertValue}; | |
use diesel::expression::helper_types::AsNullableExpr; | |
type TableBRow<'insert> = | |
(ColumnInsertValue<table_b::id, AsNullableExpr<&'insert i64, table_b::id>>, | |
ColumnInsertValue<table_b::foo_tennant_id, AsNullableExpr<&'insert i64, table_b::foo_tennant_id>>, | |
ColumnInsertValue<table_b::foo_part_number, AsNullableExpr<&'insert i64, table_b::foo_part_number>>, | |
ColumnInsertValue<table_b::order_quantity, AsNullableExpr<&'insert i64, table_b::order_quantity>>); | |
impl <'insert, DB> diesel::insertable::Insertable<table_b::table, DB> for | |
&'insert TableB where DB: diesel::backend::Backend, TableBRow<'insert> : diesel::insertable::InsertValues<DB> | |
{ | |
type Values = TableBRow<'insert>; | |
#[allow(non_shorthand_field_patterns)] | |
fn values(self) -> Self::Values { | |
use diesel::expression::{AsExpression, Expression}; | |
use diesel::insertable::ColumnInsertValue; | |
use diesel::types::IntoNullable; | |
let TableB { | |
id: ref id, | |
foo_tennant_id: ref foo_tennant_id, | |
foo_part_number: ref foo_part_number, | |
order_quantity: ref order_quantity, | |
parent_id : (_, _ ) } = *self; | |
(ColumnInsertValue::Expression(table_b::id, | |
AsExpression::<<<table_b::id as | |
Expression>::SqlType as | |
IntoNullable>::Nullable>::as_expression(id)), | |
ColumnInsertValue::Expression(table_b::foo_tennant_id, | |
AsExpression::<<<table_b::foo_tennant_id | |
as Expression>::SqlType | |
as | |
IntoNullable>::Nullable>::as_expression(foo_tennant_id)), | |
ColumnInsertValue::Expression(table_b::foo_part_number, | |
AsExpression::<<<table_b::foo_part_number | |
as Expression>::SqlType | |
as | |
IntoNullable>::Nullable>::as_expression(foo_part_number)), | |
ColumnInsertValue::Expression(table_b::order_quantity, | |
AsExpression::<<<table_b::order_quantity | |
as Expression>::SqlType | |
as | |
IntoNullable>::Nullable>::as_expression(order_quantity))) | |
} | |
} | |
pub struct FakeForeignKey((table_b::columns::foo_tennant_id, table_b::columns::foo_part_number)); | |
impl diesel::Column for FakeForeignKey { | |
type Table = table_b::table; | |
fn name() -> &'static str { "my_foreign_key" } | |
} | |
impl diesel::Expression for FakeForeignKey { | |
type SqlType = (diesel::types::Int8, diesel::types::Int8); | |
} | |
impl diesel::associations::BelongsTo<TableA> for TableB { | |
type ForeignKey = (i64, i64); | |
type ForeignKeyColumn = FakeForeignKey; //(table_b::columns::foo_tennant_id, table_b::columns::foo_part_number); | |
fn foreign_key(&self) -> Option<&Self::ForeignKey> { | |
Some(&self.parent_id) | |
} | |
fn foreign_key_column() -> Self::ForeignKeyColumn { | |
FakeForeignKey((table_b::columns::foo_tennant_id, table_b::columns::foo_part_number)) | |
} | |
} | |
fn main() { | |
println!("Hello, world!"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment