Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 49 additions & 16 deletions packages/jao/lib/src/migrations/generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class ModelFieldSchema {
final bool index;
final bool primaryKey;
final bool autoIncrement;
final String? defaultValue;
final Object? defaultValue;
final int? maxLength;
final int? precision;
final int? scale;
Expand Down Expand Up @@ -151,12 +151,22 @@ class SchemaGenerator {
field.columnName,
length: field.maxLength ?? 255,
nullable: field.nullable,
defaultValue: field.defaultValue,
defaultValue: switch (field.defaultValue) {
final String v => v,
_ => null,
},
);
if (field.unique) builder.unique(field.columnName);

case FieldType.text:
builder.text(field.columnName, nullable: field.nullable, defaultValue: field.defaultValue);
builder.text(
field.columnName,
nullable: field.nullable,
defaultValue: switch (field.defaultValue) {
final String v => v,
_ => null,
},
);

case FieldType.integer:
case FieldType.smallInt:
Expand All @@ -174,7 +184,7 @@ class SchemaGenerator {
field.columnName,
nullable: field.nullable,
defaultValue: switch (field.defaultValue) {
final value? => int.tryParse(value),
final int v => v,
_ => null,
},
);
Expand All @@ -185,7 +195,7 @@ class SchemaGenerator {
field.columnName,
nullable: field.nullable,
defaultValue: switch (field.defaultValue) {
final value? => double.tryParse(value),
final double v => v,
_ => null,
},
);
Expand All @@ -194,7 +204,7 @@ class SchemaGenerator {
field.columnName,
nullable: field.nullable,
defaultValue: switch (field.defaultValue) {
final value? => double.tryParse(value),
final double v => v,
_ => null,
},
);
Expand All @@ -205,21 +215,31 @@ class SchemaGenerator {
precision: field.precision ?? 10,
scale: field.scale ?? 2,
nullable: field.nullable,
defaultValue: field.defaultValue,
defaultValue: switch (field.defaultValue) {
final String v => v,
_ => null,
},
);

case FieldType.boolean:
builder.boolean(
field.columnName,
nullable: field.nullable,
defaultValue: switch (field.defaultValue) {
final value? => value.toLowerCase() == 'true',
final bool v => v,
_ => null,
},
);

case FieldType.date:
builder.date(field.columnName, nullable: field.nullable, defaultValue: field.defaultValue);
builder.date(
field.columnName,
nullable: field.nullable,
defaultValue: switch (field.defaultValue) {
final String v => v,
_ => null,
},
);

case FieldType.timestamp:
case FieldType.timestampTz:
Expand All @@ -230,11 +250,25 @@ class SchemaGenerator {
);

case FieldType.uuid:
builder.uuidColumn(field.columnName, nullable: field.nullable, defaultValue: field.defaultValue);
builder.uuidColumn(
field.columnName,
nullable: field.nullable,
defaultValue: switch (field.defaultValue) {
final String v => v,
_ => null,
},
);

case FieldType.json:
case FieldType.jsonb:
builder.jsonb(field.columnName, nullable: field.nullable, defaultValue: field.defaultValue);
builder.jsonb(
field.columnName,
nullable: field.nullable,
defaultValue: switch (field.defaultValue) {
final String v => v,
_ => null,
},
);

case FieldType.bytea:
case FieldType.blob:
Expand Down Expand Up @@ -289,7 +323,7 @@ class SchemaGenerator {
name: field.columnName,
type: field.dbType,
nullable: field.nullable,
defaultValue: field.defaultValue,
defaultValue: field.defaultValue?.toString(),
length: field.maxLength,
precision: field.precision,
scale: field.scale,
Expand Down Expand Up @@ -366,7 +400,7 @@ class SchemaGenerator {
ColumnModification(
table: model.tableName,
column: field.columnName,
defaultValue: defaultValue,
defaultValue: defaultValue.toString(),
),
),
);
Expand Down Expand Up @@ -734,12 +768,11 @@ class SchemaGenerator {
///
/// Used to avoid false positives when comparing serial vs integer for PKs.
/// Compare default values, normalizing DB-reported values against model values.
bool _defaultValuesDiffer(String? modelDefault, String? dbDefault) {
bool _defaultValuesDiffer(Object? modelDefault, String? dbDefault) {
if (modelDefault == null && dbDefault == null) return false;
if (modelDefault == null || dbDefault == null) return true;

// Normalize: DB may wrap strings in quotes, append type casts, etc.
final normalizedModel = _normalizeDefaultValue(modelDefault);
final normalizedModel = _normalizeDefaultValue(modelDefault.toString());
final normalizedDb = _normalizeDefaultValue(dbDefault);
return normalizedModel != normalizedDb;
}
Expand Down
16 changes: 8 additions & 8 deletions packages/jao/test/migrations/schema_generator_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ void main() {
name: 'isActive',
columnName: 'is_active',
dbType: FieldType.boolean,
defaultValue: 'true',
defaultValue: true,
);

expect(field.defaultValue, equals('true'));
expect(field.defaultValue, equals(true));
});

test('stores varchar maxLength', () {
Expand Down Expand Up @@ -247,7 +247,7 @@ void main() {
name: 'isActive',
columnName: 'is_active',
dbType: FieldType.boolean,
defaultValue: 'true',
defaultValue: true,
),
ModelFieldSchema(name: 'birthDate', columnName: 'birth_date', dbType: FieldType.date),
ModelFieldSchema(
Expand Down Expand Up @@ -1189,7 +1189,7 @@ void main() {
name: 'status',
columnName: 'status',
dbType: FieldType.text,
defaultValue: "'active'",
defaultValue: 'active',
),
],
);
Expand All @@ -1198,7 +1198,7 @@ void main() {

final alterOps = operations.whereType<AlterColumn>().toList();
expect(alterOps.isNotEmpty, isTrue, reason: 'Should detect missing default value');
expect(alterOps.any((op) => op.modification.defaultValue == "'active'"), isTrue);
expect(alterOps.any((op) => op.modification.defaultValue == 'active'), isTrue);
});
});

Expand Down Expand Up @@ -1428,7 +1428,7 @@ void main() {
name: 'priority',
columnName: 'priority',
dbType: FieldType.integer,
defaultValue: '5',
defaultValue: 5,
),
],
);
Expand Down Expand Up @@ -1465,7 +1465,7 @@ void main() {
name: 'active',
columnName: 'active',
dbType: FieldType.integer,
defaultValue: '0',
defaultValue: 0,
),
],
);
Expand Down Expand Up @@ -1938,7 +1938,7 @@ void main() {
columnName: 'value',
dbType: FieldType.doublePrecision,
nullable: true,
defaultValue: '3.14159',
defaultValue: 3.14159,
),
],
);
Expand Down
35 changes: 17 additions & 18 deletions packages/jao_generator/lib/src/generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,22 +85,13 @@ class JaoGenerator extends GeneratorForAnnotation<Model> {
return null;
}

String? _extractDefaultValue(dynamic dartObject) {
Object? _extractDefaultValue(dynamic dartObject) {
if (dartObject == null || dartObject.isNull) return null;

if (dartObject.toIntValue() case final intVal?) {
return intVal.toString();
}
if (dartObject.toDoubleValue() case final doubleVal?) {
return doubleVal.toString();
}
if (dartObject.toBoolValue() case final boolVal?) {
return boolVal.toString();
}
if (dartObject.toStringValue() case final stringVal?) {
final escaped = stringVal.replaceAll("'", "\\'");
return "'$escaped'";
}
if (dartObject.toIntValue() case final intVal?) return intVal;
if (dartObject.toDoubleValue() case final doubleVal?) return doubleVal;
if (dartObject.toBoolValue() case final boolVal?) return boolVal;
if (dartObject.toStringValue() case final stringVal?) return stringVal;

return null;
}
Expand Down Expand Up @@ -444,7 +435,11 @@ class JaoGenerator extends GeneratorForAnnotation<Model> {
buffer.writeln(' defaultValues: {');
for (final f in fieldsWithDefaults) {
final columnName = _toSnakeCase(f.name);
buffer.writeln(" '$columnName': ${f.defaultValue},");
final emittedValue = switch (f.defaultValue) {
final String v => "'$v'",
final v => '$v',
};
buffer.writeln(" '$columnName': $emittedValue,");
}
buffer.writeln(' },');
}
Expand Down Expand Up @@ -508,7 +503,11 @@ class JaoGenerator extends GeneratorForAnnotation<Model> {
buffer.writeln(' scale: $scale,');
}
if (field.defaultValue case final defaultValue?) {
buffer.writeln(" defaultValue: $defaultValue,");
final emittedValue = switch (defaultValue) {
final String v => "'$v'",
_ => '$defaultValue',
};
buffer.writeln(" defaultValue: $emittedValue,");
}
if (field.relation case final relation?) {
final onDelete = field.onDelete ?? 'cascade';
Expand Down Expand Up @@ -697,7 +696,7 @@ class _FieldInfo {
final bool autoNowAdd;
final bool autoNow;
final bool autoGenerateUuid;
final String? defaultValue;
final Object? defaultValue;
final _RelationInfo? relation;
final bool isEnum;
final bool storeEnumAsInt;
Expand Down Expand Up @@ -757,7 +756,7 @@ class _FieldAnnotationInfo {
final bool autoNowAdd;
final bool autoNow;
final bool autoGenerateUuid;
final String? defaultValue;
final Object? defaultValue;
final _RelationInfo? relation;
final bool isEnum;
final bool storeEnumAsInt;
Expand Down
2 changes: 1 addition & 1 deletion packages/jao_generator/test/generator/generator_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -424,7 +424,7 @@ class User {
}
''');

expect(result, contains('defaultValue: false'));
expect(result, contains("defaultValue: false"));
});

test('emits defaultValue in ModelFieldSchema for CharField', () async {
Expand Down
Loading