mirror of https://github.com/AMT-Cheif/drift.git
Document custom types
This commit is contained in:
parent
7f0488056c
commit
28130fd3f1
|
@ -0,0 +1,7 @@
|
|||
import 'type.dart';
|
||||
|
||||
CREATE TABLE periodic_reminders (
|
||||
id INTEGER NOT NULL PRIMARY KEY,
|
||||
frequency `const DurationType()` NOT NULL,
|
||||
reminder TEXT NOT NULL
|
||||
);
|
|
@ -0,0 +1,223 @@
|
|||
// ignore_for_file: type=lint
|
||||
import 'package:drift/drift.dart' as i0;
|
||||
import 'package:drift_docs/snippets/modular/custom_types/drift_table.drift.dart'
|
||||
as i1;
|
||||
import 'package:drift_docs/snippets/modular/custom_types/type.dart' as i2;
|
||||
|
||||
class PeriodicReminders extends i0.Table
|
||||
with i0.TableInfo<PeriodicReminders, i1.PeriodicReminder> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
PeriodicReminders(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,
|
||||
type: i0.DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
$customConstraints: 'NOT NULL PRIMARY KEY');
|
||||
static const i0.VerificationMeta _frequencyMeta =
|
||||
const i0.VerificationMeta('frequency');
|
||||
late final i0.GeneratedColumn<Duration> frequency =
|
||||
i0.GeneratedColumn<Duration>('frequency', aliasedName, false,
|
||||
type: const i2.DurationType(),
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
static const i0.VerificationMeta _reminderMeta =
|
||||
const i0.VerificationMeta('reminder');
|
||||
late final i0.GeneratedColumn<String> reminder = i0.GeneratedColumn<String>(
|
||||
'reminder', aliasedName, false,
|
||||
type: i0.DriftSqlType.string,
|
||||
requiredDuringInsert: true,
|
||||
$customConstraints: 'NOT NULL');
|
||||
@override
|
||||
List<i0.GeneratedColumn> get $columns => [id, frequency, reminder];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'periodic_reminders';
|
||||
@override
|
||||
i0.VerificationContext validateIntegrity(
|
||||
i0.Insertable<i1.PeriodicReminder> 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('frequency')) {
|
||||
context.handle(_frequencyMeta,
|
||||
frequency.isAcceptableOrUnknown(data['frequency']!, _frequencyMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_frequencyMeta);
|
||||
}
|
||||
if (data.containsKey('reminder')) {
|
||||
context.handle(_reminderMeta,
|
||||
reminder.isAcceptableOrUnknown(data['reminder']!, _reminderMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_reminderMeta);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<i0.GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
i1.PeriodicReminder map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return i1.PeriodicReminder(
|
||||
id: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}id'])!,
|
||||
frequency: attachedDatabase.typeMapping
|
||||
.read(const i2.DurationType(), data['${effectivePrefix}frequency'])!,
|
||||
reminder: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}reminder'])!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
PeriodicReminders createAlias(String alias) {
|
||||
return PeriodicReminders(attachedDatabase, alias);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get dontWriteConstraints => true;
|
||||
}
|
||||
|
||||
class PeriodicReminder extends i0.DataClass
|
||||
implements i0.Insertable<i1.PeriodicReminder> {
|
||||
final int id;
|
||||
final Duration frequency;
|
||||
final String reminder;
|
||||
const PeriodicReminder(
|
||||
{required this.id, required this.frequency, required this.reminder});
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
map['id'] = i0.Variable<int>(id);
|
||||
map['frequency'] = i0.Variable<Duration>(frequency);
|
||||
map['reminder'] = i0.Variable<String>(reminder);
|
||||
return map;
|
||||
}
|
||||
|
||||
i1.PeriodicRemindersCompanion toCompanion(bool nullToAbsent) {
|
||||
return i1.PeriodicRemindersCompanion(
|
||||
id: i0.Value(id),
|
||||
frequency: i0.Value(frequency),
|
||||
reminder: i0.Value(reminder),
|
||||
);
|
||||
}
|
||||
|
||||
factory PeriodicReminder.fromJson(Map<String, dynamic> json,
|
||||
{i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return PeriodicReminder(
|
||||
id: serializer.fromJson<int>(json['id']),
|
||||
frequency: serializer.fromJson<Duration>(json['frequency']),
|
||||
reminder: serializer.fromJson<String>(json['reminder']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'id': serializer.toJson<int>(id),
|
||||
'frequency': serializer.toJson<Duration>(frequency),
|
||||
'reminder': serializer.toJson<String>(reminder),
|
||||
};
|
||||
}
|
||||
|
||||
i1.PeriodicReminder copyWith(
|
||||
{int? id, Duration? frequency, String? reminder}) =>
|
||||
i1.PeriodicReminder(
|
||||
id: id ?? this.id,
|
||||
frequency: frequency ?? this.frequency,
|
||||
reminder: reminder ?? this.reminder,
|
||||
);
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('PeriodicReminder(')
|
||||
..write('id: $id, ')
|
||||
..write('frequency: $frequency, ')
|
||||
..write('reminder: $reminder')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, frequency, reminder);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is i1.PeriodicReminder &&
|
||||
other.id == this.id &&
|
||||
other.frequency == this.frequency &&
|
||||
other.reminder == this.reminder);
|
||||
}
|
||||
|
||||
class PeriodicRemindersCompanion
|
||||
extends i0.UpdateCompanion<i1.PeriodicReminder> {
|
||||
final i0.Value<int> id;
|
||||
final i0.Value<Duration> frequency;
|
||||
final i0.Value<String> reminder;
|
||||
const PeriodicRemindersCompanion({
|
||||
this.id = const i0.Value.absent(),
|
||||
this.frequency = const i0.Value.absent(),
|
||||
this.reminder = const i0.Value.absent(),
|
||||
});
|
||||
PeriodicRemindersCompanion.insert({
|
||||
this.id = const i0.Value.absent(),
|
||||
required Duration frequency,
|
||||
required String reminder,
|
||||
}) : frequency = i0.Value(frequency),
|
||||
reminder = i0.Value(reminder);
|
||||
static i0.Insertable<i1.PeriodicReminder> custom({
|
||||
i0.Expression<int>? id,
|
||||
i0.Expression<Duration>? frequency,
|
||||
i0.Expression<String>? reminder,
|
||||
}) {
|
||||
return i0.RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
if (frequency != null) 'frequency': frequency,
|
||||
if (reminder != null) 'reminder': reminder,
|
||||
});
|
||||
}
|
||||
|
||||
i1.PeriodicRemindersCompanion copyWith(
|
||||
{i0.Value<int>? id,
|
||||
i0.Value<Duration>? frequency,
|
||||
i0.Value<String>? reminder}) {
|
||||
return i1.PeriodicRemindersCompanion(
|
||||
id: id ?? this.id,
|
||||
frequency: frequency ?? this.frequency,
|
||||
reminder: reminder ?? this.reminder,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
if (id.present) {
|
||||
map['id'] = i0.Variable<int>(id.value);
|
||||
}
|
||||
if (frequency.present) {
|
||||
map['frequency'] =
|
||||
i0.Variable<Duration>(frequency.value, const i2.DurationType());
|
||||
}
|
||||
if (reminder.present) {
|
||||
map['reminder'] = i0.Variable<String>(reminder.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('PeriodicRemindersCompanion(')
|
||||
..write('id: $id, ')
|
||||
..write('frequency: $frequency, ')
|
||||
..write('reminder: $reminder')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
import 'package:drift/drift.dart';
|
||||
import 'type.dart';
|
||||
|
||||
class PeriodicReminders extends Table {
|
||||
IntColumn get id => integer().autoIncrement()();
|
||||
Column<Duration> get frequency => customType(const DurationType())
|
||||
.clientDefault(() => Duration(minutes: 15))();
|
||||
TextColumn get reminder => text()();
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
// ignore_for_file: type=lint
|
||||
import 'package:drift/drift.dart' as i0;
|
||||
import 'package:drift_docs/snippets/modular/custom_types/table.drift.dart'
|
||||
as i1;
|
||||
import 'package:drift_docs/snippets/modular/custom_types/type.dart' as i2;
|
||||
import 'package:drift_docs/snippets/modular/custom_types/table.dart' as i3;
|
||||
|
||||
class $PeriodicRemindersTable extends i3.PeriodicReminders
|
||||
with i0.TableInfo<$PeriodicRemindersTable, i1.PeriodicReminder> {
|
||||
@override
|
||||
final i0.GeneratedDatabase attachedDatabase;
|
||||
final String? _alias;
|
||||
$PeriodicRemindersTable(this.attachedDatabase, [this._alias]);
|
||||
static const i0.VerificationMeta _idMeta = const i0.VerificationMeta('id');
|
||||
@override
|
||||
late final i0.GeneratedColumn<int> id = i0.GeneratedColumn<int>(
|
||||
'id', aliasedName, false,
|
||||
hasAutoIncrement: true,
|
||||
type: i0.DriftSqlType.int,
|
||||
requiredDuringInsert: false,
|
||||
defaultConstraints:
|
||||
i0.GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
|
||||
static const i0.VerificationMeta _frequencyMeta =
|
||||
const i0.VerificationMeta('frequency');
|
||||
@override
|
||||
late final i0.GeneratedColumn<Duration> frequency =
|
||||
i0.GeneratedColumn<Duration>('frequency', aliasedName, false,
|
||||
type: const i2.DurationType(),
|
||||
requiredDuringInsert: false,
|
||||
clientDefault: () => Duration(minutes: 15));
|
||||
static const i0.VerificationMeta _reminderMeta =
|
||||
const i0.VerificationMeta('reminder');
|
||||
@override
|
||||
late final i0.GeneratedColumn<String> reminder = i0.GeneratedColumn<String>(
|
||||
'reminder', aliasedName, false,
|
||||
type: i0.DriftSqlType.string, requiredDuringInsert: true);
|
||||
@override
|
||||
List<i0.GeneratedColumn> get $columns => [id, frequency, reminder];
|
||||
@override
|
||||
String get aliasedName => _alias ?? actualTableName;
|
||||
@override
|
||||
String get actualTableName => $name;
|
||||
static const String $name = 'periodic_reminders';
|
||||
@override
|
||||
i0.VerificationContext validateIntegrity(
|
||||
i0.Insertable<i1.PeriodicReminder> 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('frequency')) {
|
||||
context.handle(_frequencyMeta,
|
||||
frequency.isAcceptableOrUnknown(data['frequency']!, _frequencyMeta));
|
||||
}
|
||||
if (data.containsKey('reminder')) {
|
||||
context.handle(_reminderMeta,
|
||||
reminder.isAcceptableOrUnknown(data['reminder']!, _reminderMeta));
|
||||
} else if (isInserting) {
|
||||
context.missing(_reminderMeta);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@override
|
||||
Set<i0.GeneratedColumn> get $primaryKey => {id};
|
||||
@override
|
||||
i1.PeriodicReminder map(Map<String, dynamic> data, {String? tablePrefix}) {
|
||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
|
||||
return i1.PeriodicReminder(
|
||||
id: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.int, data['${effectivePrefix}id'])!,
|
||||
frequency: attachedDatabase.typeMapping
|
||||
.read(const i2.DurationType(), data['${effectivePrefix}frequency'])!,
|
||||
reminder: attachedDatabase.typeMapping
|
||||
.read(i0.DriftSqlType.string, data['${effectivePrefix}reminder'])!,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
$PeriodicRemindersTable createAlias(String alias) {
|
||||
return $PeriodicRemindersTable(attachedDatabase, alias);
|
||||
}
|
||||
}
|
||||
|
||||
class PeriodicReminder extends i0.DataClass
|
||||
implements i0.Insertable<i1.PeriodicReminder> {
|
||||
final int id;
|
||||
final Duration frequency;
|
||||
final String reminder;
|
||||
const PeriodicReminder(
|
||||
{required this.id, required this.frequency, required this.reminder});
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
map['id'] = i0.Variable<int>(id);
|
||||
map['frequency'] = i0.Variable<Duration>(frequency);
|
||||
map['reminder'] = i0.Variable<String>(reminder);
|
||||
return map;
|
||||
}
|
||||
|
||||
i1.PeriodicRemindersCompanion toCompanion(bool nullToAbsent) {
|
||||
return i1.PeriodicRemindersCompanion(
|
||||
id: i0.Value(id),
|
||||
frequency: i0.Value(frequency),
|
||||
reminder: i0.Value(reminder),
|
||||
);
|
||||
}
|
||||
|
||||
factory PeriodicReminder.fromJson(Map<String, dynamic> json,
|
||||
{i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return PeriodicReminder(
|
||||
id: serializer.fromJson<int>(json['id']),
|
||||
frequency: serializer.fromJson<Duration>(json['frequency']),
|
||||
reminder: serializer.fromJson<String>(json['reminder']),
|
||||
);
|
||||
}
|
||||
@override
|
||||
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) {
|
||||
serializer ??= i0.driftRuntimeOptions.defaultSerializer;
|
||||
return <String, dynamic>{
|
||||
'id': serializer.toJson<int>(id),
|
||||
'frequency': serializer.toJson<Duration>(frequency),
|
||||
'reminder': serializer.toJson<String>(reminder),
|
||||
};
|
||||
}
|
||||
|
||||
i1.PeriodicReminder copyWith(
|
||||
{int? id, Duration? frequency, String? reminder}) =>
|
||||
i1.PeriodicReminder(
|
||||
id: id ?? this.id,
|
||||
frequency: frequency ?? this.frequency,
|
||||
reminder: reminder ?? this.reminder,
|
||||
);
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('PeriodicReminder(')
|
||||
..write('id: $id, ')
|
||||
..write('frequency: $frequency, ')
|
||||
..write('reminder: $reminder')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(id, frequency, reminder);
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
(other is i1.PeriodicReminder &&
|
||||
other.id == this.id &&
|
||||
other.frequency == this.frequency &&
|
||||
other.reminder == this.reminder);
|
||||
}
|
||||
|
||||
class PeriodicRemindersCompanion
|
||||
extends i0.UpdateCompanion<i1.PeriodicReminder> {
|
||||
final i0.Value<int> id;
|
||||
final i0.Value<Duration> frequency;
|
||||
final i0.Value<String> reminder;
|
||||
const PeriodicRemindersCompanion({
|
||||
this.id = const i0.Value.absent(),
|
||||
this.frequency = const i0.Value.absent(),
|
||||
this.reminder = const i0.Value.absent(),
|
||||
});
|
||||
PeriodicRemindersCompanion.insert({
|
||||
this.id = const i0.Value.absent(),
|
||||
this.frequency = const i0.Value.absent(),
|
||||
required String reminder,
|
||||
}) : reminder = i0.Value(reminder);
|
||||
static i0.Insertable<i1.PeriodicReminder> custom({
|
||||
i0.Expression<int>? id,
|
||||
i0.Expression<Duration>? frequency,
|
||||
i0.Expression<String>? reminder,
|
||||
}) {
|
||||
return i0.RawValuesInsertable({
|
||||
if (id != null) 'id': id,
|
||||
if (frequency != null) 'frequency': frequency,
|
||||
if (reminder != null) 'reminder': reminder,
|
||||
});
|
||||
}
|
||||
|
||||
i1.PeriodicRemindersCompanion copyWith(
|
||||
{i0.Value<int>? id,
|
||||
i0.Value<Duration>? frequency,
|
||||
i0.Value<String>? reminder}) {
|
||||
return i1.PeriodicRemindersCompanion(
|
||||
id: id ?? this.id,
|
||||
frequency: frequency ?? this.frequency,
|
||||
reminder: reminder ?? this.reminder,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, i0.Expression> toColumns(bool nullToAbsent) {
|
||||
final map = <String, i0.Expression>{};
|
||||
if (id.present) {
|
||||
map['id'] = i0.Variable<int>(id.value);
|
||||
}
|
||||
if (frequency.present) {
|
||||
map['frequency'] =
|
||||
i0.Variable<Duration>(frequency.value, const i2.DurationType());
|
||||
}
|
||||
if (reminder.present) {
|
||||
map['reminder'] = i0.Variable<String>(reminder.value);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return (StringBuffer('PeriodicRemindersCompanion(')
|
||||
..write('id: $id, ')
|
||||
..write('frequency: $frequency, ')
|
||||
..write('reminder: $reminder')
|
||||
..write(')'))
|
||||
.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import 'package:drift/drift.dart';
|
||||
|
||||
class DurationType implements CustomSqlType<Duration> {
|
||||
const DurationType();
|
||||
|
||||
@override
|
||||
String mapToSqlLiteral(Duration dartValue) {
|
||||
return "interval '${dartValue.inMicroseconds} microseconds'";
|
||||
}
|
||||
|
||||
@override
|
||||
Object mapToSqlParameter(Duration dartValue) => dartValue;
|
||||
|
||||
@override
|
||||
Duration read(Object fromSql) => fromSql as Duration;
|
||||
|
||||
@override
|
||||
String sqlTypeName(GenerationContext context) => 'interval';
|
||||
}
|
|
@ -187,6 +187,7 @@ class ShoppingCartsCompanion extends i0.UpdateCompanion<i2.ShoppingCart> {
|
|||
}
|
||||
if (entries.present) {
|
||||
final converter = i2.$ShoppingCartsTable.$converterentries;
|
||||
|
||||
map['entries'] = i0.Variable<String>(converter.toSql(entries.value));
|
||||
}
|
||||
return map;
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
---
|
||||
data:
|
||||
title: "Custom SQL types"
|
||||
weight: 10
|
||||
description: Use custom SQL types in Drift files and Dart code.
|
||||
|
||||
template: layouts/docs/single
|
||||
---
|
||||
|
||||
Drift's core library is written with sqlite3 as a primary target. This is
|
||||
reflected in the [SQL types][types] drift supports out of the box - these
|
||||
types supported by sqlite3 with a few additions that are handled in Dart.
|
||||
|
||||
Other databases for which drift has limited support commonly support more types.
|
||||
For instance, postgres has a dedicated type for durations, JSON values, UUIDs
|
||||
and more. With a sqlite3 database, you'd use a [type converter][type converters]
|
||||
to store these values with the types supported by sqlite3.
|
||||
While type converters can also work here, they tell drift to use a regular text
|
||||
column under the hood. When a database has builtin support for UUIDs for instance,
|
||||
this could lead to less efficient statements or issues with other applications
|
||||
talking to same database.
|
||||
For this reason, drift allows the use of "custom types" - types that are not defined
|
||||
in the core `drift` package and don't work with all databases.
|
||||
|
||||
{% block "blocks/alert" title="When to use custom types - summary" %}
|
||||
Custom types are a good tool when extending drift support to new database engines
|
||||
with their own types not already covered by drift.
|
||||
|
||||
Unless you're extending drift to work with a new database package (which is awesome,
|
||||
please reach out!), you probably don't need to implement custom types yourself.
|
||||
Packages like `drift_postgres` already define relevant custom types for you.
|
||||
{% endblock %}
|
||||
|
||||
## Defining a type
|
||||
|
||||
As an example, let's assume we have a database with native support for `Duration`
|
||||
values via the `interval` type. We're using a database driver that also has native
|
||||
support for `Duration` values, meaning that they can be passed to the database in
|
||||
prepared statements and also be read from rows without manual conversions.
|
||||
|
||||
In that case, a custom type class to implement `Duration` support for drift would be
|
||||
added:
|
||||
|
||||
{% include "blocks/snippet" snippets = ('package:drift_docs/snippets/modular/custom_types/type.dart.excerpt.json' | readString | json_decode) %}
|
||||
|
||||
This type defines the following things:
|
||||
|
||||
- When `Duration` values are mapped to SQL literals (for instance, because they're used in `Constant`s),
|
||||
we represent them as `interval '123754 microseconds'` in SQL.
|
||||
- When a `Duration` value is mapped to a parameter, we just use the value directly (since we
|
||||
assume it is supported by the underlying database driver here).
|
||||
- Similarly, we expect that the database driver correctly returns durations as instances of
|
||||
`Duration`, so the other way around in `read` also just casts the value.
|
||||
- The name to use in `CREATE TABLE` statements and casts is `interval`.
|
||||
|
||||
## Using custom types
|
||||
|
||||
### In Dart
|
||||
|
||||
To define a custom type on a Dart table, use the `customType` column builder method with the type:
|
||||
|
||||
{% include "blocks/snippet" snippets = ('package:drift_docs/snippets/modular/custom_types/table.dart.excerpt.json' | readString | json_decode) %}
|
||||
|
||||
As the example shows, other column constraints like `clientDefault` can still be added to custom
|
||||
columns. You can even combine custom columns and type converters if needed.
|
||||
|
||||
This is enough to get most queries to work, but in some advanced scenarios you may have to provide
|
||||
more information to use custom types.
|
||||
For instance, when manually constructing a `Variable` or a `Constant` with a custom type, the custom
|
||||
type must be added as a second parameter to the constructor. This is because, unlike for builtin types,
|
||||
drift doesn't have a central register describing how to deal with custom type values.
|
||||
|
||||
### In SQL
|
||||
|
||||
In SQL, Drift's [inline Dart]({{ 'drift_files.md#dart-interop' | pageUrl }}) syntax may be used to define
|
||||
the custom type:
|
||||
|
||||
{% include "blocks/snippet" snippets = ('package:drift_docs/snippets/modular/custom_types/drift_table.drift.excerpt.json' | readString | json_decode) %}
|
||||
|
||||
Please note that support for custom types in drift files is currently limited.
|
||||
For instance, custom types are not currently supported in `CAST` expressions.
|
||||
If you are interested in advanced analysis support for custom types, please reach out by
|
||||
opening an issue or a discussion describing your use-cases, thanks!
|
||||
|
||||
[types]: {{ '../Dart API/tables.md#supported-column-types' | pageUrl }}
|
||||
[type converters]: {{ '../type_converters.md' | pageUrl }}
|
|
@ -197,6 +197,13 @@ abstract class Table extends HasResultSet {
|
|||
@protected
|
||||
ColumnBuilder<double> real() => _isGenerated();
|
||||
|
||||
/// Defines a column with a custom [type] when used as a getter.
|
||||
///
|
||||
/// For more information on custom types and when they can be useful, see
|
||||
/// https://drift.simonbinder.eu/docs/sql-api/types/.
|
||||
///
|
||||
/// For most users, [TypeConverter]s are a more appropriate tool to store
|
||||
/// custom values in the database.
|
||||
@protected
|
||||
ColumnBuilder<T> customType<T extends Object>(CustomSqlType<T> type) =>
|
||||
_isGenerated();
|
||||
|
|
|
@ -407,6 +407,8 @@ enum DriftSqlType<T extends Object> implements BaseSqlType<T> {
|
|||
/// To create a custom type, implement this interface. You can now create values
|
||||
/// of this type by passing it to [Constant] or [Variable], [Expression.cast]
|
||||
/// and other methods operating on types.
|
||||
/// Custom types can also be applied to table columns, see https://drift.simonbinder.eu/docs/sql-api/types/
|
||||
/// for details.
|
||||
abstract interface class CustomSqlType<T extends Object>
|
||||
implements BaseSqlType<T> {
|
||||
/// Interprets the underlying [fromSql] value from the database driver into
|
||||
|
|
Loading…
Reference in New Issue