diff --git a/packages/jao/lib/src/db/adapters/sqlite.dart b/packages/jao/lib/src/db/adapters/sqlite.dart index 98a6e0b..48ee8bd 100644 --- a/packages/jao/lib/src/db/adapters/sqlite.dart +++ b/packages/jao/lib/src/db/adapters/sqlite.dart @@ -7,6 +7,7 @@ library; import 'dart:async'; import 'dart:io'; import 'package:sqlite3/sqlite3.dart' as sqlite; +import '../../migrations/operations.dart' show sqlDefault; import '../../migrations/schema.dart' show ForeignKeyDefinition, OnDeleteAction; import '../connection.dart'; @@ -703,7 +704,7 @@ List generateTableRecreationSql({ buffer.write(' NOT NULL'); } if (defaultValue != null) { - buffer.write(' DEFAULT $defaultValue'); + buffer.write(' DEFAULT ${sqlDefault(defaultValue)}'); } } diff --git a/packages/jao/lib/src/fields/field_def.dart b/packages/jao/lib/src/fields/field_def.dart index a49a0d5..a19127b 100644 --- a/packages/jao/lib/src/fields/field_def.dart +++ b/packages/jao/lib/src/fields/field_def.dart @@ -311,8 +311,6 @@ class EnumField extends Field { }); } -// === Primary Key === - /// Auto-incrementing primary key @immutable class AutoField extends Field { @@ -331,8 +329,6 @@ class UuidPrimaryKey extends UuidField { const UuidPrimaryKey({super.column}) : super(autoGenerate: true, nullable: false, unique: true); } -// === Relationships === - /// Foreign key relationship @immutable class ForeignKey extends Field { diff --git a/packages/jao/lib/src/fields/field_ref.dart b/packages/jao/lib/src/fields/field_ref.dart index 1842a92..9c92d7f 100644 --- a/packages/jao/lib/src/fields/field_ref.dart +++ b/packages/jao/lib/src/fields/field_ref.dart @@ -24,8 +24,6 @@ abstract class FieldRef { /// Get the column reference expression ColumnRef get col => ColumnRef(name, table: table ?? ''); - // === Common lookups available on all fields === - /// Exact match: field = value Q eq(T value) => Q(Comparison(col, ComparisonOp.eq, Value(value))); @@ -41,16 +39,12 @@ abstract class FieldRef { /// In list: field IN (values) Q inList(List values) => Q(Comparison(col, ComparisonOp.inList, Value(values))); - // === Ordering === - /// Order ascending OrderBy asc() => OrderBy(col, ascending: true); /// Order descending OrderBy desc() => OrderBy(col, ascending: false); - // === F-expression comparison === - /// Compare with another field Q eqField(FieldRef other) => Q(Comparison(col, ComparisonOp.eq, other.col)); @@ -125,8 +119,6 @@ abstract class NumericFieldRef extends ComparableFieldRef { }; } -// === Concrete Field Reference Types === - /// String field reference with text-specific lookups @immutable class StringFieldRef extends FieldRef { @@ -205,8 +197,6 @@ class DurationFieldRef extends ComparableFieldRef { const DurationFieldRef(super.name, {super.table}); } -// === Related Field References (for ForeignKey, etc.) === - /// Reference to a related model for traversing relationships @immutable class RelatedFieldRef extends FieldRef { diff --git a/packages/jao/lib/src/migrations/operations.dart b/packages/jao/lib/src/migrations/operations.dart index c9bd61f..a9b3111 100644 --- a/packages/jao/lib/src/migrations/operations.dart +++ b/packages/jao/lib/src/migrations/operations.dart @@ -7,6 +7,19 @@ import 'package:meta/meta.dart'; import '../db/connection.dart'; import 'schema.dart'; +/// Quote a default value for SQL if needed. +/// Numbers, booleans, and SQL keywords (CURRENT_TIMESTAMP) are emitted as-is. +/// Everything else is wrapped in single quotes. +String sqlDefault(String value) { + if (num.tryParse(value) != null) return value; + final lower = value.toLowerCase(); + if (lower == 'true' || lower == 'false') return value; + if (lower == 'current_timestamp' || lower == 'null') return value; + if (value.startsWith("'") && value.endsWith("'")) return value; + final escaped = value.replaceAll("'", "''"); + return "'$escaped'"; +} + /// Base class for all migration operations. @immutable abstract class MigrationOperation { @@ -22,8 +35,6 @@ abstract class MigrationOperation { bool get isReversible; } -// === Table Operations === - /// Create a new table. @immutable class CreateTable extends MigrationOperation { @@ -92,8 +103,8 @@ class CreateTable extends MigrationOperation { } // Default value - if (col.defaultValue != null) { - buffer.write(' DEFAULT ${col.defaultValue}'); + if (col.defaultValue case final defaultValue?) { + buffer.write(' DEFAULT ${sqlDefault(defaultValue)}'); } // Check constraint @@ -191,8 +202,6 @@ class RenameTable extends MigrationOperation { bool get isReversible => true; } -// === Column Operations === - /// Add a column to an existing table. @immutable class AddColumn extends MigrationOperation { @@ -219,8 +228,8 @@ class AddColumn extends MigrationOperation { buffer.write(' NOT NULL'); } - if (column.defaultValue != null) { - buffer.write(' DEFAULT ${column.defaultValue}'); + if (column.defaultValue case final defaultValue?) { + buffer.write(' DEFAULT ${sqlDefault(defaultValue)}'); } return buffer.toString(); @@ -308,8 +317,8 @@ class AlterColumn extends MigrationOperation { } // Change default - if (modification.defaultValue != null) { - statements.add('ALTER TABLE $table ALTER COLUMN $column SET DEFAULT ${modification.defaultValue}'); + if (modification.defaultValue case final defaultValue?) { + statements.add('ALTER TABLE $table ALTER COLUMN $column SET DEFAULT ${sqlDefault(defaultValue)}'); } else if (modification.dropDefault) { statements.add('ALTER TABLE $table ALTER COLUMN $column DROP DEFAULT'); } @@ -329,8 +338,6 @@ class AlterColumn extends MigrationOperation { bool get isReversible => false; } -// === Index Operations === - /// Create an index. @immutable class CreateIndex extends MigrationOperation { @@ -385,8 +392,6 @@ class DropIndex extends MigrationOperation { bool get isReversible => false; } -// === Constraint Operations === - /// Add a foreign key constraint. @immutable class AddForeignKey extends MigrationOperation { @@ -442,8 +447,6 @@ class DropConstraint extends MigrationOperation { bool get isReversible => false; } -// === Raw SQL Operations === - /// Execute raw SQL. @immutable class RawSql extends MigrationOperation { diff --git a/packages/jao/lib/src/query/aggregates.dart b/packages/jao/lib/src/query/aggregates.dart index 54ec889..1a1ca96 100644 --- a/packages/jao/lib/src/query/aggregates.dart +++ b/packages/jao/lib/src/query/aggregates.dart @@ -95,8 +95,6 @@ class Least extends FunctionCall { Least(List exprs) : super('LEAST', exprs); } -// === String Functions === - /// String length @immutable class Length extends FunctionCall { @@ -140,8 +138,6 @@ class Replace extends FunctionCall { Replace(Expression expr, String from, String to) : super('REPLACE', [expr, Value(from), Value(to)]); } -// === Date/Time Functions === - /// Current date @immutable class CurrentDate extends FunctionCall { @@ -173,8 +169,6 @@ class DateTrunc extends FunctionCall { DateTrunc(String precision, Expression expr) : super('DATE_TRUNC', [Value(precision), expr]); } -// === Math Functions === - /// Absolute value @immutable class Abs extends FunctionCall {