mirror of https://github.com/AMT-Cheif/drift.git
Update docs for Dart components in SQL
Scopes components are enabled by default, so the warning is no longer necessary.
This commit is contained in:
parent
48e7785491
commit
2c63c1a64e
|
@ -24,28 +24,57 @@ builders:
|
|||
release: true
|
||||
|
||||
targets:
|
||||
# We run drift and other builders first, syntax higlighting is more
|
||||
# accurate if the generated classes exist.
|
||||
source_gen:
|
||||
prepare:
|
||||
auto_apply_builders: false
|
||||
builders:
|
||||
":versions":
|
||||
enabled: true
|
||||
drift_dev:preparing_builder:
|
||||
enabled: true
|
||||
sources:
|
||||
- "$package$"
|
||||
- "lib/versions.json"
|
||||
- "lib/snippets/**"
|
||||
- "tool/write_versions.dart"
|
||||
- "tool/snippets.dart"
|
||||
- "test/generated/**"
|
||||
|
||||
codegen:
|
||||
dependencies: [":prepare"]
|
||||
auto_apply_builders: false
|
||||
builders:
|
||||
drift_dev:preparing_builder:
|
||||
enabled: false # Runs in prepare target
|
||||
|
||||
# Modular drift generation, suitable for standalone snippets that aren't part of a database
|
||||
drift_dev:analyzer:
|
||||
enabled: true
|
||||
options: &options
|
||||
generate_connect_constructor: true
|
||||
generate_for:
|
||||
include: &modular
|
||||
- "lib/snippets/modular/**"
|
||||
drift_dev:modular:
|
||||
enabled: true
|
||||
options: *options
|
||||
generate_for:
|
||||
include: *modular
|
||||
|
||||
# Non-modular drift generation. Used for some "getting started" e2e examples.
|
||||
drift_dev:drift_dev:
|
||||
enabled: true
|
||||
options:
|
||||
generate_connect_constructor: true
|
||||
options: *options
|
||||
generate_for:
|
||||
exclude: *modular
|
||||
json_serializable:
|
||||
enabled: true
|
||||
sources:
|
||||
- lib/**
|
||||
- test/generated/**
|
||||
|
||||
prepare:
|
||||
dependencies: [":source_gen"]
|
||||
syntax_highlighting:
|
||||
dependencies: [":codegen"]
|
||||
builders:
|
||||
":versions":
|
||||
enabled: true
|
||||
":code_snippets":
|
||||
enabled: true
|
||||
generate_for:
|
||||
|
@ -58,13 +87,11 @@ targets:
|
|||
auto_apply_builders: false
|
||||
sources:
|
||||
- "$package$"
|
||||
- "lib/versions.json"
|
||||
- "lib/snippets/**"
|
||||
- "tool/write_versions.dart"
|
||||
- "tool/snippets.dart"
|
||||
|
||||
$default:
|
||||
dependencies: [":prepare"]
|
||||
dependencies: [":codegen", ":syntax_highlighting"]
|
||||
builders:
|
||||
built_site:
|
||||
release_options:
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
import 'package:drift/drift.dart';
|
||||
|
||||
import 'example.drift.dart';
|
||||
|
||||
class DartExample extends ExampleDrift {
|
||||
DartExample(GeneratedDatabase attachedDatabase) : super(attachedDatabase);
|
||||
|
||||
// #docregion watchInCategory
|
||||
Stream<List<Todo>> watchInCategory(int category) {
|
||||
return filterTodos((todos) => todos.category.equals(category)).watch();
|
||||
}
|
||||
// #enddocregion watchInCategory
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
CREATE TABLE todos (
|
||||
id INT NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
title TEXT NOT NULL,
|
||||
content TEXT NOT NULL,
|
||||
category INTEGER REFERENCES categories(id)
|
||||
);
|
||||
|
||||
CREATE TABLE categories (
|
||||
id INT NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||
description TEXT NOT NULL
|
||||
) AS Category;
|
||||
|
||||
-- #docregion filterTodos
|
||||
filterTodos: SELECT * FROM todos WHERE $predicate;
|
||||
-- #enddocregion filterTodos
|
||||
-- #docregion getTodos
|
||||
getTodos ($predicate = TRUE): SELECT * FROM todos WHERE $predicate;
|
||||
-- #enddocregion getTodos
|
|
@ -0,0 +1,474 @@
|
|||
// ignore_for_file: type=lint
|
||||
import 'package:drift/drift.dart' as i0;
|
||||
import 'package:drift_docs/snippets/modular/drift/example.drift.dart' as i1;
|
||||
import 'package:drift/internal/modular.dart' as i2;
|
||||
|
||||
class Todos extends i0.Table with i0.TableInfo<Todos, i1.Todo> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Todos(this.attachedDatabase, [this._alias]);
|
||||
static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id');
|
||||
late final i0.GeneratedColumn<int> id = i0.GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: i0.DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT');
|
||||
static const i0.VerificationMeta _titleMeta =
|
||||
const i0.VerificationMeta('title');
|
||||
late final i0.GeneratedColumn<String> title = i0.GeneratedColumn<String>(
|
||||
'title', aliasedName, false,
|
||||
type: i0.DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
static const i0.VerificationMeta _contentMeta =
|
||||
const i0.VerificationMeta('content');
|
||||
late final i0.GeneratedColumn<String> content = i0.GeneratedColumn<String>(
|
||||
'content', aliasedName, false,
|
||||
type: i0.DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
static const i0.VerificationMeta _categoryMeta =
|
||||
const i0.VerificationMeta('category');
|
||||
late final i0.GeneratedColumn<int> category = i0.GeneratedColumn<int>(
|
||||
'category', aliasedName, true,
|
||||
type: i0.DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'REFERENCES categories(id)');
|
||||
@override
|
||||
List<i0.GeneratedColumn> get $columns => [id, title, content, category];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'todos';
|
||||
@override
|
||||
String get actualTableName => 'todos';
|
||||
@override
|
||||
i0.VerificationContext validateIntegrity(i0.Insertable<i1.Todo> 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('title')) {
|
||||
context.handle(
|
||||
_titleMeta, title.isAcceptableOrUnknown(data['title']!, _titleMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_titleMeta);
|
||||
}
|
||||
if (data.containsKey('content')) {
|
||||
context.handle(_contentMeta,
|
||||
content.isAcceptableOrUnknown(data['content']!, _contentMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_contentMeta);
|
||||
}
|
||||
if (data.containsKey('category')) {
|
||||
context.handle(_categoryMeta,
|
||||
category.isAcceptableOrUnknown(data['category']!, _categoryMeta));
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<i0.GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
i1.Todo map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return i1.Todo(
|
||||
id: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}id'])!,
|
||||
title: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}title'])!,
|
||||
content: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}content'])!,
|
||||
category: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}category']),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Todos createAlias(String alias) {
|
||||
return Todos(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class Todo extends i0.DataClass implements i0.Insertable<i1.Todo> {
|
||||
final int id;
|
||||
final String title;
|
||||
final String content;
|
||||
final int? category;
|
||||
const Todo(
|
||||
{required this.id,
|
||||
required this.title,
|
||||
required this.content,
|
||||
this.category});
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
map['id'] = i0.Variable<int>(id);
|
||||
map['title'] = i0.Variable<String>(title);
|
||||
map['content'] = i0.Variable<String>(content);
|
||||
if (!nullToAbsent || category != null) {
|
||||
map['category'] = i0.Variable<int>(category);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
i1.TodosCompanion toCompanion(bool nullToAbsent) {
|
||||
return i1.TodosCompanion(
|
||||
id: i0.Value(id),
|
||||
title: i0.Value(title),
|
||||
content: i0.Value(content),
|
||||
category: category == null && nullToAbsent
|
||||
? const i0.Value.absent()
|
||||
: i0.Value(category),
|
||||
);
|
||||
}
|
||||
|
||||
factory Todo.fromJson(Map<String, dynamic> json,
|
||||
{i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return Todo(
|
||||
id: serializer.fromJson<int>(json['id']),
|
||||
title: serializer.fromJson<String>(json['title']),
|
||||
content: serializer.fromJson<String>(json['content']),
|
||||
category: serializer.fromJson<int?>(json['category']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'id': serializer.toJson<int>(id),
|
||||
'title': serializer.toJson<String>(title),
|
||||
'content': serializer.toJson<String>(content),
|
||||
'category': serializer.toJson<int?>(category),
|
||||
};
|
||||
}
|
||||
|
||||
i1.Todo copyWith(
|
||||
{int? id,
|
||||
String? title,
|
||||
String? content,
|
||||
i0.Value<int?> category = const i0.Value.absent()}) =>
|
||||
i1.Todo(
|
||||
id: id ?? this.id,
|
||||
title: title ?? this.title,
|
||||
content: content ?? this.content,
|
||||
category: category.present ? category.value : this.category,
|
||||
);
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('Todo(')
|
||||
..write('id: $id, ')
|
||||
..write('title: $title, ')
|
||||
..write('content: $content, ')
|
||||
..write('category: $category')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, title, content, category);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is i1.Todo &&
|
||||
other.id == this.id &&
|
||||
other.title == this.title &&
|
||||
other.content == this.content &&
|
||||
other.category == this.category);
|
||||
}
|
||||
|
||||
class TodosCompanion extends i0.UpdateCompanion<i1.Todo> {
|
||||
final i0.Value<int> id;
|
||||
final i0.Value<String> title;
|
||||
final i0.Value<String> content;
|
||||
final i0.Value<int?> category;
|
||||
const TodosCompanion({
|
||||
this.id = const i0.Value.absent(),
|
||||
this.title = const i0.Value.absent(),
|
||||
this.content = const i0.Value.absent(),
|
||||
this.category = const i0.Value.absent(),
|
||||
});
|
||||
TodosCompanion.insert({
|
||||
this.id = const i0.Value.absent(),
|
||||
required String title,
|
||||
required String content,
|
||||
this.category = const i0.Value.absent(),
|
||||
}) : title = i0.Value(title),
|
||||
content = i0.Value(content);
|
||||
static i0.Insertable<i1.Todo> custom({
|
||||
i0.Expression<int>? id,
|
||||
i0.Expression<String>? title,
|
||||
i0.Expression<String>? content,
|
||||
i0.Expression<int>? category,
|
||||
}) {
|
||||
return i0.RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
if (title != null) 'title': title,
|
||||
if (content != null) 'content': content,
|
||||
if (category != null) 'category': category,
|
||||
});
|
||||
}
|
||||
|
||||
i1.TodosCompanion copyWith(
|
||||
{i0.Value<int>? id,
|
||||
i0.Value<String>? title,
|
||||
i0.Value<String>? content,
|
||||
i0.Value<int?>? category}) {
|
||||
return i1.TodosCompanion(
|
||||
id: id ?? this.id,
|
||||
title: title ?? this.title,
|
||||
content: content ?? this.content,
|
||||
category: category ?? this.category,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
if (id.present) {
|
||||
map['id'] = i0.Variable<int>(id.value);
|
||||
}
|
||||
if (title.present) {
|
||||
map['title'] = i0.Variable<String>(title.value);
|
||||
}
|
||||
if (content.present) {
|
||||
map['content'] = i0.Variable<String>(content.value);
|
||||
}
|
||||
if (category.present) {
|
||||
map['category'] = i0.Variable<int>(category.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('i1.TodosCompanion(')
|
||||
..write('id: $id, ')
|
||||
..write('title: $title, ')
|
||||
..write('content: $content, ')
|
||||
..write('category: $category')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class Categories extends i0.Table with i0.TableInfo<Categories, i1.Category> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
Categories(this.attachedDatabase, [this._alias]);
|
||||
static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id');
|
||||
late final i0.GeneratedColumn<int> id = i0.GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: i0.DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'NOT NULL PRIMARY KEY AUTOINCREMENT');
|
||||
static const i0.VerificationMeta _descriptionMeta =
|
||||
const i0.VerificationMeta('description');
|
||||
late final i0.GeneratedColumn<String> description =
|
||||
i0.GeneratedColumn<String>('description', aliasedName, false,
|
||||
type: i0.DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
@override
|
||||
List<i0.GeneratedColumn> get $columns => [id, description];
|
||||
@override
|
||||
String get aliasedName => _alias ?? 'categories';
|
||||
@override
|
||||
String get actualTableName => 'categories';
|
||||
@override
|
||||
i0.VerificationContext validateIntegrity(i0.Insertable<i1.Category> 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('description')) {
|
||||
context.handle(
|
||||
_descriptionMeta,
|
||||
description.isAcceptableOrUnknown(
|
||||
data['description']!, _descriptionMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_descriptionMeta);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<i0.GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
i1.Category map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return i1.Category(
|
||||
id: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}id'])!,
|
||||
description: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}description'])!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Categories createAlias(String alias) {
|
||||
return Categories(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class Category extends i0.DataClass implements i0.Insertable<i1.Category> {
|
||||
final int id;
|
||||
final String description;
|
||||
const Category({required this.id, required this.description});
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
map['id'] = i0.Variable<int>(id);
|
||||
map['description'] = i0.Variable<String>(description);
|
||||
return map;
|
||||
}
|
||||
|
||||
i1.CategoriesCompanion toCompanion(bool nullToAbsent) {
|
||||
return i1.CategoriesCompanion(
|
||||
id: i0.Value(id),
|
||||
description: i0.Value(description),
|
||||
);
|
||||
}
|
||||
|
||||
factory Category.fromJson(Map<String, dynamic> json,
|
||||
{i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return Category(
|
||||
id: serializer.fromJson<int>(json['id']),
|
||||
description: serializer.fromJson<String>(json['description']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'id': serializer.toJson<int>(id),
|
||||
'description': serializer.toJson<String>(description),
|
||||
};
|
||||
}
|
||||
|
||||
i1.Category copyWith({int? id, String? description}) => i1.Category(
|
||||
id: id ?? this.id,
|
||||
description: description ?? this.description,
|
||||
);
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('Category(')
|
||||
..write('id: $id, ')
|
||||
..write('description: $description')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, description);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is i1.Category &&
|
||||
other.id == this.id &&
|
||||
other.description == this.description);
|
||||
}
|
||||
|
||||
class CategoriesCompanion extends i0.UpdateCompanion<i1.Category> {
|
||||
final i0.Value<int> id;
|
||||
final i0.Value<String> description;
|
||||
const CategoriesCompanion({
|
||||
this.id = const i0.Value.absent(),
|
||||
this.description = const i0.Value.absent(),
|
||||
});
|
||||
CategoriesCompanion.insert({
|
||||
this.id = const i0.Value.absent(),
|
||||
required String description,
|
||||
}) : description = i0.Value(description);
|
||||
static i0.Insertable<i1.Category> custom({
|
||||
i0.Expression<int>? id,
|
||||
i0.Expression<String>? description,
|
||||
}) {
|
||||
return i0.RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
if (description != null) 'description': description,
|
||||
});
|
||||
}
|
||||
|
||||
i1.CategoriesCompanion copyWith(
|
||||
{i0.Value<int>? id, i0.Value<String>? description}) {
|
||||
return i1.CategoriesCompanion(
|
||||
id: id ?? this.id,
|
||||
description: description ?? this.description,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
if (id.present) {
|
||||
map['id'] = i0.Variable<int>(id.value);
|
||||
}
|
||||
if (description.present) {
|
||||
map['description'] = i0.Variable<String>(description.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('i1.CategoriesCompanion(')
|
||||
..write('id: $id, ')
|
||||
..write('description: $description')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
class ExampleDrift extends i2.ModularAccessor {
|
||||
ExampleDrift(i0.GeneratedDatabase db) : super(db);
|
||||
i0.Selectable<i1.Todo> filterTodos(FilterTodos$predicate predicate) {
|
||||
var $arrayStartIndex = 1;
|
||||
final generatedpredicate =
|
||||
$write(predicate(this.todos), startIndex: $arrayStartIndex);
|
||||
$arrayStartIndex += generatedpredicate.amountOfVariables;
|
||||
return customSelect('SELECT * FROM todos WHERE ${generatedpredicate.sql}',
|
||||
variables: [
|
||||
...generatedpredicate.introducedVariables
|
||||
],
|
||||
readsFrom: {
|
||||
todos,
|
||||
...generatedpredicate.watchedTables,
|
||||
}).asyncMap(todos.mapFromRow);
|
||||
}
|
||||
|
||||
i0.Selectable<i1.Todo> getTodos({GetTodos$predicate? predicate}) {
|
||||
var $arrayStartIndex = 1;
|
||||
final generatedpredicate = $write(
|
||||
predicate?.call(this.todos) ?? const i0.CustomExpression('(TRUE)'),
|
||||
startIndex: $arrayStartIndex);
|
||||
$arrayStartIndex += generatedpredicate.amountOfVariables;
|
||||
return customSelect('SELECT * FROM todos WHERE ${generatedpredicate.sql}',
|
||||
variables: [
|
||||
...generatedpredicate.introducedVariables
|
||||
],
|
||||
readsFrom: {
|
||||
todos,
|
||||
...generatedpredicate.watchedTables,
|
||||
}).asyncMap(todos.mapFromRow);
|
||||
}
|
||||
|
||||
i1.Todos get todos => this.resultSet<i1.Todos>('todos');
|
||||
}
|
||||
|
||||
typedef FilterTodos$predicate = i0.Expression<bool> Function(i1.Todos todos);
|
||||
typedef GetTodos$predicate = i0.Expression<bool> Function(i1.Todos todos);
|
|
@ -15,6 +15,9 @@ template: layouts/docs/single
|
|||
{% assign drift_tables = "package:drift_docs/snippets/drift_files/tables.drift.excerpt.json" | readString | json_decode %}
|
||||
{% assign small = "package:drift_docs/snippets/drift_files/small_snippets.drift.excerpt.json" | readString | json_decode %}
|
||||
|
||||
{% assign newDrift = "package:drift_docs/snippets/modular/drift/example.drift.excerpt.json" | readString | json_decode %}
|
||||
{% assign newDart = "package:drift_docs/snippets/modular/drift/dart_example.dart.excerpt.json" | readString | json_decode %}
|
||||
|
||||
Drift files are a new feature that lets you write all your database code in SQL.
|
||||
But unlike raw SQL strings you might pass to simple database clients, everything in a drift file is verified
|
||||
by drift's powerful SQL analyzer.
|
||||
|
@ -291,16 +294,14 @@ would generate a column serialized as "userId" in json.
|
|||
You can make most of both SQL and Dart with "Dart Templates", which is a
|
||||
Dart expression that gets inlined to a query at runtime. To use them, declare a
|
||||
$-variable in a query:
|
||||
```sql
|
||||
_filterTodos: SELECT * FROM todos WHERE $predicate;
|
||||
```
|
||||
Drift will generate a `Selectable<Todo> _filterTodos(Expression<bool> predicate)`
|
||||
method that can be used to construct dynamic filters at runtime:
|
||||
```dart
|
||||
Stream<List<Todo>> watchInCategory(int category) {
|
||||
return _filterTodos(todos.category.equals(category)).watch();
|
||||
}
|
||||
```
|
||||
|
||||
{% include "blocks/snippet" snippets = newDrift name = "filterTodos" %}
|
||||
|
||||
Drift will generate a `Selectable<Todo>` method with a `predicate` parameter that
|
||||
can be used to construct dynamic filters at runtime:
|
||||
|
||||
{% include "blocks/snippet" snippets = newDart name = "watchInCategory" %}
|
||||
|
||||
This lets you write a single SQL query and dynamically apply a predicate at runtime!
|
||||
This feature works for
|
||||
|
||||
|
@ -314,46 +315,11 @@ This feature works for
|
|||
|
||||
When used as expression, you can also supply a default value in your query:
|
||||
|
||||
```sql
|
||||
_filterTodos ($predicate = TRUE): SELECT * FROM todos WHERE $predicate;
|
||||
```
|
||||
{% include "blocks/snippet" snippets = newDrift name = "getTodos" %}
|
||||
|
||||
This will make the `predicate` parameter optional in Dart. It will use the
|
||||
default SQL value (here, `TRUE`) when not explicitly set.
|
||||
|
||||
{% block "blocks/alert" title="Using column names in Dart" color="warning" %}
|
||||
If your query uses table aliases, you'll need to account for that when embedding Dart
|
||||
expressions in your SQL query. Consider this for instance:
|
||||
|
||||
```sql
|
||||
findRoutes: SELECT r.* FROM routes r
|
||||
INNER JOIN points "start" ON "start".id = r."start"
|
||||
INNER JOIN points "end" ON "end".id = r."end"
|
||||
WHERE $predicate
|
||||
```
|
||||
|
||||
If you want to filter for the `start` point in Dart, you have to use
|
||||
an explicit [`alias`](https://pub.dev/documentation/drift/latest/drift/DatabaseConnectionUser/alias.html):
|
||||
|
||||
```dart
|
||||
Future<List<Route>> routesByStart(int startPointId) {
|
||||
final start = alias(points, 'start');
|
||||
return findRoutes(start.id.equals(startPointId));
|
||||
}
|
||||
```
|
||||
|
||||
You can enable the `scoped_dart_components` [build option]({{ '../Advanced Features/builder_options.md' | pageUrl }})
|
||||
and let the generator help you here.
|
||||
When the option is enabled, drift would generate a `Expression<bool> Function(Routes r, Points start, Points end)` as a parameter, which
|
||||
makes this a lot easier:
|
||||
|
||||
```dart
|
||||
Future<List<Route>> routesByStart(int startPointId) {
|
||||
return findRoutes((r, start, end) => start.id.equals(startPointId));
|
||||
}
|
||||
```
|
||||
{% endblock %}
|
||||
|
||||
### Type converters
|
||||
|
||||
You can import and use [type converters]({{ "../Advanced Features/type_converters.md" | pageUrl }})
|
||||
|
|
|
@ -14,7 +14,7 @@ dependencies:
|
|||
version: ^0.2.2
|
||||
code_snippets:
|
||||
hosted: https://simonbinder.eu
|
||||
version: ^0.0.8
|
||||
version: ^0.0.11
|
||||
# used in snippets
|
||||
http: ^0.13.5
|
||||
sqlite3: ^1.7.2
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
{% assign excerpt = args.name | default: '(full)' %}
|
||||
<pre>
|
||||
<code class="hljs">{{ args.snippets | get: excerpt }}</code>
|
||||
</pre>
|
||||
<pre><code class="hljs">{{ args.snippets | get: excerpt }}</code></pre>
|
||||
|
|
|
@ -339,7 +339,7 @@ class _DriftBuildRun {
|
|||
);
|
||||
writer = Writer(options, generationOptions: generationOptions);
|
||||
} else {
|
||||
final imports = LibraryInputManager();
|
||||
final imports = LibraryInputManager(buildStep.allowedOutputs.single.uri);
|
||||
final generationOptions = GenerationOptions(
|
||||
imports: imports,
|
||||
isModular: true,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:path/path.dart' show url;
|
||||
|
||||
import '../utils/string_escaper.dart';
|
||||
import 'writer.dart';
|
||||
|
||||
|
@ -16,9 +18,16 @@ class LibraryInputManager extends ImportManager {
|
|||
static final _dartCore = Uri.parse('dart:core');
|
||||
|
||||
final Map<Uri, String> _importAliases = {};
|
||||
|
||||
/// The uri of the file being generated.
|
||||
///
|
||||
/// This allows constructing relative imports for assets that aren't in
|
||||
/// `lib/`.
|
||||
final Uri? _outputUri;
|
||||
|
||||
TextEmitter? emitter;
|
||||
|
||||
LibraryInputManager();
|
||||
LibraryInputManager([this._outputUri]);
|
||||
|
||||
void linkToWriter(Writer writer) {
|
||||
emitter = writer.leaf();
|
||||
|
@ -33,8 +42,20 @@ class LibraryInputManager extends ImportManager {
|
|||
return _importAliases.putIfAbsent(definitionUri, () {
|
||||
final alias = 'i${_importAliases.length}';
|
||||
|
||||
emitter?.writeln(
|
||||
'import ${asDartLiteral(definitionUri.toString())} as $alias;');
|
||||
final importedScheme = definitionUri.scheme;
|
||||
String importLiteral;
|
||||
|
||||
if (importedScheme != 'package' &&
|
||||
importedScheme != 'dart' &&
|
||||
importedScheme == _outputUri?.scheme) {
|
||||
// Not a package nor a dart import, use a relative import instead
|
||||
importLiteral = url.relative(definitionUri.path,
|
||||
from: url.dirname(_outputUri!.path));
|
||||
} else {
|
||||
importLiteral = definitionUri.toString();
|
||||
}
|
||||
|
||||
emitter?.writeln('import ${asDartLiteral(importLiteral)} as $alias;');
|
||||
return alias;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import 'package:build/build.dart';
|
||||
import 'package:drift_dev/src/analysis/options.dart';
|
||||
import 'package:drift_dev/src/analysis/results/results.dart';
|
||||
import 'package:drift_dev/src/writer/import_manager.dart';
|
||||
import 'package:drift_dev/src/writer/writer.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
group('LibraryInputManager', () {
|
||||
final sourceUri = AssetId('a', 'example/main.dart').uri;
|
||||
|
||||
late LibraryInputManager imports;
|
||||
late Writer writer;
|
||||
|
||||
setUp(() {
|
||||
imports = LibraryInputManager(sourceUri);
|
||||
final generationOptions =
|
||||
GenerationOptions(imports: imports, isModular: true);
|
||||
writer = Writer(const DriftOptions.defaults(),
|
||||
generationOptions: generationOptions);
|
||||
imports.linkToWriter(writer);
|
||||
});
|
||||
|
||||
test('does not generate prefix for dart:core', () {
|
||||
expect(imports.prefixFor(Uri.parse('dart:core'), 'String'), isNull);
|
||||
});
|
||||
|
||||
test('writes imports', () {
|
||||
expect(imports.prefixFor(AnnotatedDartCode.dartAsync, 'Future'), 'i0');
|
||||
expect(imports.prefixFor(AnnotatedDartCode.drift, 'GeneratedDatabase'),
|
||||
'i1');
|
||||
expect(imports.prefixFor(AnnotatedDartCode.dartAsync, 'Stream'), 'i0');
|
||||
|
||||
expect(writer.writeGenerated(), '''
|
||||
import 'dart:async' as i0;
|
||||
import 'package:drift/drift.dart' as i1;
|
||||
''');
|
||||
});
|
||||
|
||||
test('can write imports for files outside of lib', () {
|
||||
final uri = AssetId('a', 'example/imported.dart').uri;
|
||||
expect(imports.prefixFor(uri, 'Test'), 'i0');
|
||||
|
||||
expect(
|
||||
writer.writeGenerated(), contains("import 'imported.dart' as i0;"));
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue