-
Notifications
You must be signed in to change notification settings - Fork 365
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
11 changed files
with
444 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// #docregion existing | ||
import 'dart:convert'; | ||
|
||
import 'package:drift/drift.dart'; | ||
import 'package:drift/extensions/json1.dart'; | ||
import 'package:json_annotation/json_annotation.dart'; | ||
|
||
// #enddocregion existing | ||
import 'package:drift/native.dart'; | ||
|
||
part 'json.g.dart'; | ||
|
||
// #docregion existing | ||
@JsonSerializable() | ||
class ContactData { | ||
final String name; | ||
final List<String> phoneNumbers; | ||
|
||
ContactData(this.name, this.phoneNumbers); | ||
|
||
factory ContactData.fromJson(Map<String, Object?> json) => | ||
_$ContactDataFromJson(json); | ||
|
||
Map<String, Object?> toJson() => _$ContactDataToJson(this); | ||
} | ||
// #enddocregion existing | ||
|
||
// #docregion contacts | ||
class _ContactsConverter extends TypeConverter<ContactData, String> { | ||
@override | ||
ContactData fromSql(String fromDb) { | ||
return ContactData.fromJson(json.decode(fromDb) as Map<String, Object?>); | ||
} | ||
|
||
@override | ||
String toSql(ContactData value) { | ||
return json.encode(value.toJson()); | ||
} | ||
} | ||
|
||
class Contacts extends Table { | ||
IntColumn get id => integer().autoIncrement()(); | ||
TextColumn get data => text().map(_ContactsConverter())(); | ||
|
||
TextColumn get name => text().generatedAs(data.jsonExtract(r'$.name'))(); | ||
} | ||
// #enddocregion contacts | ||
|
||
// #docregion calls | ||
class Calls extends Table { | ||
IntColumn get id => integer().autoIncrement()(); | ||
BoolColumn get incoming => boolean()(); | ||
TextColumn get phoneNumber => text()(); | ||
DateTimeColumn get callTime => dateTime()(); | ||
} | ||
// #enddocregion calls | ||
|
||
@DriftDatabase(tables: [Contacts, Calls]) | ||
class MyDatabase extends _$MyDatabase { | ||
MyDatabase() : super(NativeDatabase.memory()); | ||
|
||
@override | ||
int get schemaVersion => 1; | ||
|
||
// #docregion calls-with-contacts | ||
Future<List<(Call, Contact)>> callsWithContact() async { | ||
final phoneNumbersForContact = | ||
contacts.data.jsonEach(this, r'$.phoneNumbers'); | ||
final phoneNumberQuery = selectOnly(phoneNumbersForContact) | ||
..addColumns([phoneNumbersForContact.value]); | ||
|
||
final query = select(calls).join( | ||
[innerJoin(contacts, calls.phoneNumber.isInQuery(phoneNumberQuery))]); | ||
|
||
return query | ||
.map((row) => (row.readTable(calls), row.readTable(contacts))) | ||
.get(); | ||
} | ||
// #enddocregion calls-with-contacts | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
100 changes: 100 additions & 0 deletions
100
drift/lib/src/runtime/query_builder/components/table_valued_function.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:meta/meta.dart'; | ||
|
||
import '../../../dsl/dsl.dart'; | ||
import '../../api/runtime_api.dart'; | ||
import '../../utils.dart'; | ||
import '../query_builder.dart'; | ||
|
||
/// In sqlite3, a table-valued function is a function that resolves to a result | ||
/// set, meaning that it can be selected from. | ||
/// | ||
/// For more information on table-valued functions in general, visit their | ||
/// [documentation](https://sqlite.org/vtab.html#tabfunc2) on the sqlite website. | ||
/// | ||
/// This class is meant to be extended for each table-valued function, so that | ||
/// the [Self] type parameter points to the actual implementation class. The | ||
/// class must also implement [createAlias] correctly (ensuring that every | ||
/// column has its [GeneratedColumn.tableName] set to the [aliasedName]). | ||
/// | ||
/// For an example of a table-valued function in drift, see the | ||
/// `JsonTableFunction` in `package:drift/json1.dart`. It makes the `json_each` | ||
/// and `json_tree` table-valued functions available to drift. | ||
@experimental | ||
abstract base class TableValuedFunction<Self extends ResultSetImplementation> | ||
extends ResultSetImplementation<Self, TypedResult> | ||
implements HasResultSet, Component { | ||
final String _functionName; | ||
|
||
/// The arguments passed to the table-valued function. | ||
final List<Expression> arguments; | ||
|
||
@override | ||
final DatabaseConnectionUser attachedDatabase; | ||
|
||
@override | ||
final List<GeneratedColumn<Object>> $columns; | ||
|
||
@override | ||
final String aliasedName; | ||
|
||
/// Constructor for table-valued functions. | ||
/// | ||
/// This takes the [attachedDatabase] (used to interpret results), the name | ||
/// of the function as well as arguments passed to it and finally the schema | ||
/// of the table (in the form of [columns]). | ||
TableValuedFunction( | ||
this.attachedDatabase, { | ||
required String functionName, | ||
required this.arguments, | ||
required List<GeneratedColumn> columns, | ||
String? alias, | ||
}) : _functionName = functionName, | ||
$columns = columns, | ||
aliasedName = alias ?? functionName; | ||
|
||
@override | ||
Self get asDslTable => this as Self; | ||
|
||
@override | ||
late final Map<String, GeneratedColumn<Object>> columnsByName = { | ||
for (final column in $columns) column.name: column, | ||
}; | ||
|
||
@override | ||
String get entityName => _functionName; | ||
|
||
@override | ||
FutureOr<TypedResult> map(Map<String, dynamic> data, {String? tablePrefix}) { | ||
final row = QueryRow(data.withoutPrefix(tablePrefix), attachedDatabase); | ||
return TypedResult( | ||
const {}, | ||
row, | ||
{ | ||
for (final column in $columns) | ||
column: attachedDatabase.typeMapping | ||
.read(column.type, row.data[column.name]), | ||
}, | ||
); | ||
} | ||
|
||
@override | ||
void writeInto(GenerationContext context) { | ||
context.buffer | ||
..write(_functionName) | ||
..write('('); | ||
|
||
var first = true; | ||
for (final argument in arguments) { | ||
if (!first) { | ||
context.buffer.write(', '); | ||
} | ||
|
||
argument.writeInto(context); | ||
first = false; | ||
} | ||
|
||
context.buffer.write(')'); | ||
} | ||
} |
Oops, something went wrong.