diff --git a/docs/lib/snippets/_shared/todo_tables.dart b/docs/lib/snippets/_shared/todo_tables.dart index 695e3c31..8a0da5ba 100644 --- a/docs/lib/snippets/_shared/todo_tables.dart +++ b/docs/lib/snippets/_shared/todo_tables.dart @@ -9,6 +9,9 @@ class TodoItems extends Table { TextColumn get title => text().withLength(min: 6, max: 32)(); TextColumn get content => text().named('body')(); IntColumn get category => integer().nullable().references(Categories, #id)(); + // #enddocregion tables + DateTimeColumn get dueDate => dateTime().nullable()(); + // #docregion tables } @DataClassName('Category') @@ -18,9 +21,15 @@ class Categories extends Table { } // #enddocregion tables +class Users extends Table { + IntColumn get id => integer().autoIncrement()(); + DateTimeColumn get birthDate => dateTime()(); +} + class CanUseCommonTables extends ModularAccessor { CanUseCommonTables(super.attachedDatabase); $TodoItemsTable get todoItems => resultSet('todo_items'); $CategoriesTable get categories => resultSet('categories'); + $UsersTable get users => resultSet('users'); } diff --git a/docs/lib/snippets/_shared/todo_tables.drift.dart b/docs/lib/snippets/_shared/todo_tables.drift.dart index 704fc55f..8a5e2d92 100644 --- a/docs/lib/snippets/_shared/todo_tables.drift.dart +++ b/docs/lib/snippets/_shared/todo_tables.drift.dart @@ -42,8 +42,15 @@ class $TodoItemsTable extends i2.TodoItems requiredDuringInsert: false, defaultConstraints: i0.GeneratedColumn.constraintIsAlways('REFERENCES categories (id)')); + static const i0.VerificationMeta _dueDateMeta = + const i0.VerificationMeta('dueDate'); @override - List get $columns => [id, title, content, category]; + late final i0.GeneratedColumn dueDate = + i0.GeneratedColumn('due_date', aliasedName, true, + type: i0.DriftSqlType.dateTime, requiredDuringInsert: false); + @override + List get $columns => + [id, title, content, category, dueDate]; @override String get aliasedName => _alias ?? actualTableName; @override @@ -73,6 +80,10 @@ class $TodoItemsTable extends i2.TodoItems context.handle(_categoryMeta, category.isAcceptableOrUnknown(data['category']!, _categoryMeta)); } + if (data.containsKey('due_date')) { + context.handle(_dueDateMeta, + dueDate.isAcceptableOrUnknown(data['due_date']!, _dueDateMeta)); + } return context; } @@ -90,6 +101,8 @@ class $TodoItemsTable extends i2.TodoItems .read(i0.DriftSqlType.string, data['${effectivePrefix}body'])!, category: attachedDatabase.typeMapping .read(i0.DriftSqlType.int, data['${effectivePrefix}category']), + dueDate: attachedDatabase.typeMapping + .read(i0.DriftSqlType.dateTime, data['${effectivePrefix}due_date']), ); } @@ -104,11 +117,13 @@ class TodoItem extends i0.DataClass implements i0.Insertable { final String title; final String content; final int? category; + final DateTime? dueDate; const TodoItem( {required this.id, required this.title, required this.content, - this.category}); + this.category, + this.dueDate}); @override Map toColumns(bool nullToAbsent) { final map = {}; @@ -118,6 +133,9 @@ class TodoItem extends i0.DataClass implements i0.Insertable { if (!nullToAbsent || category != null) { map['category'] = i0.Variable(category); } + if (!nullToAbsent || dueDate != null) { + map['due_date'] = i0.Variable(dueDate); + } return map; } @@ -129,6 +147,9 @@ class TodoItem extends i0.DataClass implements i0.Insertable { category: category == null && nullToAbsent ? const i0.Value.absent() : i0.Value(category), + dueDate: dueDate == null && nullToAbsent + ? const i0.Value.absent() + : i0.Value(dueDate), ); } @@ -140,6 +161,7 @@ class TodoItem extends i0.DataClass implements i0.Insertable { title: serializer.fromJson(json['title']), content: serializer.fromJson(json['content']), category: serializer.fromJson(json['category']), + dueDate: serializer.fromJson(json['dueDate']), ); } @override @@ -150,6 +172,7 @@ class TodoItem extends i0.DataClass implements i0.Insertable { 'title': serializer.toJson(title), 'content': serializer.toJson(content), 'category': serializer.toJson(category), + 'dueDate': serializer.toJson(dueDate), }; } @@ -157,12 +180,14 @@ class TodoItem extends i0.DataClass implements i0.Insertable { {int? id, String? title, String? content, - i0.Value category = const i0.Value.absent()}) => + i0.Value category = const i0.Value.absent(), + i0.Value dueDate = const i0.Value.absent()}) => i1.TodoItem( id: id ?? this.id, title: title ?? this.title, content: content ?? this.content, category: category.present ? category.value : this.category, + dueDate: dueDate.present ? dueDate.value : this.dueDate, ); @override String toString() { @@ -170,13 +195,14 @@ class TodoItem extends i0.DataClass implements i0.Insertable { ..write('id: $id, ') ..write('title: $title, ') ..write('content: $content, ') - ..write('category: $category') + ..write('category: $category, ') + ..write('dueDate: $dueDate') ..write(')')) .toString(); } @override - int get hashCode => Object.hash(id, title, content, category); + int get hashCode => Object.hash(id, title, content, category, dueDate); @override bool operator ==(Object other) => identical(this, other) || @@ -184,7 +210,8 @@ class TodoItem extends i0.DataClass implements i0.Insertable { other.id == this.id && other.title == this.title && other.content == this.content && - other.category == this.category); + other.category == this.category && + other.dueDate == this.dueDate); } class TodoItemsCompanion extends i0.UpdateCompanion { @@ -192,17 +219,20 @@ class TodoItemsCompanion extends i0.UpdateCompanion { final i0.Value title; final i0.Value content; final i0.Value category; + final i0.Value dueDate; const TodoItemsCompanion({ this.id = const i0.Value.absent(), this.title = const i0.Value.absent(), this.content = const i0.Value.absent(), this.category = const i0.Value.absent(), + this.dueDate = const i0.Value.absent(), }); TodoItemsCompanion.insert({ this.id = const i0.Value.absent(), required String title, required String content, this.category = const i0.Value.absent(), + this.dueDate = const i0.Value.absent(), }) : title = i0.Value(title), content = i0.Value(content); static i0.Insertable custom({ @@ -210,12 +240,14 @@ class TodoItemsCompanion extends i0.UpdateCompanion { i0.Expression? title, i0.Expression? content, i0.Expression? category, + i0.Expression? dueDate, }) { return i0.RawValuesInsertable({ if (id != null) 'id': id, if (title != null) 'title': title, if (content != null) 'body': content, if (category != null) 'category': category, + if (dueDate != null) 'due_date': dueDate, }); } @@ -223,12 +255,14 @@ class TodoItemsCompanion extends i0.UpdateCompanion { {i0.Value? id, i0.Value? title, i0.Value? content, - i0.Value? category}) { + i0.Value? category, + i0.Value? dueDate}) { return i1.TodoItemsCompanion( id: id ?? this.id, title: title ?? this.title, content: content ?? this.content, category: category ?? this.category, + dueDate: dueDate ?? this.dueDate, ); } @@ -247,6 +281,9 @@ class TodoItemsCompanion extends i0.UpdateCompanion { if (category.present) { map['category'] = i0.Variable(category.value); } + if (dueDate.present) { + map['due_date'] = i0.Variable(dueDate.value); + } return map; } @@ -256,7 +293,8 @@ class TodoItemsCompanion extends i0.UpdateCompanion { ..write('id: $id, ') ..write('title: $title, ') ..write('content: $content, ') - ..write('category: $category') + ..write('category: $category, ') + ..write('dueDate: $dueDate') ..write(')')) .toString(); } @@ -432,3 +470,176 @@ class CategoriesCompanion extends i0.UpdateCompanion { .toString(); } } + +class $UsersTable extends i2.Users with i0.TableInfo<$UsersTable, i1.User> { + @override + final i0.GeneratedDatabase attachedDatabase; + final String? _alias; + $UsersTable(this.attachedDatabase, [this._alias]); + static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id'); + @override + late final i0.GeneratedColumn id = i0.GeneratedColumn( + 'id', aliasedName, false, + hasAutoIncrement: true, + type: i0.DriftSqlType.int, + requiredDuringInsert: false, + defaultConstraints: + i0.GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT')); + static const i0.VerificationMeta _birthDateMeta = + const i0.VerificationMeta('birthDate'); + @override + late final i0.GeneratedColumn birthDate = + i0.GeneratedColumn('birth_date', aliasedName, false, + type: i0.DriftSqlType.dateTime, requiredDuringInsert: true); + @override + List get $columns => [id, birthDate]; + @override + String get aliasedName => _alias ?? actualTableName; + @override + String get actualTableName => $name; + static const String $name = 'users'; + @override + i0.VerificationContext validateIntegrity(i0.Insertable instance, + {bool isInserting = false}) { + final context = i0.VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } + if (data.containsKey('birth_date')) { + context.handle(_birthDateMeta, + birthDate.isAcceptableOrUnknown(data['birth_date']!, _birthDateMeta)); + } else if (isInserting) { + context.missing(_birthDateMeta); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + i1.User map(Map data, {String? tablePrefix}) { + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; + return i1.User( + id: attachedDatabase.typeMapping + .read(i0.DriftSqlType.int, data['${effectivePrefix}id'])!, + birthDate: attachedDatabase.typeMapping.read( + i0.DriftSqlType.dateTime, data['${effectivePrefix}birth_date'])!, + ); + } + + @override + $UsersTable createAlias(String alias) { + return $UsersTable(attachedDatabase, alias); + } +} + +class User extends i0.DataClass implements i0.Insertable { + final int id; + final DateTime birthDate; + const User({required this.id, required this.birthDate}); + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = i0.Variable(id); + map['birth_date'] = i0.Variable(birthDate); + return map; + } + + i1.UsersCompanion toCompanion(bool nullToAbsent) { + return i1.UsersCompanion( + id: i0.Value(id), + birthDate: i0.Value(birthDate), + ); + } + + factory User.fromJson(Map json, + {i0.ValueSerializer? serializer}) { + serializer ??= i0.driftRuntimeOptions.defaultSerializer; + return User( + id: serializer.fromJson(json['id']), + birthDate: serializer.fromJson(json['birthDate']), + ); + } + @override + Map toJson({i0.ValueSerializer? serializer}) { + serializer ??= i0.driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'birthDate': serializer.toJson(birthDate), + }; + } + + i1.User copyWith({int? id, DateTime? birthDate}) => i1.User( + id: id ?? this.id, + birthDate: birthDate ?? this.birthDate, + ); + @override + String toString() { + return (StringBuffer('User(') + ..write('id: $id, ') + ..write('birthDate: $birthDate') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, birthDate); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is i1.User && + other.id == this.id && + other.birthDate == this.birthDate); +} + +class UsersCompanion extends i0.UpdateCompanion { + final i0.Value id; + final i0.Value birthDate; + const UsersCompanion({ + this.id = const i0.Value.absent(), + this.birthDate = const i0.Value.absent(), + }); + UsersCompanion.insert({ + this.id = const i0.Value.absent(), + required DateTime birthDate, + }) : birthDate = i0.Value(birthDate); + static i0.Insertable custom({ + i0.Expression? id, + i0.Expression? birthDate, + }) { + return i0.RawValuesInsertable({ + if (id != null) 'id': id, + if (birthDate != null) 'birth_date': birthDate, + }); + } + + i1.UsersCompanion copyWith( + {i0.Value? id, i0.Value? birthDate}) { + return i1.UsersCompanion( + id: id ?? this.id, + birthDate: birthDate ?? this.birthDate, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = i0.Variable(id.value); + } + if (birthDate.present) { + map['birth_date'] = i0.Variable(birthDate.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('UsersCompanion(') + ..write('id: $id, ') + ..write('birthDate: $birthDate') + ..write(')')) + .toString(); + } +} diff --git a/docs/lib/snippets/dart_api/expressions.dart b/docs/lib/snippets/dart_api/expressions.dart index 604055cd..67ad178f 100644 --- a/docs/lib/snippets/dart_api/expressions.dart +++ b/docs/lib/snippets/dart_api/expressions.dart @@ -11,6 +11,29 @@ extension Snippets on CanUseCommonTables { return (select(categories)..where((row) => hasNoTodo)).get(); } // #enddocregion emptyCategories + + void queries() { + // #docregion date1 + select(users).where((u) => u.birthDate.year.isSmallerThanValue(1950)); + // #enddocregion date1 + } + + // #docregion date2 + Future increaseDueDates() async { + final change = TodoItemsCompanion.custom( + dueDate: todoItems.dueDate + Duration(days: 1)); + await update(todoItems).write(change); + } + // #enddocregion date2 + + // #docregion date3 + Future moveDueDateToNextMonday() async { + final change = TodoItemsCompanion.custom( + dueDate: todoItems.dueDate + .modify(DateTimeModifier.weekday(DateTime.monday))); + await update(todoItems).write(change); + } + // #enddocregion date3 } // #docregion bitwise diff --git a/docs/pages/docs/Dart API/expressions.md b/docs/pages/docs/Dart API/expressions.md index b911c104..c628e182 100644 --- a/docs/pages/docs/Dart API/expressions.md +++ b/docs/pages/docs/Dart API/expressions.md @@ -101,12 +101,12 @@ final category = coalesce([todos.category, const Constant(1)]); This corresponds to the `??` operator in Dart. ## Date and Time + For columns and expressions that return a `DateTime`, you can use the `year`, `month`, `day`, `hour`, `minute` and `second` getters to extract individual fields from that date: -```dart -select(users)..where((u) => u.birthDate.year.isLessThan(1950)) -``` + +{% include "blocks/snippet" snippets = snippets name = 'date1' %} The individual fields like `year`, `month` and so on are expressions themselves. This means that you can use operators and comparisons on them. @@ -115,10 +115,12 @@ and `currentDateAndTime` constants provided by drift. You can also use the `+` and `-` operators to add or subtract a duration from a time column: -```dart -final toNextWeek = TasksCompanion.custom(dueDate: tasks.dueDate + Duration(weeks: 1)); -update(tasks).write(toNextWeek); -``` +{% include "blocks/snippet" snippets = snippets name = 'date2' %} + +For more complex transformations of a datetime, the `modify` and `modifyAll` function is useful. +For instance, this increments every `dueDate` value for todo items to the same time on a Monday: + +{% include "blocks/snippet" snippets = snippets name = 'date3' %} ## `IN` and `NOT IN` You can check whether an expression is in a list of values by using the `isIn` and `isNotIn`