Skip to content

Commit

Permalink
onConflict intospection working
Browse files Browse the repository at this point in the history
  • Loading branch information
olirice committed May 10, 2024
1 parent 561ae3a commit 4708590
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 45 deletions.
111 changes: 67 additions & 44 deletions src/graphql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1112,6 +1112,7 @@ pub enum EnumSource {
Enum(Arc<Enum>),
FilterIs,
TableColumns(Arc<Table>),
OnConflictTarget(Arc<Table>),
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
Expand Down Expand Up @@ -1429,40 +1430,43 @@ impl ___Type for MutationType {
let table_base_type_name = self.schema.graphql_table_base_type_name(table);

if self.schema.graphql_table_insert_types_are_valid(table) {
let mut args = vec![__InputValue {
name_: "objects".to_string(),
type_: __Type::NonNull(NonNullType {
type_: Box::new(__Type::List(ListType {
type_: Box::new(__Type::NonNull(NonNullType {
type_: Box::new(__Type::InsertInput(InsertInputType {
table: Arc::clone(table),
schema: Arc::clone(&self.schema),
})),
})),
})),
}),
description: None,
default_value: None,
sql_type: None,
}];

if table.has_upsert_support() {
args.push(__InputValue {
name_: "onConflict".to_string(),
type_: __Type::InsertOnConflictInput(InsertOnConflictType {
table: Arc::clone(table),
schema: Arc::clone(&self.schema),
}),
description: None,
default_value: None,
sql_type: None,
});
}

f.push(__Field {
name_: format!("insertInto{}Collection", table_base_type_name),
type_: __Type::InsertResponse(InsertResponseType {
table: Arc::clone(table),
schema: Arc::clone(&self.schema),
}),
args: vec![
__InputValue {
name_: "objects".to_string(),
type_: __Type::NonNull(NonNullType {
type_: Box::new(__Type::List(ListType {
type_: Box::new(__Type::NonNull(NonNullType {
type_: Box::new(__Type::InsertInput(InsertInputType {
table: Arc::clone(table),
schema: Arc::clone(&self.schema),
})),
})),
})),
}),
description: None,
default_value: None,
sql_type: None,
},
__InputValue {
name_: "onConflict".to_string(),
type_: __Type::InsertOnConflictInput(InsertOnConflictType {
table: Arc::clone(table),
schema: Arc::clone(&self.schema),
}),
description: None,
default_value: None,
sql_type: None,
},
],
args,
description: Some(format!(
"Adds one or more `{}` records to the collection",
table_base_type_name
Expand Down Expand Up @@ -1654,6 +1658,10 @@ impl ___Type for EnumType {
"{}Field",
self.schema.graphql_table_base_type_name(&table)
)),
EnumSource::OnConflictTarget(table) => Some(format!(
"{}OnConflictConstraint",
self.schema.graphql_table_base_type_name(&table)
)),
}
}

Expand Down Expand Up @@ -1703,6 +1711,18 @@ impl ___Type for EnumType {
deprecation_reason: None,
})
.collect(),
EnumSource::OnConflictTarget(table) => {
table
.on_conflict_indexes()
.iter()
.map(|ix| __EnumValue {
// TODO, apply name restrictions
name: ix.name.clone(),
description: None,
deprecation_reason: None,
})
.collect()
}
})
}
}
Expand Down Expand Up @@ -3159,13 +3179,9 @@ impl ___Type for InsertOnConflictType {
// If triggers are involved, we can't detect if a field is non-null. Default
// all fields to non-null and let postgres errors handle it.
type_: __Type::NonNull(NonNullType {
type_: Box::new(__Type::List(ListType {
type_: Box::new(__Type::NonNull(NonNullType {
type_: Box::new(__Type::Enum(EnumType {
enum_: EnumSource::TableColumns(Arc::clone(&self.table)),
schema: Arc::clone(&self.schema),
})),
})),
type_: Box::new(__Type::Enum(EnumType {
enum_: EnumSource::OnConflictTarget(Arc::clone(&self.table)),
schema: Arc::clone(&self.schema),
})),
}),
description: Some(
Expand Down Expand Up @@ -4141,15 +4157,22 @@ impl __Schema {
table: Arc::clone(table),
schema: Arc::clone(&schema_rc),
}));
// Used by on conflict
types_.push(__Type::Enum(EnumType {
enum_: EnumSource::TableColumns(Arc::clone(table)),
schema: Arc::clone(&schema_rc),
}));
types_.push(__Type::InsertOnConflictInput(InsertOnConflictType {
table: Arc::clone(table),
schema: Arc::clone(&schema_rc),
}));

// Used exclusively by onConflict
if table.has_upsert_support() {
types_.push(__Type::InsertOnConflictInput(InsertOnConflictType {
table: Arc::clone(table),
schema: Arc::clone(&schema_rc),
}));
types_.push(__Type::Enum(EnumType {
enum_: EnumSource::TableColumns(Arc::clone(table)),
schema: Arc::clone(&schema_rc),
}));
types_.push(__Type::Enum(EnumType {
enum_: EnumSource::OnConflictTarget(Arc::clone(table)),
schema: Arc::clone(&schema_rc),
}));
}
}

if self.graphql_table_update_types_are_valid(table) {
Expand Down
1 change: 1 addition & 0 deletions src/parser_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ pub fn validate_arg_from_type(type_: &__Type, value: &gson::Value) -> Result<gso
EnumSource::FilterIs => value.clone(),
// TODO(or): Do I need to check directives here?
EnumSource::TableColumns(_e) => value.clone(),
EnumSource::OnConflictTarget(_e) => value.clone(),
}
}
None => return Err(format!("Invalid input for {} type", enum_name)),
Expand Down
31 changes: 30 additions & 1 deletion src/sql_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -531,14 +531,39 @@ impl Table {
column_names: column_names.clone(),
is_unique: true,
is_primary_key: true,
name: "dummy".to_string(),
name: "NOT REQUIRED".to_string(),
})
}
} else {
None
}
}

pub fn on_conflict_indexes(&self) -> Vec<&Index> {
// Indexes that are valid targets for an on conflict clause
// must be unique, real (not comment directives), and must
// not contain serial or generated columns because we don't
// allow those to be set in insert statements
let unique_indexes = self.indexes.iter().filter(|x| x.is_unique);

let allowed_column_names = self
.columns
.iter()
.filter(|x| x.permissions.is_insertable)
.filter(|x| !x.is_generated)
.filter(|x| !x.is_serial)
.map(|x| &x.name)
.collect::<HashSet<&String>>();

unique_indexes
.filter(|uix| {
uix.column_names
.iter()
.all(|col_name| allowed_column_names.contains(col_name))
})
.collect::<Vec<&Index>>()
}

pub fn primary_key_columns(&self) -> Vec<&Arc<Column>> {
self.primary_key()
.map(|x| x.column_names)
Expand All @@ -553,6 +578,10 @@ impl Table {
.collect::<Vec<&Arc<Column>>>()
}

pub fn has_upsert_support(&self) -> bool {
self.on_conflict_indexes().len() > 0
}

pub fn is_any_column_selectable(&self) -> bool {
self.columns.iter().any(|x| x.permissions.is_selectable)
}
Expand Down

0 comments on commit 4708590

Please sign in to comment.