fix(widgets): add multi-database compatibility to all dashboard widgets
Replace SQLite-specific functions with database-agnostic expressions to support MySQL, SQLite, PostgreSQL, and SQL Server across all Filament dashboard widgets. - Fix strftime() date formatting in SubscriptionMetrics, RevenueMetrics, and TrialPerformance - Fix CAST AS REAL syntax in ChurnAnalysis widget - Add getDateFormatExpression() method for date function compatibility - Add getCastExpression() method for CAST syntax compatibility - Support MySQL/MariaDB, SQLite, PostgreSQL, and SQL Server drivers - Maintain identical functionality across all database types Fixes multiple SQLSTATE[42000] syntax errors when using MySQL/MariaDB databases.
This commit is contained in:
@@ -112,12 +112,14 @@ class ChurnAnalysis extends ChartWidget
|
||||
|
||||
private function getChurnByProvider(): array
|
||||
{
|
||||
$castExpression = $this->getCastExpression();
|
||||
|
||||
return Subscription::query()
|
||||
->select(
|
||||
'provider',
|
||||
DB::raw('COUNT(CASE WHEN status = "cancelled" THEN 1 END) as cancelled'),
|
||||
DB::raw('COUNT(*) as total'),
|
||||
DB::raw('(CAST(COUNT(CASE WHEN status = "cancelled" THEN 1 END) AS REAL) * 100.0 / COUNT(*)) as churn_rate')
|
||||
DB::raw("({$castExpression} * 100.0 / COUNT(*)) as churn_rate")
|
||||
)
|
||||
->groupBy('provider')
|
||||
->orderBy('churn_rate', 'desc')
|
||||
@@ -130,12 +132,14 @@ class ChurnAnalysis extends ChartWidget
|
||||
|
||||
private function getChurnByPlan(): array
|
||||
{
|
||||
$castExpression = $this->getCastExpression();
|
||||
|
||||
return Subscription::query()
|
||||
->select(
|
||||
'plans.name as plan_name',
|
||||
DB::raw('COUNT(CASE WHEN subscriptions.status = "cancelled" THEN 1 END) as cancelled'),
|
||||
DB::raw('COUNT(*) as total'),
|
||||
DB::raw('(CAST(COUNT(CASE WHEN subscriptions.status = "cancelled" THEN 1 END) AS REAL) * 100.0 / COUNT(*)) as churn_rate')
|
||||
DB::raw("({$castExpression} * 100.0 / COUNT(*)) as churn_rate")
|
||||
)
|
||||
->join('plans', 'subscriptions.plan_id', '=', 'plans.id')
|
||||
->groupBy('plans.id', 'plans.name')
|
||||
@@ -147,4 +151,17 @@ class ChurnAnalysis extends ChartWidget
|
||||
})
|
||||
->toArray();
|
||||
}
|
||||
|
||||
private function getCastExpression(): string
|
||||
{
|
||||
$connection = DB::connection()->getDriverName();
|
||||
|
||||
return match ($connection) {
|
||||
'sqlite' => 'CAST(COUNT(CASE WHEN status = "cancelled" THEN 1 END) AS REAL)',
|
||||
'mysql', 'mariadb' => 'CAST(COUNT(CASE WHEN status = "cancelled" THEN 1 END) AS DECIMAL(10,2))',
|
||||
'pgsql' => 'CAST(COUNT(CASE WHEN status = "cancelled" THEN 1 END) AS NUMERIC)',
|
||||
'sqlsrv' => 'CAST(COUNT(CASE WHEN status = "cancelled" THEN 1 END) AS FLOAT)',
|
||||
default => 'CAST(COUNT(CASE WHEN status = "cancelled" THEN 1 END) AS DECIMAL(10,2))', // fallback to MySQL format
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,9 +92,11 @@ class RevenueMetrics extends ChartWidget
|
||||
|
||||
private function getMonthlyRevenueTrend(): array
|
||||
{
|
||||
$dateFormat = $this->getDateFormatExpression();
|
||||
|
||||
return Subscription::query()
|
||||
->select(
|
||||
DB::raw("strftime('%Y-%m', subscriptions.created_at) as month"),
|
||||
DB::raw("{$dateFormat} as month"),
|
||||
DB::raw('SUM(plans.price) as revenue')
|
||||
)
|
||||
->join('plans', 'subscriptions.plan_id', '=', 'plans.id')
|
||||
@@ -106,6 +108,19 @@ class RevenueMetrics extends ChartWidget
|
||||
->toArray();
|
||||
}
|
||||
|
||||
private function getDateFormatExpression(): string
|
||||
{
|
||||
$connection = DB::connection()->getDriverName();
|
||||
|
||||
return match ($connection) {
|
||||
'sqlite' => "strftime('%Y-%m', subscriptions.created_at)",
|
||||
'mysql', 'mariadb' => "DATE_FORMAT(subscriptions.created_at, '%Y-%m')",
|
||||
'pgsql' => "TO_CHAR(subscriptions.created_at, 'YYYY-MM')",
|
||||
'sqlsrv' => "FORMAT(subscriptions.created_at, 'yyyy-MM')",
|
||||
default => "DATE_FORMAT(subscriptions.created_at, '%Y-%m')", // fallback to MySQL format
|
||||
};
|
||||
}
|
||||
|
||||
private function getMRRByProvider(): array
|
||||
{
|
||||
return Subscription::query()
|
||||
|
||||
@@ -113,9 +113,11 @@ class SubscriptionMetrics extends ChartWidget
|
||||
|
||||
private function getMonthlySubscriptionTrend(): array
|
||||
{
|
||||
$dateFormat = $this->getDateFormatExpression();
|
||||
|
||||
return Subscription::query()
|
||||
->select(
|
||||
DB::raw("strftime('%Y-%m', subscriptions.created_at) as month"),
|
||||
DB::raw("{$dateFormat} as month"),
|
||||
DB::raw('count(*) as count')
|
||||
)
|
||||
->groupBy('month')
|
||||
@@ -123,4 +125,17 @@ class SubscriptionMetrics extends ChartWidget
|
||||
->pluck('count', 'month')
|
||||
->toArray();
|
||||
}
|
||||
|
||||
private function getDateFormatExpression(): string
|
||||
{
|
||||
$connection = DB::connection()->getDriverName();
|
||||
|
||||
return match ($connection) {
|
||||
'sqlite' => "strftime('%Y-%m', subscriptions.created_at)",
|
||||
'mysql', 'mariadb' => "DATE_FORMAT(subscriptions.created_at, '%Y-%m')",
|
||||
'pgsql' => "TO_CHAR(subscriptions.created_at, 'YYYY-MM')",
|
||||
'sqlsrv' => "FORMAT(subscriptions.created_at, 'yyyy-MM')",
|
||||
default => "DATE_FORMAT(subscriptions.created_at, '%Y-%m')", // fallback to MySQL format
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,9 +134,11 @@ class TrialPerformance extends ChartWidget
|
||||
|
||||
private function getTrialExtensionsTrend(): array
|
||||
{
|
||||
$dateFormat = $this->getDateFormatExpression();
|
||||
|
||||
return TrialExtension::query()
|
||||
->select(
|
||||
DB::raw("strftime('%Y-%m', trial_extensions.granted_at) as month"),
|
||||
DB::raw("{$dateFormat} as month"),
|
||||
DB::raw('COUNT(*) as extensions'),
|
||||
DB::raw('SUM(extension_days) as total_days')
|
||||
)
|
||||
@@ -152,6 +154,19 @@ class TrialPerformance extends ChartWidget
|
||||
->toArray();
|
||||
}
|
||||
|
||||
private function getDateFormatExpression(): string
|
||||
{
|
||||
$connection = DB::connection()->getDriverName();
|
||||
|
||||
return match ($connection) {
|
||||
'sqlite' => "strftime('%Y-%m', trial_extensions.granted_at)",
|
||||
'mysql', 'mariadb' => "DATE_FORMAT(trial_extensions.granted_at, '%Y-%m')",
|
||||
'pgsql' => "TO_CHAR(trial_extensions.granted_at, 'YYYY-MM')",
|
||||
'sqlsrv' => "FORMAT(trial_extensions.granted_at, 'yyyy-MM')",
|
||||
default => "DATE_FORMAT(trial_extensions.granted_at, '%Y-%m')", // fallback to MySQL format
|
||||
};
|
||||
}
|
||||
|
||||
private function getAverageTrialLength(): float
|
||||
{
|
||||
return Subscription::query()
|
||||
|
||||
Reference in New Issue
Block a user