use crate::generator::{Generator, GeneratorKind};
#[cfg(any(feature = "sqlite", feature = "postgres"))]
use drizzle_core::{Relation, SQLColumn, SQLColumnInfo};
use drizzle_core::{SQLSchemaImpl, SQLTableInfo, SchemaHasTable, TableRef};
use std::collections::{HashMap, HashSet};
use std::marker::PhantomData;
use std::sync::Arc;
#[cfg(feature = "sqlite")]
use crate::Sqlite;
#[cfg(feature = "sqlite")]
use drizzle_sqlite::traits::SQLiteColumn;
#[cfg(feature = "sqlite")]
use drizzle_sqlite::traits::SQLiteTable;
#[cfg(feature = "sqlite")]
use drizzle_sqlite::values::SQLiteValue;
#[cfg(feature = "postgres")]
use crate::Postgres;
#[cfg(feature = "postgres")]
use drizzle_postgres::traits::PostgresColumn;
#[cfg(feature = "postgres")]
use drizzle_postgres::traits::PostgresTable;
#[cfg(feature = "postgres")]
use drizzle_postgres::values::PostgresValue;
pub struct SeedConfig<'a, D, S> {
pub(crate) schema: &'a S,
pub(crate) skipped_tables: HashSet<&'static str>,
pub(crate) seed: u64,
pub(crate) default_count: usize,
pub(crate) table_counts: HashMap<&'static str, usize>,
pub(crate) column_generators: HashMap<(&'static str, &'static str), Arc<dyn Generator>>,
pub(crate) column_kinds: HashMap<(&'static str, &'static str), GeneratorKind>,
pub(crate) relation_counts: HashMap<(&'static str, &'static str), usize>,
pub(crate) max_params_per_batch: Option<usize>,
_dialect: PhantomData<D>,
_schema: PhantomData<&'a S>,
}
impl<'a, D, S> SeedConfig<'a, D, S> {
fn with_defaults(schema: &'a S) -> Self {
Self {
schema,
skipped_tables: HashSet::new(),
seed: 0,
default_count: 10,
table_counts: HashMap::new(),
column_generators: HashMap::new(),
column_kinds: HashMap::new(),
relation_counts: HashMap::new(),
max_params_per_batch: None,
_dialect: PhantomData,
_schema: PhantomData,
}
}
#[must_use]
pub const fn seed(mut self, seed: u64) -> Self {
self.seed = seed;
self
}
#[must_use]
pub const fn default_count(mut self, count: usize) -> Self {
self.default_count = count;
self
}
#[must_use]
pub fn max_params(mut self, limit: usize) -> Self {
assert!(limit > 0, "max_params must be > 0");
self.max_params_per_batch = Some(limit);
self
}
pub(crate) fn count_for(&self, table: &str) -> usize {
self.table_counts
.get(table)
.copied()
.unwrap_or(self.default_count)
}
}
impl<D, S> SeedConfig<'_, D, S>
where
S: SQLSchemaImpl,
{
pub(crate) fn active_tables(&self) -> Vec<&'static TableRef> {
self.schema
.table_refs()
.iter()
.copied()
.filter(|t| !self.skipped_tables.contains(t.name))
.collect()
}
}
impl<D, S> SeedConfig<'_, D, S> {
#[must_use]
pub fn skip<T>(mut self, table: &T) -> Self
where
T: SQLTableInfo,
S: SchemaHasTable<T>,
{
self.skipped_tables.insert(table.name());
self
}
}
#[cfg(feature = "sqlite")]
impl<'a> SeedConfig<'a, Sqlite, ()> {
pub fn sqlite<Schema>(schema: &'a Schema) -> SeedConfig<'a, Sqlite, Schema>
where
Schema: SQLSchemaImpl,
{
SeedConfig::<'a, Sqlite, Schema>::with_defaults(schema)
}
}
#[cfg(feature = "sqlite")]
impl<S> SeedConfig<'_, Sqlite, S>
where
S: SQLSchemaImpl,
{
#[must_use]
pub fn count<T>(mut self, table: &T, count: usize) -> Self
where
T: SQLTableInfo,
S: SchemaHasTable<T>,
{
self.table_counts.insert(table.name(), count);
self
}
#[must_use]
pub fn relation<P, C>(mut self, parent: &P, child: &C, count: usize) -> Self
where
P: SQLTableInfo + SQLiteTable<'static>,
C: SQLTableInfo + SQLiteTable<'static> + Relation<P>,
S: SchemaHasTable<P> + SchemaHasTable<C>,
{
self.relation_counts
.insert((parent.name(), child.name()), count);
self
}
#[must_use]
pub fn kind<C>(mut self, column: &C, kind: GeneratorKind) -> Self
where
C: SQLColumnInfo + SQLiteColumn<'static>,
S: SchemaHasTable<<C as SQLColumn<'static, SQLiteValue<'static>>>::Table>,
{
let key = (column.table().name(), column.name());
self.column_kinds.insert(key, kind);
self
}
#[must_use]
pub fn generator<C>(mut self, column: &C, g: impl Generator + 'static) -> Self
where
C: SQLColumnInfo + SQLiteColumn<'static>,
S: SchemaHasTable<<C as SQLColumn<'static, SQLiteValue<'static>>>::Table>,
{
let key = (column.table().name(), column.name());
self.column_generators.insert(key, Arc::new(g));
self
}
#[must_use]
pub fn generate(&self) -> Vec<crate::SQLiteSeedStatement> {
crate::Seeder::new(self).generate_sqlite()
}
}
#[cfg(feature = "postgres")]
impl<'a> SeedConfig<'a, Postgres, ()> {
pub fn postgres<Schema>(schema: &'a Schema) -> SeedConfig<'a, Postgres, Schema>
where
Schema: SQLSchemaImpl,
{
SeedConfig::<'a, Postgres, Schema>::with_defaults(schema)
}
}
#[cfg(feature = "postgres")]
impl<S> SeedConfig<'_, Postgres, S>
where
S: SQLSchemaImpl,
{
#[must_use]
pub fn count<T>(mut self, table: &T, count: usize) -> Self
where
T: SQLTableInfo,
S: SchemaHasTable<T>,
{
self.table_counts.insert(table.name(), count);
self
}
#[must_use]
pub fn relation<P, C>(mut self, parent: &P, child: &C, count: usize) -> Self
where
P: SQLTableInfo + PostgresTable<'static>,
C: SQLTableInfo + PostgresTable<'static> + Relation<P>,
S: SchemaHasTable<P> + SchemaHasTable<C>,
{
self.relation_counts
.insert((parent.name(), child.name()), count);
self
}
#[must_use]
pub fn kind<C>(mut self, column: &C, kind: GeneratorKind) -> Self
where
C: SQLColumnInfo + PostgresColumn<'static>,
S: SchemaHasTable<<C as SQLColumn<'static, PostgresValue<'static>>>::Table>,
{
let key = (column.table().name(), column.name());
self.column_kinds.insert(key, kind);
self
}
#[must_use]
pub fn generator<C>(mut self, column: &C, g: impl Generator + 'static) -> Self
where
C: SQLColumnInfo + PostgresColumn<'static>,
S: SchemaHasTable<<C as SQLColumn<'static, PostgresValue<'static>>>::Table>,
{
let key = (column.table().name(), column.name());
self.column_generators.insert(key, Arc::new(g));
self
}
#[must_use]
pub fn generate(&self) -> Vec<crate::PostgresSeedStatement> {
crate::Seeder::new(self).generate_postgres()
}
}