-
Notifications
You must be signed in to change notification settings - Fork 377
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Simplify n:m example with json functions
- Loading branch information
Showing
8 changed files
with
1,068 additions
and
50 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,139 @@ | ||
import 'package:drift/drift.dart'; | ||
import 'package:drift/extensions/json1.dart'; | ||
import 'package:json_annotation/json_annotation.dart'; | ||
|
||
import 'json.drift.dart'; | ||
import 'shared.dart' show BuyableItems; | ||
import 'shared.drift.dart'; | ||
|
||
part 'json.g.dart'; | ||
|
||
typedef ShoppingCartWithItems = ({ | ||
ShoppingCart cart, | ||
List<BuyableItem> items, | ||
}); | ||
|
||
// #docregion tables | ||
@DataClassName('ShoppingCart') | ||
class ShoppingCarts extends Table { | ||
IntColumn get id => integer().autoIncrement()(); | ||
TextColumn get entries => text().map(ShoppingCartEntries.converter)(); | ||
|
||
// we could also store some further information about the user creating | ||
// this cart etc. | ||
} | ||
|
||
@JsonSerializable() | ||
class ShoppingCartEntries { | ||
final List<int> items; | ||
|
||
ShoppingCartEntries({required this.items}); | ||
|
||
factory ShoppingCartEntries.fromJson(Map<String, Object?> json) => | ||
_$ShoppingCartEntriesFromJson(json); | ||
|
||
Map<String, Object?> toJson() { | ||
return _$ShoppingCartEntriesToJson(this); | ||
} | ||
|
||
static JsonTypeConverter<ShoppingCartEntries, String> converter = | ||
TypeConverter.json( | ||
fromJson: (json) => | ||
ShoppingCartEntries.fromJson(json as Map<String, Object?>), | ||
toJson: (entries) => entries.toJson(), | ||
); | ||
} | ||
|
||
// #enddocregion tables | ||
|
||
@DriftDatabase(tables: [BuyableItems, ShoppingCarts]) | ||
class JsonBasedDatabase extends $JsonBasedDatabase { | ||
JsonBasedDatabase(QueryExecutor e) : super(e); | ||
|
||
@override | ||
int get schemaVersion => 1; | ||
|
||
// #docregion createEmptyCart | ||
Future<ShoppingCartWithItems> createEmptyCart() async { | ||
final cart = await into(shoppingCarts) | ||
.insertReturning(const ShoppingCartsCompanion()); | ||
|
||
// we set the items property to [] because we've just created the cart - it | ||
// will be empty | ||
return (cart: cart, items: <BuyableItem>[]); | ||
} | ||
// #enddocregion createEmptyCart | ||
|
||
// #docregion updateCart | ||
Future<void> updateCart(ShoppingCartWithItems entry) async { | ||
await update(shoppingCarts).replace(entry.cart.copyWith( | ||
entries: ShoppingCartEntries(items: [ | ||
for (final item in entry.items) item.id, | ||
]))); | ||
} | ||
// #enddocregion updateCart | ||
|
||
// #docregion watchCart | ||
Stream<ShoppingCartWithItems> watchCart(int id) { | ||
final referencedItems = shoppingCarts.entries.jsonEach(this, r'#$.items'); | ||
|
||
final cartWithEntries = select(shoppingCarts).join( | ||
[ | ||
// Join every referenced item from the json array | ||
innerJoin(referencedItems, const Constant(true), useColumns: false), | ||
// And use that to join the items | ||
innerJoin( | ||
buyableItems, | ||
buyableItems.id.equalsExp(referencedItems.value.cast()), | ||
), | ||
], | ||
)..where(shoppingCarts.id.equals(id)); | ||
|
||
return cartWithEntries.watch().map((rows) { | ||
late ShoppingCart cart; | ||
final entries = <BuyableItem>[]; | ||
|
||
for (final row in rows) { | ||
cart = row.readTable(shoppingCarts); | ||
entries.add(row.readTable(buyableItems)); | ||
} | ||
|
||
return (cart: cart, items: entries); | ||
}); | ||
} | ||
// #enddocregion watchCart | ||
|
||
// #docregion watchAllCarts | ||
Stream<List<ShoppingCartWithItems>> watchAllCarts() { | ||
final referencedItems = shoppingCarts.entries.jsonEach(this, r'#$.items'); | ||
|
||
final cartWithEntries = select(shoppingCarts).join( | ||
[ | ||
// Join every referenced item from the json array | ||
innerJoin(referencedItems, const Constant(true), useColumns: false), | ||
// And use that to join the items | ||
innerJoin( | ||
buyableItems, | ||
buyableItems.id.equalsExp(referencedItems.value.cast()), | ||
), | ||
], | ||
); | ||
|
||
return cartWithEntries.watch().map((rows) { | ||
final entriesByCart = <ShoppingCart, List<BuyableItem>>{}; | ||
|
||
for (final row in rows) { | ||
final cart = row.readTable(shoppingCarts); | ||
final item = row.readTable(buyableItems); | ||
|
||
entriesByCart.putIfAbsent(cart, () => []).add(item); | ||
} | ||
|
||
return [ | ||
for (final entry in entriesByCart.entries) | ||
(cart: entry.key, items: entry.value) | ||
]; | ||
}); | ||
} | ||
// #enddocregion watchAllCarts | ||
} |
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,203 @@ | ||
// ignore_for_file: type=lint | ||
import 'package:drift/drift.dart' as i0; | ||
import 'package:drift_docs/snippets/modular/many_to_many/shared.drift.dart' | ||
as i1; | ||
import 'package:drift_docs/snippets/modular/many_to_many/json.drift.dart' as i2; | ||
import 'package:drift_docs/snippets/modular/many_to_many/json.dart' as i3; | ||
|
||
abstract class $JsonBasedDatabase extends i0.GeneratedDatabase { | ||
$JsonBasedDatabase(i0.QueryExecutor e) : super(e); | ||
late final i1.$BuyableItemsTable buyableItems = i1.$BuyableItemsTable(this); | ||
late final i2.$ShoppingCartsTable shoppingCarts = | ||
i2.$ShoppingCartsTable(this); | ||
@override | ||
Iterable<i0.TableInfo<i0.Table, Object?>> get allTables => | ||
allSchemaEntities.whereType<i0.TableInfo<i0.Table, Object?>>(); | ||
@override | ||
List<i0.DatabaseSchemaEntity> get allSchemaEntities => | ||
[buyableItems, shoppingCarts]; | ||
} | ||
|
||
class $ShoppingCartsTable extends i3.ShoppingCarts | ||
with i0.TableInfo<$ShoppingCartsTable, i2.ShoppingCart> { | ||
@override | ||
final i0.GeneratedDatabase attachedDatabase; | ||
final String? _alias; | ||
$ShoppingCartsTable(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 _entriesMeta = | ||
const i0.VerificationMeta('entries'); | ||
@override | ||
late final i0.GeneratedColumnWithTypeConverter<i3.ShoppingCartEntries, String> | ||
entries = i0.GeneratedColumn<String>('entries', aliasedName, false, | ||
type: i0.DriftSqlType.string, requiredDuringInsert: true) | ||
.withConverter<i3.ShoppingCartEntries>( | ||
i2.$ShoppingCartsTable.$converterentries); | ||
@override | ||
List<i0.GeneratedColumn> get $columns => [id, entries]; | ||
@override | ||
String get aliasedName => _alias ?? actualTableName; | ||
@override | ||
String get actualTableName => $name; | ||
static const String $name = 'shopping_carts'; | ||
@override | ||
i0.VerificationContext validateIntegrity( | ||
i0.Insertable<i2.ShoppingCart> 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)); | ||
} | ||
context.handle(_entriesMeta, const i0.VerificationResult.success()); | ||
return context; | ||
} | ||
|
||
@override | ||
Set<i0.GeneratedColumn> get $primaryKey => {id}; | ||
@override | ||
i2.ShoppingCart map(Map<String, dynamic> data, {String? tablePrefix}) { | ||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; | ||
return i2.ShoppingCart( | ||
id: attachedDatabase.typeMapping | ||
.read(i0.DriftSqlType.int, data['${effectivePrefix}id'])!, | ||
entries: i2.$ShoppingCartsTable.$converterentries.fromSql(attachedDatabase | ||
.typeMapping | ||
.read(i0.DriftSqlType.string, data['${effectivePrefix}entries'])!), | ||
); | ||
} | ||
|
||
@override | ||
$ShoppingCartsTable createAlias(String alias) { | ||
return $ShoppingCartsTable(attachedDatabase, alias); | ||
} | ||
|
||
static i0.JsonTypeConverter2<i3.ShoppingCartEntries, String, String> | ||
$converterentries = i3.ShoppingCartEntries.converter; | ||
} | ||
|
||
class ShoppingCart extends i0.DataClass | ||
implements i0.Insertable<i2.ShoppingCart> { | ||
final int id; | ||
final i3.ShoppingCartEntries entries; | ||
const ShoppingCart({required this.id, required this.entries}); | ||
@override | ||
Map<String, i0.Expression> toColumns(bool nullToAbsent) { | ||
final map = <String, i0.Expression>{}; | ||
map['id'] = i0.Variable<int>(id); | ||
{ | ||
final converter = i2.$ShoppingCartsTable.$converterentries; | ||
map['entries'] = i0.Variable<String>(converter.toSql(entries)); | ||
} | ||
return map; | ||
} | ||
|
||
i2.ShoppingCartsCompanion toCompanion(bool nullToAbsent) { | ||
return i2.ShoppingCartsCompanion( | ||
id: i0.Value(id), | ||
entries: i0.Value(entries), | ||
); | ||
} | ||
|
||
factory ShoppingCart.fromJson(Map<String, dynamic> json, | ||
{i0.ValueSerializer? serializer}) { | ||
serializer ??= i0.driftRuntimeOptions.defaultSerializer; | ||
return ShoppingCart( | ||
id: serializer.fromJson<int>(json['id']), | ||
entries: i2.$ShoppingCartsTable.$converterentries | ||
.fromJson(serializer.fromJson<String>(json['entries'])), | ||
); | ||
} | ||
@override | ||
Map<String, dynamic> toJson({i0.ValueSerializer? serializer}) { | ||
serializer ??= i0.driftRuntimeOptions.defaultSerializer; | ||
return <String, dynamic>{ | ||
'id': serializer.toJson<int>(id), | ||
'entries': serializer.toJson<String>( | ||
i2.$ShoppingCartsTable.$converterentries.toJson(entries)), | ||
}; | ||
} | ||
|
||
i2.ShoppingCart copyWith({int? id, i3.ShoppingCartEntries? entries}) => | ||
i2.ShoppingCart( | ||
id: id ?? this.id, | ||
entries: entries ?? this.entries, | ||
); | ||
@override | ||
String toString() { | ||
return (StringBuffer('ShoppingCart(') | ||
..write('id: $id, ') | ||
..write('entries: $entries') | ||
..write(')')) | ||
.toString(); | ||
} | ||
|
||
@override | ||
int get hashCode => Object.hash(id, entries); | ||
@override | ||
bool operator ==(Object other) => | ||
identical(this, other) || | ||
(other is i2.ShoppingCart && | ||
other.id == this.id && | ||
other.entries == this.entries); | ||
} | ||
|
||
class ShoppingCartsCompanion extends i0.UpdateCompanion<i2.ShoppingCart> { | ||
final i0.Value<int> id; | ||
final i0.Value<i3.ShoppingCartEntries> entries; | ||
const ShoppingCartsCompanion({ | ||
this.id = const i0.Value.absent(), | ||
this.entries = const i0.Value.absent(), | ||
}); | ||
ShoppingCartsCompanion.insert({ | ||
this.id = const i0.Value.absent(), | ||
required i3.ShoppingCartEntries entries, | ||
}) : entries = i0.Value(entries); | ||
static i0.Insertable<i2.ShoppingCart> custom({ | ||
i0.Expression<int>? id, | ||
i0.Expression<String>? entries, | ||
}) { | ||
return i0.RawValuesInsertable({ | ||
if (id != null) 'id': id, | ||
if (entries != null) 'entries': entries, | ||
}); | ||
} | ||
|
||
i2.ShoppingCartsCompanion copyWith( | ||
{i0.Value<int>? id, i0.Value<i3.ShoppingCartEntries>? entries}) { | ||
return i2.ShoppingCartsCompanion( | ||
id: id ?? this.id, | ||
entries: entries ?? this.entries, | ||
); | ||
} | ||
|
||
@override | ||
Map<String, i0.Expression> toColumns(bool nullToAbsent) { | ||
final map = <String, i0.Expression>{}; | ||
if (id.present) { | ||
map['id'] = i0.Variable<int>(id.value); | ||
} | ||
if (entries.present) { | ||
final converter = i2.$ShoppingCartsTable.$converterentries; | ||
map['entries'] = i0.Variable<String>(converter.toSql(entries.value)); | ||
} | ||
return map; | ||
} | ||
|
||
@override | ||
String toString() { | ||
return (StringBuffer('ShoppingCartsCompanion(') | ||
..write('id: $id, ') | ||
..write('entries: $entries') | ||
..write(')')) | ||
.toString(); | ||
} | ||
} |
Oops, something went wrong.