Giter Site home page Giter Site logo

jaguar-dart / jaguar_orm Goto Github PK

View Code? Open in Web Editor NEW
217.0 8.0 54.0 1.66 MB

Source-generated ORM with relations (one-to-one, one-to-many, many-to-many), preloading, cascading, polymorphic relations, etc

Home Page: https://jaguar-dart.github.io

License: BSD 3-Clause "New" or "Revised" License

Dart 99.27% Java 0.38% Objective-C 0.35%
orm relationships sql one-to-one one-to-many many-to-many polymorphic-relationships postgresql source-generation dart

jaguar_orm's Introduction

jaguar orm

Source-generated ORM with relations (one-to-one, one-to-many, many-to-many), preloading, cascading, polymorphic relations, etc

Features

  • Relationships
  • Preloads
  • Cascading
    • Cascaded inserts
    • Cascaded updates
    • Cascaded removals
  • Migration
  • Polymorphic relations
  • Composite primary keys
  • Composite foreign keys

Getting started

Declaring the Model

class User {
  @PrimaryKey()
  String id;

  String name;

  static const String tableName = '_user';

  String toString() => "User($id, $name)";
}

Declaring the Bean

A Bean performs database actions on behalf of the model. In this case, UserBean performs actions for User model. Much of the Bean's functionality will be source generated.

@GenBean()
class UserBean extends Bean<User> with _UserBean {
  UserBean(Adapter adapter) : super(adapter);
}

Generating Bean logic

jaguar_orm use source_gen and jaguar_orm_gen to generate bean logic from bean specification.

Add the following dependencies to dev_dependencies.

  build_runner:
  jaguar_orm_gen:

Run the following command to generate Bean logic:

pub run build_runner build

Connecting to database

We will use PostgreSQL for this tutorial. PgAdapter is found in the package jaguar_query_postgres.

final PgAdapter _adapter =
    new PgAdapter('example', username: 'postgres', password: 'dart_jaguar');
await _adapter.connect();

Creating instance of bean

Beans internally use jaguar_query's Adapter interface to talk to database. Lets create an instance of UserBean.

final userBean = new UserBean(_adapter);

Dropping the table

await userBean.drop();

Creating a table

await userBean.createTable();

Inserting a new record

await userBean.insert(new User()
    ..id = '1'
    ..name = 'teja');

Fetching record by primary key

User user = await userBean.find('1');

Fetching all records

List<User> users = await userBean.getAll();

Updating a record

User user = await userBean.find('1');
user.name = 'teja hackborn';
await userBean.update(user);

Remove by id

await userBean.remove('1');

Remove all

await userBean.removeAll();

Examples

One-To-One example

class User {
  @PrimaryKey()
  String id;

  String name;

  @HasOne(AddressBean)
  Address address;

  static const String tableName = '_user';

  String toString() => "User($id, $name, $address)";
}

class Address {
  @PrimaryKey()
  String id;

  @BelongsTo(UserBean)
  String userId;

  String street;

  static String tableName = 'address';

  String toString() => "Post($id, $userId, $street)";
}

@GenBean()
class UserBean extends Bean<User> with _UserBean {
  UserBean(Adapter adapter)
      : addressBean = new AddressBean(adapter),
        super(adapter);

  final AddressBean addressBean;

  Future createTable() {
    final st = Sql
        .create(tableName)
        .addStr('id', primary: true, length: 50)
        .addStr('name', length: 50);
    return execCreateTable(st);
  }
}

@GenBean()
class AddressBean extends Bean<Address> with _AddressBean {
  AddressBean(Adapter adapter) : super(adapter);

  Future createTable() {
    final st = Sql
        .create(tableName)
        .addStr('id', primary: true, length: 50)
        .addStr('street', length: 150)
        .addStr('user_id', length: 50, foreignTable: '_user', foreignCol: 'id');
    return execCreateTable(st);
  }
}

/// The adapter
PgAdapter _adapter =
    new PgAdapter('postgres://postgres:dart_jaguar@localhost/example');

main() async {
  // Connect to database
  await _adapter.connect();

  // Create beans
  final userBean = new UserBean(_adapter);
  final addressBean = new AddressBean(_adapter);

  // Drop old tables
  await addressBean.drop();
  await userBean.drop();

  // Create new tables
  await userBean.createTable();
  await addressBean.createTable();

  // Cascaded One-To-One insert
  {
    final user = new User()
      ..id = '1'
      ..name = 'Teja'
      ..address = (new Address()
        ..id = '1'
        ..street = 'Stockholm');
    await userBean.insert(user, cascade: true);
  }

  // Fetch One-To-One preloaded
  {
    final user = await userBean.find('1', preload: true);
    print(user);
  }

  // Manual One-To-One insert
  {
    User user = new User()
      ..id = '2'
      ..name = 'Kleak';
    await userBean.insert(user, cascade: true);

    user = await userBean.find('2');

    final address = new Address()
      ..id = '2'
      ..street = 'Stockholm';
    addressBean.associateUser(address, user);
    await addressBean.insert(address);
  }

  // Manual One-To-One preload
  {
    final user = await userBean.find('2');
    print(user);
    user.address = await addressBean.findByUser(user.id);
    print(user);
  }

  // Preload many
  {
    final users = await userBean.getAll();
    print(users);
    await userBean.preloadAll(users);
    print(users);
  }

  // Cascaded One-To-One update
  {
    User user = await userBean.find('1', preload: true);
    user.name = 'Teja Hackborn';
    user.address.street = 'Stockholm, Sweden';
    await userBean.update(user, cascade: true);
  }

  // Fetch One-To-One relationship preloaded
  {
    final user = await userBean.find('1', preload: true);
    print(user);
  }

  // Cascaded removal of One-To-One relation
  await userBean.remove('1', true);

  // Remove addresses belonging to a User
  await addressBean.removeByUser('2');

  exit(0);
}

jaguar_orm's People

Contributors

elnurvl avatar hexer10 avatar iqbalhood avatar isaacfi avatar jaumard avatar leifcr avatar martinhlavna avatar mikeroneer avatar mogol avatar officelioneight avatar tejainece avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jaguar_orm's Issues

Possibility to ignore fields during generation on getters

I have this model:

class CartDb {
  @PrimaryKey(autoIncrement: true)
  int id;

  @HasMany(CartItemDbBean)
  List<CartItemDb> items;
  double amount;

  CartDb({this.id, this.amount = 0.0, this.items = const []});

  String get amountLabel {
    return kNumberFormat.format(amount);
  }

  @override
  String toString() => 'amount=$amount, items=$items';

  @override
  bool operator ==(Object other) =>
      identical(this, other) || other is CartDb && runtimeType == other.runtimeType && items == other.items && amount == other.amount;

  @override
  int get hashCode => items.hashCode ^ amount.hashCode;

}

The problem with this is that during generation, it's generating stuff for amountLabel and hashCode.
Would be nice if the generator can automatically ignore those fields (don't know if it's possible or not) or at least having some kind of @ignore annotation maybe to just don't generate anything related to those :)

Generator last version doesn't work / crash

Just try to update deps on the sqflite example and nothing is working anymore.
Here is the stack


// **************************************************************************
// BeanGenerator
// **************************************************************************

/*
NoSuchMethodError: Attempted to use type 'WriterInfo' as a function. Since types do not define a method 'call', this is not possible. Did you intend to call the WriterInfo constructor and forget the 'new' operator?
Receiver: WriterInfo
Tried calling: WriterInfo("PostBean", "Post", _LinkedHashMap len:5, Instance(length:1) of '_GrowableList', _LinkedHashMap len:0, _LinkedHashMap len:0, Instance(length:0) of '_GrowableList')
#0      Object.noSuchMethod (dart:core-patch/dart:core/object_patch.dart:46)
#1      ParsedBean.detect (package:jaguar_orm_gen/src/parser/parser.dart:216:27)
#2      BeanGenerator.generateForAnnotatedElement (package:jaguar_orm_gen/src/hook/hook.dart:38:42)
<asynchronous suspension>
#3      GeneratorForAnnotation.generate (package:source_gen/src/generator_for_annotation.dart:42:28)
<asynchronous suspension>
#4      _generate (package:source_gen/src/builder.dart:213:35)
<asynchronous suspension>
#5      _Builder._generateForLibrary (package:source_gen/src/builder.dart:74:15)
<asynchronous suspension>
#6      _Builder.build (package:source_gen/src/builder.dart:68:11)
<asynchronous suspension>
#7      runBuilder.buildForInput (package:build/src/generate/run_builder.dart:43:21)
<asynchronous suspension>
#8      MappedListIterable.elementAt (dart:_internal/iterable.dart:414)
#9      ListIterator.moveNext (dart:_internal/iterable.dart:343)
#10     Future.wait (dart:async/future.dart:385)
#11     runBuilder.<anonymous closure> (package:build/src/generate/run_builder.dart:49:36)
#12     _rootRun (dart:async/zone.dart:1126)
#13     _CustomZone.run (dart:async/zone.dart:1023)
#14     runZoned (dart:async/zone.dart:1490)
#15     scopeLogAsync (package:build/src/builder/logging.dart:22:3)
#16     runBuilder (package:build/src/generate/run_builder.dart:49:9)
<asynchronous suspension>
#17     _SingleBuild._runForInput.<anonymous closure> (package:build_runner_core/src/generate/build_impl.dart:424:15)
#18     _NoOpBuilderActionTracker.track (package:build_runner_core/src/generate/performance_tracker.dart:246:73)
#19     _SingleBuild._runForInput (package:build_runner_core/src/generate/build_impl.dart:423:19)
<asynchronous suspension>
#20     _SingleBuild._runBuilder.<anonymous closure> (package:build_runner_core/src/generate/build_impl.dart:349:38)
#21     MappedIterator.moveNext (dart:_internal/iterable.dart:392)
#22     Future.wait (dart:async/future.dart:385)
#23     _SingleBuild._runBuilder (package:build_runner_core/src/generate/build_impl.dart:348:36)
<asynchronous suspension>
#24     _SingleBuild._runPhases.<anonymous closure> (package:build_runner_core/src/generate/build_impl.dart:296:32)
<asynchronous suspension>
#25     _NoOpBuildPerformanceTracker.trackBuildPhase (package:build_runner_core/src/generate/performance_tracker.dart:140:15)
#26     _SingleBuild._runPhases (package:build_runner_core/src/generate/build_impl.dart:292:33)
<asynchronous suspension>
#27     logTimedAsync (package:build_runner_core/src/logging/logging.dart:25:30)
<asynchronous suspension>
#28     _SingleBuild._safeBuild.<anonymous closure> (package:build_runner_core/src/generate/build_impl.dart:260:26)
<asynchronous suspension>
#29     _rootRun (dart:async/zone.dart:1126)
#30     _CustomZone.run (dart:async/zone.dart:1023)
#31     runZoned (dart:async/zone.dart:1490)
#32     _SingleBuild._safeBuild (package:build_runner_core/src/generate/build_impl.dart:255:5)
#33     _SingleBuild.run (package:build_runner_core/src/generate/build_impl.dart:185:24)
<asynchronous suspension>
#34     BuildImpl.run (package:build_runner_core/src/generate/build_impl.dart:89:30)
#35     BuildRunner.run (package:build_runner_core/src/generate/build_runner.dart:23:14)
#36     build (package:build_runner/src/generate/build.dart:98:30)
<asynchronous suspension>
#37     BuildCommand.run (package:build_runner/src/entrypoint/build.dart:28:24)
<asynchronous suspension>
#38     CommandRunner.runCommand (package:args/command_runner.dart:194:27)
<asynchronous suspension>
#39     CommandRunner.run.<anonymous closure> (package:args/command_runner.dart:109:29)
#40     new Future.sync (dart:async/future.dart:222)
#41     CommandRunner.run (package:args/command_runner.dart:109:11)
#42     run (package:build_runner/src/entrypoint/run.dart:22:31)
<asynchronous suspension>
#43     main (file:///Users/jaumard/StudioProjects/sqfliteJaguarExample/.dart_tool/build/entrypoint/build.dart:10:22)
<asynchronous suspension>
#44     _startIsolate.<anonymous closure> (dart:isolate-patch/dart:isolate/isolate_patch.dart:275)
#45     _RawReceivePortImpl._handleMessage (dart:isolate-patch/dart:isolate/isolate_patch.dart:165)
*/

Dart SDK v2 support ?

Dear all,

any idea as to when the maintainers of this package will expand compatibility to Dart SDK v2 ?

Generation is wrong when oneToOne and oneToMany on same object

Here is what my model look like:

class Post {
  Post();
  Post.make(this.id, this.msg, this.stars, this.read, this.at, this.item, this.items);

  @PrimaryKey(autoIncrement: true)
  int id;
  @Column(nullable: true)
  String msg;
  @Column(nullable: true)
  bool read;
  @Column(nullable: true)
  double stars;
  @Column(nullable: true)
  DateTime at;
  @HasOne(ItemBean)
  Item item;
  @HasMany(ItemBean)
  List<Item> items;

  String toString() =>
      'Post(id: $id, message: $msg, stars: $stars, read: $read, at: $at, item: $item, items: $items)';

  static String get tableName => 'posts';
}

@GenBean()
class PostBean extends Bean<Post> with _PostBean {
  PostBean(Adapter adapter)
      : itemBean = ItemBean(adapter),
        super(adapter);

  final ItemBean itemBean;

  Future<int> updateReadField(int id, bool read) async {
    Update st = updater.where(this.id.eq(id)).set(this.read, read);
    return execUpdate(st);
  }

  /// Finds all posts
  Future<List<Post>> findAll() async => (await execFind(finder)).toList();
}

And this is what is generate:

// GENERATED CODE - DO NOT MODIFY BY HAND

part of 'post.dart';

// **************************************************************************
// BeanGenerator
// **************************************************************************

abstract class _PostBean implements Bean<Post> {
  String get tableName => Post.tableName;

  final IntField id = new IntField('id');

  final StrField msg = new StrField('msg');

  final BoolField read = new BoolField('read');

  final DoubleField stars = new DoubleField('stars');

  final DateTimeField at = new DateTimeField('at');

  Post fromMap(Map map) {
    Post model = new Post();

    model.id = adapter.parseValue(map['id']);
    model.msg = adapter.parseValue(map['msg']);
    model.read = adapter.parseValue(map['read']);
    model.stars = adapter.parseValue(map['stars']);
    model.at = adapter.parseValue(map['at']);

    return model;
  }

  List<SetColumn> toSetColumns(Post model, [bool update = false]) {
    List<SetColumn> ret = [];

    ret.add(id.set(model.id));
    ret.add(msg.set(model.msg));
    ret.add(read.set(model.read));
    ret.add(stars.set(model.stars));
    ret.add(at.set(model.at));

    return ret;
  }

  Future createTable() async {
    final st = Sql.create(tableName);
    st.addInt(id.name, primary: true, autoIncrement: true);
    st.addStr(msg.name);
    st.addBool(read.name);
    st.addInt(stars.name);
    st.addDateTime(at.name);
    return execCreateTable(st);
  }

  Future<dynamic> insert(Post model, {bool cascade: false}) async {
    final Insert insert = inserter.setMany(toSetColumns(model));
    var retId = await execInsert(insert);
    if (cascade) {
      Post newModel;
      if (model.item != null) {
        newModel ??= await find(model.id);
        itemBean.associatePost(model.item, newModel);
        await itemBean.insert(model.item);
      }
      if (model.items != null) {
        newModel ??= await find(model.id);
        model.items.forEach((x) => itemBean.associatePost(x, newModel));
        for (final child in model.items) {
          await itemBean.insert(child);
        }
      }
    }
    return retId;
  }

  Future<int> update(Post model,
      {bool cascade: false, bool associate: false}) async {
    final Update update =
        updater.where(this.id.eq(model.id)).setMany(toSetColumns(model));
    final ret = execUpdate(update);
    if (cascade) {
      Post newModel;
      if (model.item != null) {
        if (associate) {
          newModel ??= await find(model.id);
          itemBean.associatePost(model.item, newModel);
        }
        await itemBean.update(model.item);
      }
      if (model.items != null) {
        if (associate) {
          newModel ??= await find(model.id);
          model.items.forEach((x) => itemBean.associatePost(x, newModel));
        }
        for (final child in model.items) {
          await itemBean.update(child);
        }
      }
    }
    return ret;
  }

  Future<Post> find(int id, {bool preload: false, bool cascade: false}) async {
    final Find find = finder.where(this.id.eq(id));
    final Post model = await execFindOne(find);
    if (preload) {
      await this.preload(model, cascade: cascade);
    }
    return model;
  }

  Future<List<Post>> findWhere(Expression exp) async {
    final Find find = finder.where(exp);
    return await (await execFind(find)).toList();
  }

  Future<int> remove(int id, [bool cascade = false]) async {
    if (cascade) {
      final Post newModel = await find(id);
      await itemBean.removeByPost(newModel.id);
      await itemBean.removeByPost(newModel.id);
    }
    final Remove remove = remover.where(this.id.eq(id));
    return execRemove(remove);
  }

  Future<int> removeMany(List<Post> models) async {
    final Remove remove = remover;
    for (final model in models) {
      remove.or(this.id.eq(model.id));
    }
    return execRemove(remove);
  }

  Future<int> removeWhere(Expression exp) async {
    return execRemove(remover.where(exp));
  }

  Future preload(Post model, {bool cascade: false}) async {
    model.item =
        await itemBean.findByPost(model.id, preload: cascade, cascade: cascade);
    model.items =
        await itemBean.findByPost(model.id, preload: cascade, cascade: cascade);
  }

  Future preloadAll(List<Post> models, {bool cascade: false}) async {
    await PreloadHelper.preload<Post, Item>(
        models,
        (Post model) => [model.id],
        itemBean.findByPostList,
        (Item model) => [model.postId],
        (Post model, Item child) => model.item = child,
        cascade: cascade);
    models.forEach((Post model) => model.items ??= []);
    await PreloadHelper.preload<Post, Item>(
        models,
        (Post model) => [model.id],
        itemBean.findByPostList,
        (Item model) => [model.postId],
        (Post model, Item child) => model.items.add(child),
        cascade: cascade);
  }

  ItemBean get itemBean;
  ItemBean get itemBean;
}

There is a duplication of the bean that cause trouble in multiple places in the generated code

Immutability support relations

If model are immutable, all generated code about relations doesn't compile anymore.

Mostly because if generate stuff like this:

void associateCart(CartItem child, Cart parent) {
    child.cartId = parent.id;
  }
Future<Cart> preload(Cart model, {bool cascade: false}) async {
    model.items = await cartItemBean.findByCart(model.id,
        preload: cascade, cascade: cascade);
    return model;
  }

  Future<List<Cart>> preloadAll(List<Cart> models,
      {bool cascade: false}) async {
    models.forEach((Cart model) => model.items ??= []);
    await OneToXHelper.preloadAll<Cart, CartItem>(
        models,
        (Cart model) => [model.id],
        cartItemBean.findByCartList,
        (CartItem model) => [model.cartId],
        (Cart model, CartItem child) => model.items.add(child),
        cascade: cascade);
    return models;
  }

as models are immutable it's not possible to access setters directly

Update method association improvements

Currently the update method call update method of his children, the problem is when you update the parent you might have added new children, in that case it should call insert and not update.
I know this one can be tricky as you don't know the schema of the children but it can be resolved by adding a insertOrUpdate method into bean, like this this one is aware of his own schema and can call insert or update accordingly

@Column nullable ignored

Apparently nullable on column doesn't work:

I tried this:

@Column(nullable: true)
  String product;

or

@GenBean(
  columns: {
    'product': Column(nullable: true),
  },
)

But both generate this:
st.addStr(product.name);
instead of
st.addNullStr(product.name);

Logo Design Offer For JAGUAR ORM

Hello Sir. I'm a UI/UX and Graphics Designer. who has contacted you via email last week.
These are my logo proposal for your application.
I'm very welcome if you have any comments, opinions, or revisions. Please just tell me.
I'll provide all file types and sizes you needed.
Hope you like it.

Version 1

jaguar with name app

Version 2

jaguar with name app 2

If id is Int, insert method not gen correctly with association

In SQLite, if you want an auto increment id, you need to put it as int, by doing so the insert method is not generated correctly in case of association:

Future<dynamic> insert(Post model, {bool cascade: false}) async {
    final Insert insert = inserter.setMany(toSetColumns(model))..id(id);
  

Problem is that id method of Insert is waiting for a String not an int so it complain

LICENSE ?

In order to use (or knowing if we can) jaguar in enterprise environment we need to have a license. I look several repository of jaguar that might save us a lot of time lol but can't use them until we know which license you put on those repo
Thanks

Possibility to have immutable model [enhancement]

I'm used to work with immutable object to avoid side effect problems. Would be nice if the generator can adapt if the class is immutable :)

Example let's consider this class:

@immutable
class CartItem {
  final int id;
  final double amount;
  final String product;
  final int quantity;

  const CartItem({this.amount, this.product, this.quantity, this.id});

  String get amountLabel => kNumberFormat.format(amount);

  @override
  String toString() => 'amount=$amount, quantity=$quantity, product=$product';

  CartItem copy({int id, int quantity, String product, double amount}) {
    return CartItem(
      amount ?? this.amount,
      product ?? this.product,
      quantity ?? this.quantity,
      id: id ?? this.id,
    );
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
          other is CartItem &&
              runtimeType == other.runtimeType &&
              amount == other.amount &&
              product == other.product &&
              quantity == other.quantity;

  @override
  int get hashCode =>
      amount.hashCode ^
      product.hashCode ^
      quantity.hashCode;
}

Then the generated fromMap look like:

CartItemDb fromMap(Map map) {
    CartItemDb model = new CartItemDb();

    model.id = adapter.parseValue(map['id']);
    model.amount = adapter.parseValue(map['amount']);
    model.product = adapter.parseValue(map['product']);
    model.quantity = adapter.parseValue(map['quantity']);
    model.cartId = adapter.parseValue(map['cart_id']);

    return model;
  }

Where the correct way would be:

CartItemDb fromMap(Map map) {
    CartItemDb model = new CartItemDb(
      id: adapter.parseValue(map['id']),
      amount: adapter.parseValue(map['amount']),
      product: adapter.parseValue(map['product']),
      quantity: adapter.parseValue(map['quantity']),
      cartId: adapter.parseValue(map['cart_id']),
    );
    return model;
  }

Might have some changes to do around association too as it directly change the object:

void associateCartDb(CartItemDb child, CartDb parent) {
    child.cartId = parent.id;
  }

When I understand better how this generation works I might take a look at this :)

Flutter usage

Is it possible to use this package with Flutter (sqlite database) ?
Would be awesome as currently on Flutter there nothing as I know (except plugin to make raw sql queries...).

If it doesn't work with Flutter can it work ? Maybe I can check to add Flutter support if it's not too difficult ^^

Many to many relationships fail to load

The preloadAll method call fails with a SQL error when the pivot table has no items in it.

E/SQLiteLog( 3028): (1) near ")": syntax error
E/flutter ( 3028): [ERROR:flutter/shell/common/shell.cc(181)] Dart Error: Unhandled exception:
E/flutter ( 3028): DatabaseException(near ")": syntax error (code 1): , while compiling: SELECT *  FROM product_list WHERE ();) sql 'SELECT *  FROM product_list WHERE ();' args []}
E/

UpdateAll and insertAll method

Would be nice to have to be able to make bulk operation, will be also faster to do one request will all model than loop on all of them to insert/update

Single quote ' text not escaped on insert

Hi,

I'm using Flutter and have generated my class using:
flutter packages pub run build_runner build

I'm getting rows inserted into the database. ๐Ÿ˜€ However I'm having trouble with some items not being added because they contain a single quote in their text. ๐Ÿ˜•(eg. "MTHEM8101'CP")

flutter: DatabaseException(Error Domain=FMDatabase Code=1 "near "CP": syntax error" UserInfo={NSLocalizedDescription=near "CP": syntax error}) sql 'INSERT INTO product(sku, name, category_id) VALUES ('MTHEM8101'CP', 'Echo Minimalist Basin Mixer Chrome', 1117629706)' args []}

Is this something I should be doing when creating assigning my object parameters? ๐Ÿค” I thought that the generated class would handle.

Thanks for any help.

Write wiki pages

  • Getting started
  • Where Expression
  • What is a Bean?
  • Generating a Bean
  • Relations
    • One to one
    • One to many
    • Many to many
  • Fields

...

Enhanced `update` methods

Implement:

  • updateOnly
  • updateFieldsById
  • updateFields:
  Future<int> updateOnly(User model, Set<String> fields) async {
    // TODO
  }

  Future<int> updateFieldsById(String id, Map<String, dynamic> values) async {
    // TODO
  }

  Future<int> updateFields(
      Expression where, Map<String, dynamic> values) async {
    final st = updater.where(where);
    for (String key in values.keys) {
      final f = fields[key];
      if (f == null) throw Exception('Unknown field!');
      st.set(f, values[key]);
    }
    return execUpdate(st);
  }

Postgres Adapter, Auto-Increment on Primary Key

The auto-increment functionality does not seem to work with a PostgreSQL adapter.

The following model definition:

class MyModel {
  @PrimaryKey(auto: true, isNullable: true)
  int id;
}

Generates the following table:

     Column      |         Type          | Collation | Nullable |                        Default                         
------------------+-----------------------+-----------+----------+--------------------------------------------------------
 id               | integer               |           | not null | nextval('_my_model_seq'::regclass)

The test:

myModels.insert(MyModel());

Fails with:

PostgreSQLSeverity.error 23502: null value in column "id" violates not-null constraint Detail: Failing row contains (null). Table: _my_model Column: id
  package:postgres/src/connection.dart 400:24   _PostgreSQLConnection&Object&_PostgreSQLExecutionContextMixin._enqueue
  ===== asynchronous gap ===========================
  dart:async/future_impl.dart 22:43             _Completer.completeError
  dart:async/runtime/libasync_patch.dart 40:18  _AsyncAwaitCompleter.completeError
  package:postgres/src/connection.dart          _PostgreSQLConnection&Object&_PostgreSQLExecutionContextMixin._enqueue
  ===== asynchronous gap ===========================
  dart:async/zone.dart 1053:19                  _CustomZone.registerUnaryCallback
  dart:async/runtime/libasync_patch.dart 77:23  _asyncThenWrapperHelper
  package:postgres/src/connection.dart          _PostgreSQLConnection&Object&_PostgreSQLExecutionContextMixin._enqueue
  package:postgres/src/connection.dart 316:12   _PostgreSQLConnection&Object&_PostgreSQLExecutionContextMixin.query
  ===== asynchronous gap ===========================
  dart:async/zone.dart 1053:19                  _CustomZone.registerUnaryCallback
  dart:async/runtime/libasync_patch.dart 77:23  _asyncThenWrapperHelper
  package:test/src/backend/declarer.dart        Declarer.test.<fn>.<fn>.<fn>
  package:test/src/backend/invoker.dart 249:15  Invoker.waitForOutstandingCallbacks.<fn>
  ===== asynchronous gap ===========================
  dart:async/zone.dart 1045:19                  _CustomZone.registerCallback
  dart:async/zone.dart 962:22                   _CustomZone.bindCallbackGuarded
  dart:async/timer.dart 52:45                   new Timer
  dart:async/timer.dart 87:9                    Timer.run
  dart:async/future.dart 174:11                 new Future
  package:test/src/backend/invoker.dart 402:15  Invoker._onRun.<fn>.<fn>.<fn>

A manual insert also seems to fail, it's like the null constraint validation is run before the default script is run. Is there a correct way of doing this instead?

Many to many pivot class autogenerated

From the example of many to many the pivot class is done manually, in most case we don't case about this class, would be nice to have the possibility to generate it automatically if not already specify

Serialize in string column capabilities

Would be nice to be able to serialize some field as string (or JSON type if supported by the DB).

It will allow doing stuff like:

class Data {
  @Column(type:'string')
  Map<String, String> properties;
}

or

class Data {
  @Column(type:'string')
  List<SubData> properties;
}

It will prevent creating another table in DB if you don't care query this data.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.