Created
July 1, 2019 14:08
-
-
Save jaumard/5e777dbd1f2090a7d859061aa2165f5d to your computer and use it in GitHub Desktop.
immutable jaguar models
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
import 'dart:io'; | |
import 'package:jaguar_query_postgres/jaguar_query_postgres.dart'; | |
import 'models.dart'; | |
/// The adapter | |
final adapter = PgAdapter('postgres', username: 'postgres', password: 'postgres'); | |
main() async { | |
// Create beans | |
await adapter.connect(); | |
final cartBean = CartBean(adapter); | |
final cartItemBean = CartItemBean(adapter); | |
await cartItemBean.drop(); | |
await cartBean.drop(); | |
await cartBean.createTable(ifNotExists: true); | |
await cartItemBean.createTable(ifNotExists: true); | |
final cart = Cart( | |
extId: 1, | |
id: 3, | |
amount: 12, | |
items: [ | |
CartItem(amount: 12, description: 'test'), | |
], | |
modified: 1); | |
final carts = await cartBean.getAll(); | |
print(carts); | |
await cartBean.insert(cart, cascade: true); | |
final carts2 = await cartBean.getAll(); | |
final preloadedCarts = await cartBean.preloadAll(carts2); | |
print(preloadedCarts); | |
await cartBean.update(Cart( | |
extId: preloadedCarts[0].extId, | |
id: preloadedCarts[0].id, | |
amount: preloadedCarts[0].amount, | |
items: [ | |
CartItem( | |
id: preloadedCarts[0].items[0].id, | |
amount: 66, | |
quantity: preloadedCarts[0].items[0].quantity, | |
product: preloadedCarts[0].items[0].product, | |
description: preloadedCarts[0].items[0].description + ' updated', | |
cartId: preloadedCarts[0].items[0].cartId, | |
) | |
], | |
modified: 2, | |
), cascade: true); | |
final updatedCart = await cartBean.find(cart.extId, preload: true, cascade: true); | |
print(updatedCart); | |
exit(0); | |
} |
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
import 'package:jaguar_query/jaguar_query.dart'; | |
import 'package:jaguar_orm/jaguar_orm.dart'; | |
part 'models.jorm.dart'; | |
class Cart { | |
static const int currentCartId = 1; | |
@Column(isNullable: true) | |
final int id; | |
@PrimaryKey(isNullable: false) | |
final int extId; | |
@HasMany(CartItemBean) | |
final List<CartItem> items; | |
@Column() | |
final int amount; | |
@Column() | |
final int modified; | |
Cart({this.extId, this.amount = 0, this.id, this.modified, this.items = const <CartItem>[]}); | |
Cart copy({id, extId, int amount, List<CartItem> items, modified, transactionId}) { | |
return Cart( | |
id: id ?? this.id, | |
extId: extId ?? this.extId, | |
modified: modified ?? this.modified, | |
amount: amount ?? this.amount, | |
items: items ?? this.items, | |
); | |
} | |
@override | |
String toString() { | |
return 'Cart{id: $id, extId: $extId, items: $items, amount: $amount, modified: $modified}'; | |
} | |
} | |
class CartItem { | |
@PrimaryKey(auto: true) | |
final int id; | |
@Column() | |
final int amount; | |
@Column(isNullable: true) | |
final int product; | |
@Column() | |
final int quantity; | |
@Column(isNullable: true) | |
final String description; | |
@BelongsTo(CartBean, refCol: 'extId', byHasMany: true) | |
final int cartId; | |
CartItem({this.amount, this.quantity = 1, this.description, this.product, this.id, this.cartId}); | |
CartItem copy({id, int cartId, String description, int quantity, int product, int amount}) { | |
return CartItem( | |
amount: amount ?? this.amount, | |
product: product ?? this.product, | |
quantity: quantity ?? this.quantity, | |
id: id ?? this.id, | |
description: description ?? this.description, | |
cartId: cartId ?? this.cartId, | |
); | |
} | |
@override | |
String toString() { | |
return 'CartItem{id: $id, amount: $amount, product: $product, quantity: $quantity, description: $description, cartId: $cartId}'; | |
} | |
} | |
@GenBean() | |
class CartItemBean extends Bean<CartItem> with _CartItemBean { | |
CartItemBean(Adapter adapter) : super(adapter); | |
CartBean _cartBean; | |
@override | |
String get tableName => 'cartItem'; | |
@override | |
CartBean get cartBean => _cartBean ??= CartBean(adapter); | |
} | |
@GenBean() | |
class CartBean extends Bean<Cart> with _CartBean { | |
CartBean(Adapter adapter) : super(adapter); | |
CartItemBean _cartItemBean; | |
@override | |
String get tableName => 'cart'; | |
@override | |
CartItemBean get cartItemBean => _cartItemBean ??= CartItemBean(adapter); | |
} |
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
part of 'models.dart'; | |
abstract class _CartBean implements Bean<Cart> { | |
final id = IntField('id'); | |
final extId = IntField('ext_id'); | |
final amount = IntField('amount'); | |
final modified = IntField('modified'); | |
Map<String, Field> _fields; | |
Map<String, Field> get fields => _fields ??= { | |
id.name: id, | |
extId.name: extId, | |
amount.name: amount, | |
modified.name: modified, | |
}; | |
Cart fromMap(Map map) { | |
Cart model = Cart( | |
id: adapter.parseValue(map['id']), | |
extId: adapter.parseValue(map['ext_id']), | |
amount: adapter.parseValue(map['amount']), | |
modified: adapter.parseValue(map['modified']), | |
); | |
return model; | |
} | |
List<SetColumn> toSetColumns(Cart model, {bool update = false, Set<String> only, bool onlyNonNull = false}) { | |
List<SetColumn> ret = []; | |
if (only == null && !onlyNonNull) { | |
ret.add(id.set(model.id)); | |
ret.add(extId.set(model.extId)); | |
ret.add(amount.set(model.amount)); | |
ret.add(modified.set(model.modified)); | |
} else if (only != null) { | |
if (only.contains(id.name)) ret.add(id.set(model.id)); | |
if (only.contains(extId.name)) ret.add(extId.set(model.extId)); | |
if (only.contains(amount.name)) ret.add(amount.set(model.amount)); | |
if (only.contains(modified.name)) ret.add(modified.set(model.modified)); | |
} else | |
/* if (onlyNonNull) */ { | |
if (model.id != null) { | |
ret.add(id.set(model.id)); | |
} | |
if (model.extId != null) { | |
ret.add(extId.set(model.extId)); | |
} | |
if (model.amount != null) { | |
ret.add(amount.set(model.amount)); | |
} | |
if (model.modified != null) { | |
ret.add(modified.set(model.modified)); | |
} | |
} | |
return ret; | |
} | |
Future<void> createTable({bool ifNotExists = false}) async { | |
final st = Sql.create(tableName, ifNotExists: ifNotExists); | |
st.addInt(id.name, isNullable: true); | |
st.addInt(extId.name, primary: true, isNullable: false); | |
st.addInt(amount.name, isNullable: false); | |
st.addInt(modified.name, isNullable: false); | |
return adapter.createTable(st); | |
} | |
Future<dynamic> insert(Cart model, {bool cascade = false, bool onlyNonNull = false, Set<String> only}) async { | |
final Insert insert = inserter.setMany(toSetColumns(model, only: only, onlyNonNull: onlyNonNull)); | |
var retId = await adapter.insert(insert); | |
if (cascade) { | |
Cart newModel; | |
if (model.items != null) { | |
newModel ??= await find(model.extId); | |
final items = model.items.map((x) => cartItemBean.associateCart(x, newModel)); | |
for (final child in items) { | |
await cartItemBean.insert(child, cascade: cascade); | |
} | |
} | |
} | |
return retId; | |
} | |
Future<void> insertMany(List<Cart> models, {bool cascade = false, bool onlyNonNull = false, Set<String> only}) async { | |
if (cascade) { | |
final List<Future> futures = []; | |
for (var model in models) { | |
futures.add(insert(model, cascade: cascade)); | |
} | |
await Future.wait(futures); | |
return; | |
} else { | |
final List<List<SetColumn>> data = models.map((model) => toSetColumns(model, only: only, onlyNonNull: onlyNonNull)).toList(); | |
final InsertMany insert = inserters.addAll(data); | |
await adapter.insertMany(insert); | |
return; | |
} | |
} | |
Future<dynamic> upsert(Cart model, {bool cascade = false, Set<String> only, bool onlyNonNull = false}) async { | |
final Upsert upsert = upserter.setMany(toSetColumns(model, only: only, onlyNonNull: onlyNonNull)); | |
var retId = await adapter.upsert(upsert); | |
if (cascade) { | |
Cart newModel; | |
if (model.items != null) { | |
newModel ??= await find(model.extId); | |
final items = model.items.map((x) => cartItemBean.associateCart(x, newModel)); | |
for (final child in items) { | |
await cartItemBean.upsert(child, cascade: cascade); | |
} | |
} | |
} | |
return retId; | |
} | |
Future<void> upsertMany(List<Cart> models, {bool cascade = false, bool onlyNonNull = false, Set<String> only}) async { | |
if (cascade) { | |
final List<Future> futures = []; | |
for (var model in models) { | |
futures.add(upsert(model, cascade: cascade)); | |
} | |
await Future.wait(futures); | |
return; | |
} else { | |
final List<List<SetColumn>> data = []; | |
for (var i = 0; i < models.length; ++i) { | |
var model = models[i]; | |
data.add(toSetColumns(model, only: only, onlyNonNull: onlyNonNull).toList()); | |
} | |
final UpsertMany upsert = upserters.addAll(data); | |
await adapter.upsertMany(upsert); | |
return; | |
} | |
} | |
Future<int> update(Cart model, {bool cascade = false, bool associate = false, Set<String> only, bool onlyNonNull = false}) async { | |
final Update update = updater.where(this.extId.eq(model.extId)).setMany(toSetColumns(model, only: only, onlyNonNull: onlyNonNull)); | |
final ret = adapter.update(update); | |
if (cascade) { | |
Cart newModel; | |
if (model.items != null) { | |
if (associate) { | |
newModel ??= await find(model.extId); | |
model.items.forEach((x) => cartItemBean.associateCart(x, newModel)); | |
} | |
for (final child in model.items) { | |
await cartItemBean.update(child, cascade: cascade, associate: associate); | |
} | |
} | |
} | |
return ret; | |
} | |
Future<void> updateMany(List<Cart> models, {bool cascade = false, bool onlyNonNull = false, Set<String> only}) async { | |
if (cascade) { | |
final List<Future> futures = []; | |
for (var model in models) { | |
futures.add(update(model, cascade: cascade)); | |
} | |
await Future.wait(futures); | |
return; | |
} else { | |
final List<List<SetColumn>> data = []; | |
final List<Expression> where = []; | |
for (var i = 0; i < models.length; ++i) { | |
var model = models[i]; | |
data.add(toSetColumns(model, only: only, onlyNonNull: onlyNonNull).toList()); | |
where.add(this.extId.eq(model.extId)); | |
} | |
final UpdateMany update = updaters.addAll(data, where); | |
await adapter.updateMany(update); | |
return; | |
} | |
} | |
Future<Cart> find(int extId, {bool preload = false, bool cascade = false}) async { | |
final Find find = finder.where(this.extId.eq(extId)); | |
Cart model = await findOne(find); | |
if (preload && model != null) { | |
model = await this.preload(model, cascade: cascade); | |
} | |
return model; | |
} | |
Future<int> remove(int extId, {bool cascade = false}) async { | |
if (cascade) { | |
final Cart newModel = await find(extId); | |
if (newModel != null) { | |
await cartItemBean.removeByCart(newModel.extId); | |
} | |
} | |
final Remove remove = remover.where(this.extId.eq(extId)); | |
return adapter.remove(remove); | |
} | |
Future<int> removeMany(List<Cart> models) async { | |
// Return if models is empty. If this is not done, all records will be removed! | |
if (models == null || models.isEmpty) return 0; | |
final Remove remove = remover; | |
for (final model in models) { | |
remove.or(this.extId.eq(model.extId)); | |
} | |
return adapter.remove(remove); | |
} | |
Future<Cart> preload(Cart model, {bool cascade = false}) async { | |
final items = await cartItemBean.findByCart(model.extId, preload: cascade, cascade: cascade); | |
return Cart( | |
items: items, | |
extId: model.extId, | |
id: model.id, | |
amount: model.amount, | |
modified: model.modified, | |
); | |
} | |
Future<List<Cart>> preloadAll(List<Cart> models, {bool cascade = false}) async { | |
List<Cart> preloadedModels = []; | |
await OneToXHelper.preloadAll<Cart, CartItem>( | |
models, | |
(Cart model) => [model.extId], | |
cartItemBean.findByCartList, | |
(CartItem model) => [model.cartId], | |
(Cart model, CartItem child) { | |
preloadedModels.add(Cart( | |
items: List.from(model.items)..add(child), | |
extId: model.extId, | |
id: model.id, | |
amount: model.amount, | |
modified: model.modified, | |
)); | |
}, | |
cascade: cascade); | |
return preloadedModels; | |
} | |
CartItemBean get cartItemBean; | |
} | |
abstract class _CartItemBean implements Bean<CartItem> { | |
final id = IntField('id'); | |
final amount = IntField('amount'); | |
final product = IntField('product'); | |
final quantity = IntField('quantity'); | |
final description = StrField('description'); | |
final cartId = IntField('cart_id'); | |
Map<String, Field> _fields; | |
Map<String, Field> get fields => _fields ??= { | |
id.name: id, | |
amount.name: amount, | |
product.name: product, | |
quantity.name: quantity, | |
description.name: description, | |
cartId.name: cartId, | |
}; | |
CartItem fromMap(Map map) { | |
CartItem model = CartItem( | |
id: adapter.parseValue(map['id']), | |
amount: adapter.parseValue(map['amount']), | |
product: adapter.parseValue(map['product']), | |
quantity: adapter.parseValue(map['quantity']), | |
description: adapter.parseValue(map['description']), | |
cartId: adapter.parseValue(map['cart_id'])); | |
return model; | |
} | |
List<SetColumn> toSetColumns(CartItem model, {bool update = false, Set<String> only, bool onlyNonNull = false}) { | |
List<SetColumn> ret = []; | |
if (only == null && !onlyNonNull) { | |
if (model.id != null) { | |
ret.add(id.set(model.id)); | |
} | |
ret.add(amount.set(model.amount)); | |
ret.add(product.set(model.product)); | |
ret.add(quantity.set(model.quantity)); | |
ret.add(description.set(model.description)); | |
ret.add(cartId.set(model.cartId)); | |
} else if (only != null) { | |
if (model.id != null) { | |
if (only.contains(id.name)) ret.add(id.set(model.id)); | |
} | |
if (only.contains(amount.name)) ret.add(amount.set(model.amount)); | |
if (only.contains(product.name)) ret.add(product.set(model.product)); | |
if (only.contains(quantity.name)) ret.add(quantity.set(model.quantity)); | |
if (only.contains(description.name)) ret.add(description.set(model.description)); | |
if (only.contains(cartId.name)) ret.add(cartId.set(model.cartId)); | |
} else | |
/* if (onlyNonNull) */ { | |
if (model.id != null) { | |
ret.add(id.set(model.id)); | |
} | |
if (model.amount != null) { | |
ret.add(amount.set(model.amount)); | |
} | |
if (model.product != null) { | |
ret.add(product.set(model.product)); | |
} | |
if (model.quantity != null) { | |
ret.add(quantity.set(model.quantity)); | |
} | |
if (model.description != null) { | |
ret.add(description.set(model.description)); | |
} | |
if (model.cartId != null) { | |
ret.add(cartId.set(model.cartId)); | |
} | |
} | |
return ret; | |
} | |
Future<void> createTable({bool ifNotExists = false}) async { | |
final st = Sql.create(tableName, ifNotExists: ifNotExists); | |
st.addInt(id.name, primary: true, autoIncrement: true, isNullable: false); | |
st.addInt(amount.name, isNullable: false); | |
st.addInt(product.name, isNullable: true); | |
st.addInt(quantity.name, isNullable: false); | |
st.addStr(description.name, isNullable: true); | |
st.addInt(cartId.name, foreignTable: cartBean.tableName, foreignCol: 'ext_id', isNullable: false); | |
return adapter.createTable(st); | |
} | |
Future<dynamic> insert(CartItem model, {bool cascade = false, bool onlyNonNull = false, Set<String> only}) async { | |
final Insert insert = inserter.setMany(toSetColumns(model, only: only, onlyNonNull: onlyNonNull)).id(id.name); | |
var retId = await adapter.insert(insert); | |
return retId; | |
} | |
Future<void> insertMany(List<CartItem> models, {bool onlyNonNull = false, Set<String> only}) async { | |
final List<List<SetColumn>> data = models.map((model) => toSetColumns(model, only: only, onlyNonNull: onlyNonNull)).toList(); | |
final InsertMany insert = inserters.addAll(data); | |
await adapter.insertMany(insert); | |
return; | |
} | |
Future<dynamic> upsert(CartItem model, {bool cascade = false, Set<String> only, bool onlyNonNull = false}) async { | |
final Upsert upsert = upserter.setMany(toSetColumns(model, only: only, onlyNonNull: onlyNonNull)).id(id.name); | |
var retId = await adapter.upsert(upsert); | |
return retId; | |
} | |
Future<void> upsertMany(List<CartItem> models, {bool onlyNonNull = false, Set<String> only}) async { | |
final List<List<SetColumn>> data = []; | |
for (var i = 0; i < models.length; ++i) { | |
var model = models[i]; | |
data.add(toSetColumns(model, only: only, onlyNonNull: onlyNonNull).toList()); | |
} | |
final UpsertMany upsert = upserters.addAll(data); | |
await adapter.upsertMany(upsert); | |
return; | |
} | |
Future<int> update(CartItem model, {bool cascade = false, bool associate = false, Set<String> only, bool onlyNonNull = false}) async { | |
final Update update = updater.where(this.id.eq(model.id)).setMany(toSetColumns(model, only: only, onlyNonNull: onlyNonNull)); | |
return adapter.update(update); | |
} | |
Future<void> updateMany(List<CartItem> models, {bool onlyNonNull = false, Set<String> only}) async { | |
final List<List<SetColumn>> data = []; | |
final List<Expression> where = []; | |
for (var i = 0; i < models.length; ++i) { | |
var model = models[i]; | |
data.add(toSetColumns(model, only: only, onlyNonNull: onlyNonNull).toList()); | |
where.add(this.id.eq(model.id)); | |
} | |
final UpdateMany update = updaters.addAll(data, where); | |
await adapter.updateMany(update); | |
return; | |
} | |
Future<CartItem> find(int id, {bool preload = false, bool cascade = false}) async { | |
final Find find = finder.where(this.id.eq(id)); | |
return await findOne(find); | |
} | |
Future<int> remove(int id) async { | |
final Remove remove = remover.where(this.id.eq(id)); | |
return adapter.remove(remove); | |
} | |
Future<int> removeMany(List<CartItem> models) async { | |
// Return if models is empty. If this is not done, all records will be removed! | |
if (models == null || models.isEmpty) return 0; | |
final Remove remove = remover; | |
for (final model in models) { | |
remove.or(this.id.eq(model.id)); | |
} | |
return adapter.remove(remove); | |
} | |
Future<List<CartItem>> findByCart(int cartId, {bool preload = false, bool cascade = false}) async { | |
final Find find = finder.where(this.cartId.eq(cartId)); | |
return findMany(find); | |
} | |
Future<List<CartItem>> findByCartList(List<Cart> models, {bool preload = false, bool cascade = false}) async { | |
// Return if models is empty. If this is not done, all the records will be returned! | |
if (models == null || models.isEmpty) return []; | |
final Find find = finder; | |
for (Cart model in models) { | |
find.or(this.cartId.eq(model.extId)); | |
} | |
return findMany(find); | |
} | |
Future<int> removeByCart(int cartId) async { | |
final Remove rm = remover.where(this.cartId.eq(cartId)); | |
return await adapter.remove(rm); | |
} | |
CartItem associateCart(CartItem child, Cart parent) { | |
return CartItem( | |
cartId: parent.extId, | |
description: child.description, | |
product: child.product, | |
amount: child.amount, | |
id: child.id, | |
quantity: child.quantity, | |
); | |
} | |
CartBean get cartBean; | |
} |
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
name: jaguar_test | |
description: Test | |
version: 1.0.0 | |
environment: | |
sdk: '>=2.2.0 <3.0.0' | |
dependencies: | |
jaguar_query_postgres: ^2.2.6 | |
dev_dependencies: | |
build_runner: 1.1.2 | |
jaguar_orm_gen: ^2.2.27 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment