Define API for default values

This commit is contained in:
Simon Binder 2019-04-01 14:28:44 +02:00
parent d284aca4f6
commit 62743dc15f
No known key found for this signature in database
GPG Key ID: B807FDF954BA00CF
6 changed files with 85 additions and 31 deletions

View File

@ -32,7 +32,11 @@ abstract class BlobColumn extends Column<Uint8List, BlobType> {}
/// be called at runtime. Instead, moor_generator will take a look at your
/// source code (specifically, it will analyze which of the methods you use) to
/// figure out the column structure of a table.
class ColumnBuilder<Builder, ResultColumn> {
class ColumnBuilder<
Builder,
ResultColumn extends Column<ResultDartType, ResultSqlType>,
ResultSqlType extends SqlType<ResultDartType>,
ResultDartType> {
/// By default, the field name will be used as the column name, e.g.
/// `IntColumn get id = integer()` will have "id" as its associated name.
/// Columns made up of multiple words are expected to be in camelCase and will
@ -53,7 +57,7 @@ class ColumnBuilder<Builder, ResultColumn> {
/// `name TYPE NULLABILITY NATIVE_CONSTRAINTS`. Native constraints are used to
/// enforce that booleans are either 0 or 1 (e.g.
/// `field BOOLEAN NOT NULL CHECK (field in (0, 1)`). Auto-Increment
/// columns also make use of the native constraints.
/// columns also make use of the native constraints, as do default values.
/// If [customConstraint] has been called, the nullability information and
/// native constraints will never be written. Instead, they will be replaced
/// with the [constraint]. For example, if you call
@ -73,23 +77,36 @@ class ColumnBuilder<Builder, ResultColumn> {
/// - [GeneratedColumn.writeCustomConstraints]
Builder customConstraint(String constraint) => null;
/// The column will use this expression when a row is inserted and no value
/// has been specified.
///
/// See also:
/// - [Constant], which can be used to model literals that appear in CREATE
/// TABLE statements.
/// - [currentDate] and [currentDateAndTime], which are useful expressions to
/// store the current date/time as a default value.
Builder withDefault(Expression<ResultDartType, ResultSqlType> e) => null;
/// Turns this column builder into a column. This method won't actually be
/// called in your code. Instead, moor_generator will take a look at your
/// source code to figure out your table structure.
ResultColumn call() => null;
}
class IntColumnBuilder extends ColumnBuilder<IntColumnBuilder, IntColumn> {
class IntColumnBuilder extends ColumnBuilder<IntColumnBuilder, IntColumn, IntType, int> {
/// Enables auto-increment for this column, which will also make this column
/// the primary key of the table.
IntColumnBuilder autoIncrement() => this;
}
class BoolColumnBuilder extends ColumnBuilder<BoolColumnBuilder, BoolColumn> {}
class BoolColumnBuilder
extends ColumnBuilder<BoolColumnBuilder, BoolColumn, BoolType, bool> {}
class BlobColumnBuilder extends ColumnBuilder<BlobColumnBuilder, BlobColumn> {}
class BlobColumnBuilder
extends ColumnBuilder<BlobColumnBuilder, BlobColumn, BlobType, Uint8List> {}
class TextColumnBuilder extends ColumnBuilder<TextColumnBuilder, TextColumn> {
class TextColumnBuilder
extends ColumnBuilder<TextColumnBuilder, TextColumn, StringType, String> {
/// Puts a constraint on the minimum and maximum length of text that can be
/// stored in this column (will be validated whenever this column is updated
/// or a value is inserted). If [min] is not null and one tries to write a
@ -100,4 +117,4 @@ class TextColumnBuilder extends ColumnBuilder<TextColumnBuilder, TextColumn> {
}
class DateTimeColumnBuilder
extends ColumnBuilder<DateTimeColumnBuilder, DateTimeColumn> {}
extends ColumnBuilder<DateTimeColumnBuilder, DateTimeColumn, DateTimeType, DateTime> {}

View File

@ -5,7 +5,7 @@ import 'package:moor/src/runtime/expressions/expression.dart';
class CustomExpression<D, S extends SqlType<D>> extends Expression<D, S> {
final String content;
CustomExpression(this.content);
const CustomExpression(this.content);
@override
void writeInto(GenerationContext context) {

View File

@ -1,5 +1,6 @@
import 'package:moor/moor.dart';
import 'package:moor/src/runtime/components/component.dart';
import 'package:moor/src/runtime/expressions/custom.dart';
import 'package:moor/src/runtime/expressions/expression.dart';
/// Extracts the (UTC) year from the given expression that resolves
@ -32,6 +33,15 @@ Expression<int, IntType> minute(Expression<DateTime, DateTimeType> date) =>
Expression<int, IntType> second(Expression<DateTime, DateTimeType> date) =>
_StrftimeSingleFieldExpression('%S', date);
/// A sql expression that evaluates to the current date represented as a unix
/// timestamp. The hour, minute and second fields will be set to 0.
const Expression<DateTime, DateTimeType> currentDate =
CustomExpression("strftime('%s', CURRENT_DATE)");
/// A sql expression that evaluates to the current date and time, similar to
/// [DateTime.now]. Timestamps are stored with a second accuracy.
const Expression<DateTime, DateTimeType> currentDateAndTime =
CustomExpression("strftime('%s', CURRENT_TIMESTAMP)");
/// 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<int, IntType> {

View File

@ -7,6 +7,10 @@ import 'package:moor/src/types/sql_types.dart';
/// include queries (which might evaluate to multiple values) but individual
/// columns, functions and operators.
abstract class Expression<D, T extends SqlType<D>> implements Component {
const Expression();
bool get isLiteral => false;
/// Whether this expression is equal to the given expression.
Expression<bool, BoolType> equalsExp(Expression<D, T> compare) =>
Comparison.equal(this, compare);
@ -21,7 +25,7 @@ abstract class Expression<D, T extends SqlType<D>> implements Component {
/// An expression that looks like "$a operator $b", where $a and $b itself
/// are expressions and the operator is any string.
abstract class InfixOperator<D, T extends SqlType<D>> with Expression<D, T> {
abstract class InfixOperator<D, T extends SqlType<D>> extends Expression<D, T> {
Expression get left;
Expression get right;
String get operator;

View File

@ -9,7 +9,7 @@ import 'package:moor/src/types/sql_types.dart';
class Variable<T, S extends SqlType<T>> extends Expression<T, S> {
final T value;
Variable(this.value);
const Variable(this.value);
/// Creates a variable that holds the specified boolean.
static Variable<bool, BoolType> withBool(bool value) {
@ -60,9 +60,12 @@ class Variable<T, S extends SqlType<T>> extends Expression<T, S> {
/// yet as it can be vulnerable to SQL-injection attacks. Please use [Variable]
/// instead.
class Constant<T, S extends SqlType<T>> extends Expression<T, S> {
const Constant(this.value);
final T value;
Constant(this.value);
@override
final bool isLiteral = true;
@override
void writeInto(GenerationContext context) {

View File

@ -13,7 +13,6 @@ import 'package:moor/sqlite_keywords.dart';
abstract class GeneratedColumn<T, S extends SqlType<T>> extends Column<T, S> {
/// The sql name of this column.
final String $name;
String get escapedName => escapeIfNeeded($name);
/// The name of the table that contains this column
@ -27,8 +26,12 @@ abstract class GeneratedColumn<T, S extends SqlType<T>> extends Column<T, S> {
/// field is going to be null.
final String $customConstraints;
/// The default expression to be used during inserts when no value has been
/// specified. Can be null if no default value is set.
final Expression<T, S> defaultValue;
GeneratedColumn(this.$name, this.tableName, this.$nullable,
{this.$customConstraints});
{this.$customConstraints, this.defaultValue});
/// Writes the definition of this column, as defined
/// [here](https://www.sqlite.org/syntax/column-def.html), into the given
@ -68,8 +71,10 @@ abstract class GeneratedColumn<T, S extends SqlType<T>> extends Column<T, S> {
/// method should check whether the value is valid for an update. Null values
/// should always be accepted for updates, as the describe a value that should
/// not be replaced.
bool isAcceptableValue(T value, bool duringInsert) =>
($nullable || !duringInsert) || value != null;
bool isAcceptableValue(T value, bool duringInsert) {
final nullOk = !duringInsert || $nullable || defaultValue != null;
return nullOk || value != null;
}
}
class GeneratedTextColumn extends GeneratedColumn<String, StringType>
@ -77,10 +82,16 @@ class GeneratedTextColumn extends GeneratedColumn<String, StringType>
final int minTextLength;
final int maxTextLength;
GeneratedTextColumn(String name, String tableName, bool nullable,
{this.minTextLength, this.maxTextLength, String $customConstraints})
: super(name, tableName, nullable,
$customConstraints: $customConstraints);
GeneratedTextColumn(
String name,
String tableName,
bool nullable, {
this.minTextLength,
this.maxTextLength,
String $customConstraints,
Expression<String, StringType> defaultValue,
}) : super(name, tableName, nullable,
$customConstraints: $customConstraints, defaultValue: defaultValue);
@override
Expression<bool, BoolType> like(String pattern) =>
@ -91,8 +102,8 @@ class GeneratedTextColumn extends GeneratedColumn<String, StringType>
@override
bool isAcceptableValue(String value, bool duringInsert) {
final nullOk = !duringInsert || $nullable;
if (value == null) return nullOk;
// handle nullability check in common column
if (value == null) return super.isAcceptableValue(null, duringInsert);
final length = value.length;
if (minTextLength != null && minTextLength > length) return false;
@ -105,9 +116,9 @@ class GeneratedTextColumn extends GeneratedColumn<String, StringType>
class GeneratedBoolColumn extends GeneratedColumn<bool, BoolType>
implements BoolColumn {
GeneratedBoolColumn(String name, String tableName, bool nullable,
{String $customConstraints})
{String $customConstraints, Expression<bool, BoolType> defaultValue})
: super(name, tableName, nullable,
$customConstraints: $customConstraints);
$customConstraints: $customConstraints, defaultValue: defaultValue);
@override
final String typeName = 'BOOLEAN';
@ -126,10 +137,15 @@ class GeneratedIntColumn extends GeneratedColumn<int, IntType>
@override
final String typeName = 'INTEGER';
GeneratedIntColumn(String name, String tableName, bool nullable,
{this.hasAutoIncrement = false, String $customConstraints})
: super(name, tableName, nullable,
$customConstraints: $customConstraints);
GeneratedIntColumn(
String name,
String tableName,
bool nullable, {
this.hasAutoIncrement = false,
String $customConstraints,
Expression<int, IntType> defaultValue,
}) : super(name, tableName, nullable,
$customConstraints: $customConstraints, defaultValue: defaultValue);
@override
void writeColumnDefinition(StringBuffer into) {
@ -147,10 +163,14 @@ class GeneratedIntColumn extends GeneratedColumn<int, IntType>
class GeneratedDateTimeColumn extends GeneratedColumn<DateTime, DateTimeType>
implements DateTimeColumn {
GeneratedDateTimeColumn(String $name, String tableName, bool $nullable,
{String $customConstraints})
: super($name, tableName, $nullable,
$customConstraints: $customConstraints);
GeneratedDateTimeColumn(
String $name,
String tableName,
bool $nullable, {
String $customConstraints,
Expression<DateTime, DateTimeType> defaultValue,
}) : super($name, tableName, $nullable,
$customConstraints: $customConstraints, defaultValue: defaultValue);
@override
String get typeName => 'INTEGER'; // date-times are stored as unix-timestamps