Add functions to extract individual fields from a datetime

This commit is contained in:
Simon Binder 2019-02-14 21:06:57 +01:00
parent 080682e841
commit 1fc487cac8
7 changed files with 72 additions and 9 deletions

View File

@ -21,9 +21,7 @@ abstract class TextColumn extends Column<String, StringType> {
/// A column that stores a [DateTime]. Times will be stored as unix timestamp /// A column that stores a [DateTime]. Times will be stored as unix timestamp
/// and will thus have a second accuracy. /// and will thus have a second accuracy.
abstract class DateTimeColumn extends Column<DateTime, DateTimeType> { abstract class DateTimeColumn extends Column<DateTime, DateTimeType> {}
}
class ColumnBuilder<Builder, ResultColumn> { class ColumnBuilder<Builder, ResultColumn> {
/// By default, the field name will be used as the column name, e.g. /// By default, the field name will be used as the column name, e.g.

View File

@ -0,0 +1,32 @@
import 'package:sally/sally.dart';
import 'package:sally/src/runtime/components/component.dart';
import 'package:sally/src/runtime/expressions/expression.dart';
Expression<IntType> year(Expression<DateTimeType> date) =>
_StrftimeSingleFieldExpression('%Y', date);
Expression<IntType> month(Expression<DateTimeType> date) =>
_StrftimeSingleFieldExpression('%m', date);
Expression<IntType> day(Expression<DateTimeType> date) =>
_StrftimeSingleFieldExpression('%d', date);
Expression<IntType> hour(Expression<DateTimeType> date) =>
_StrftimeSingleFieldExpression('%H', date);
Expression<IntType> minute(Expression<DateTimeType> date) =>
_StrftimeSingleFieldExpression('%M', date);
Expression<IntType> second(Expression<DateTimeType> date) =>
_StrftimeSingleFieldExpression('%S', date);
/// Expression that extracts components out of a date time by using the builtin
/// sqlite function "strftime" and casting the result to an integer.
class _StrftimeSingleFieldExpression extends Expression<IntType> {
final String format;
final Expression<DateTimeType> date;
_StrftimeSingleFieldExpression(this.format, this.date);
@override
void writeInto(GenerationContext context) {
context.buffer.write('CAST(strftime("$format", ');
date.writeInto(context);
context.buffer.write(', "unixepoch") AS INTEGER)');
}
}

View File

@ -1,2 +1,3 @@
export 'bools.dart' show and, or, not; export 'bools.dart' show and, or, not;
export 'datetimes.dart';
export 'variables.dart'; export 'variables.dart';

View File

@ -0,0 +1,28 @@
import 'package:sally/sally.dart';
import 'package:sally/src/runtime/components/component.dart';
import 'package:sally/src/runtime/expressions/expression.dart';
import 'package:test_api/test_api.dart';
typedef Expression<IntType> _Extractor(Expression<DateTimeType> d);
/// Tests the top level [year], [month], ..., [second] methods
void main() {
final expectedResults = <_Extractor, String>{
year: 'CAST(strftime("%Y", column, "unixepoch") AS INTEGER)',
month: 'CAST(strftime("%m", column, "unixepoch") AS INTEGER)',
day: 'CAST(strftime("%d", column, "unixepoch") AS INTEGER)',
hour: 'CAST(strftime("%H", column, "unixepoch") AS INTEGER)',
minute: 'CAST(strftime("%M", column, "unixepoch") AS INTEGER)',
second: 'CAST(strftime("%S", column, "unixepoch") AS INTEGER)',
};
final column = GeneratedDateTimeColumn('column', false);
expectedResults.forEach((key, value) {
test('should extract field', () {
final ctx = GenerationContext(null);
key(column).writeInto(ctx);
expect(ctx.sql, value);
});
});
}

View File

@ -46,7 +46,8 @@ void main() {
}); });
test('adds columns', () async { test('adds columns', () async {
await Migrator(db, mockQueryExecutor).addColumn(db.users, db.users.isAwesome); await Migrator(db, mockQueryExecutor)
.addColumn(db.users, db.users.isAwesome);
verify(mockQueryExecutor.call('ALTER TABLE users ADD COLUMN ' verify(mockQueryExecutor.call('ALTER TABLE users ADD COLUMN '
'is_awesome BOOLEAN NOT NULL CHECK (is_awesome in (0, 1));')); 'is_awesome BOOLEAN NOT NULL CHECK (is_awesome in (0, 1));'));

View File

@ -3,14 +3,16 @@ import 'package:test_api/test_api.dart';
const _exampleUnixSqlite = 1550172560; const _exampleUnixSqlite = 1550172560;
const _exampleUnixMillis = 1550172560000; const _exampleUnixMillis = 1550172560000;
final _exampleDateTime = DateTime.fromMillisecondsSinceEpoch(_exampleUnixMillis); final _exampleDateTime =
DateTime.fromMillisecondsSinceEpoch(_exampleUnixMillis);
void main() { void main() {
final type = const DateTimeType(); final type = const DateTimeType();
group('DateTimes', () { group('DateTimes', () {
test('can be read from unix stamps returned by sql', () { test('can be read from unix stamps returned by sql', () {
expect(type.mapFromDatabaseResponse(_exampleUnixSqlite), _exampleDateTime); expect(
type.mapFromDatabaseResponse(_exampleUnixSqlite), _exampleDateTime);
}); });
test('can read null value from sql', () { test('can read null value from sql', () {
@ -18,7 +20,8 @@ void main() {
}); });
test('can be mapped to sql constants', () { test('can be mapped to sql constants', () {
expect(type.mapToSqlConstant(_exampleDateTime), _exampleUnixSqlite.toString()); expect(type.mapToSqlConstant(_exampleDateTime),
_exampleUnixSqlite.toString());
}); });
test('can be mapped to variables', () { test('can be mapped to variables', () {