mirror of https://github.com/AMT-Cheif/drift.git
Started to integrate the sqlparser into moor generator
This commit is contained in:
parent
1479a0d850
commit
40a4ebdadf
|
@ -1,788 +0,0 @@
|
||||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
|
||||||
|
|
||||||
part of 'example.dart';
|
|
||||||
|
|
||||||
// **************************************************************************
|
|
||||||
// MoorGenerator
|
|
||||||
// **************************************************************************
|
|
||||||
|
|
||||||
// ignore_for_file: unnecessary_brace_in_string_interps
|
|
||||||
class Category extends DataClass implements Insertable<Category> {
|
|
||||||
final int id;
|
|
||||||
final String description;
|
|
||||||
Category({@required this.id, this.description});
|
|
||||||
factory Category.fromData(Map<String, dynamic> data, GeneratedDatabase db,
|
|
||||||
{String prefix}) {
|
|
||||||
final effectivePrefix = prefix ?? '';
|
|
||||||
final intType = db.typeSystem.forDartType<int>();
|
|
||||||
final stringType = db.typeSystem.forDartType<String>();
|
|
||||||
return Category(
|
|
||||||
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']),
|
|
||||||
description: stringType
|
|
||||||
.mapFromDatabaseResponse(data['${effectivePrefix}description']),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
factory Category.fromJson(Map<String, dynamic> json,
|
|
||||||
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
|
|
||||||
return Category(
|
|
||||||
id: serializer.fromJson<int>(json['id']),
|
|
||||||
description: serializer.fromJson<String>(json['description']),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@override
|
|
||||||
Map<String, dynamic> toJson(
|
|
||||||
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
|
|
||||||
return {
|
|
||||||
'id': serializer.toJson<int>(id),
|
|
||||||
'description': serializer.toJson<String>(description),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
T createCompanion<T extends UpdateCompanion<Category>>(bool nullToAbsent) {
|
|
||||||
return CategoriesCompanion(
|
|
||||||
id: id == null && nullToAbsent ? const Value.absent() : Value(id),
|
|
||||||
description: description == null && nullToAbsent
|
|
||||||
? const Value.absent()
|
|
||||||
: Value(description),
|
|
||||||
) as T;
|
|
||||||
}
|
|
||||||
|
|
||||||
Category copyWith({int id, String description}) => Category(
|
|
||||||
id: id ?? this.id,
|
|
||||||
description: description ?? this.description,
|
|
||||||
);
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return (StringBuffer('Category(')
|
|
||||||
..write('id: $id, ')
|
|
||||||
..write('description: $description')
|
|
||||||
..write(')'))
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => $mrjf($mrjc($mrjc(0, id.hashCode), description.hashCode));
|
|
||||||
@override
|
|
||||||
bool operator ==(other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
(other is Category && other.id == id && other.description == description);
|
|
||||||
}
|
|
||||||
|
|
||||||
class CategoriesCompanion extends UpdateCompanion<Category> {
|
|
||||||
final Value<int> id;
|
|
||||||
final Value<String> description;
|
|
||||||
const CategoriesCompanion({
|
|
||||||
this.id = const Value.absent(),
|
|
||||||
this.description = const Value.absent(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class $CategoriesTable extends Categories
|
|
||||||
with TableInfo<$CategoriesTable, Category> {
|
|
||||||
final GeneratedDatabase _db;
|
|
||||||
final String _alias;
|
|
||||||
$CategoriesTable(this._db, [this._alias]);
|
|
||||||
final VerificationMeta _idMeta = const VerificationMeta('id');
|
|
||||||
GeneratedIntColumn _id;
|
|
||||||
@override
|
|
||||||
GeneratedIntColumn get id => _id ??= _constructId();
|
|
||||||
GeneratedIntColumn _constructId() {
|
|
||||||
return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
final VerificationMeta _descriptionMeta =
|
|
||||||
const VerificationMeta('description');
|
|
||||||
GeneratedTextColumn _description;
|
|
||||||
@override
|
|
||||||
GeneratedTextColumn get description =>
|
|
||||||
_description ??= _constructDescription();
|
|
||||||
GeneratedTextColumn _constructDescription() {
|
|
||||||
return GeneratedTextColumn(
|
|
||||||
'description',
|
|
||||||
$tableName,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<GeneratedColumn> get $columns => [id, description];
|
|
||||||
@override
|
|
||||||
$CategoriesTable get asDslTable => this;
|
|
||||||
@override
|
|
||||||
String get $tableName => _alias ?? 'categories';
|
|
||||||
@override
|
|
||||||
final String actualTableName = 'categories';
|
|
||||||
@override
|
|
||||||
VerificationContext validateIntegrity(CategoriesCompanion d,
|
|
||||||
{bool isInserting = false}) {
|
|
||||||
final context = VerificationContext();
|
|
||||||
if (d.id.present) {
|
|
||||||
context.handle(_idMeta, id.isAcceptableValue(d.id.value, _idMeta));
|
|
||||||
} else if (id.isRequired && isInserting) {
|
|
||||||
context.missing(_idMeta);
|
|
||||||
}
|
|
||||||
if (d.description.present) {
|
|
||||||
context.handle(_descriptionMeta,
|
|
||||||
description.isAcceptableValue(d.description.value, _descriptionMeta));
|
|
||||||
} else if (description.isRequired && isInserting) {
|
|
||||||
context.missing(_descriptionMeta);
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Set<GeneratedColumn> get $primaryKey => {id};
|
|
||||||
@override
|
|
||||||
Category map(Map<String, dynamic> data, {String tablePrefix}) {
|
|
||||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
|
|
||||||
return Category.fromData(data, _db, prefix: effectivePrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, Variable> entityToSql(CategoriesCompanion d) {
|
|
||||||
final map = <String, Variable>{};
|
|
||||||
if (d.id.present) {
|
|
||||||
map['id'] = Variable<int, IntType>(d.id.value);
|
|
||||||
}
|
|
||||||
if (d.description.present) {
|
|
||||||
map['description'] = Variable<String, StringType>(d.description.value);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
$CategoriesTable createAlias(String alias) {
|
|
||||||
return $CategoriesTable(_db, alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Recipe extends DataClass implements Insertable<Recipe> {
|
|
||||||
final int id;
|
|
||||||
final String title;
|
|
||||||
final String instructions;
|
|
||||||
final int category;
|
|
||||||
Recipe(
|
|
||||||
{@required this.id,
|
|
||||||
@required this.title,
|
|
||||||
@required this.instructions,
|
|
||||||
this.category});
|
|
||||||
factory Recipe.fromData(Map<String, dynamic> data, GeneratedDatabase db,
|
|
||||||
{String prefix}) {
|
|
||||||
final effectivePrefix = prefix ?? '';
|
|
||||||
final intType = db.typeSystem.forDartType<int>();
|
|
||||||
final stringType = db.typeSystem.forDartType<String>();
|
|
||||||
return Recipe(
|
|
||||||
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']),
|
|
||||||
title:
|
|
||||||
stringType.mapFromDatabaseResponse(data['${effectivePrefix}title']),
|
|
||||||
instructions: stringType
|
|
||||||
.mapFromDatabaseResponse(data['${effectivePrefix}instructions']),
|
|
||||||
category:
|
|
||||||
intType.mapFromDatabaseResponse(data['${effectivePrefix}category']),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
factory Recipe.fromJson(Map<String, dynamic> json,
|
|
||||||
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
|
|
||||||
return Recipe(
|
|
||||||
id: serializer.fromJson<int>(json['id']),
|
|
||||||
title: serializer.fromJson<String>(json['title']),
|
|
||||||
instructions: serializer.fromJson<String>(json['instructions']),
|
|
||||||
category: serializer.fromJson<int>(json['category']),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@override
|
|
||||||
Map<String, dynamic> toJson(
|
|
||||||
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
|
|
||||||
return {
|
|
||||||
'id': serializer.toJson<int>(id),
|
|
||||||
'title': serializer.toJson<String>(title),
|
|
||||||
'instructions': serializer.toJson<String>(instructions),
|
|
||||||
'category': serializer.toJson<int>(category),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
T createCompanion<T extends UpdateCompanion<Recipe>>(bool nullToAbsent) {
|
|
||||||
return RecipesCompanion(
|
|
||||||
id: id == null && nullToAbsent ? const Value.absent() : Value(id),
|
|
||||||
title:
|
|
||||||
title == null && nullToAbsent ? const Value.absent() : Value(title),
|
|
||||||
instructions: instructions == null && nullToAbsent
|
|
||||||
? const Value.absent()
|
|
||||||
: Value(instructions),
|
|
||||||
category: category == null && nullToAbsent
|
|
||||||
? const Value.absent()
|
|
||||||
: Value(category),
|
|
||||||
) as T;
|
|
||||||
}
|
|
||||||
|
|
||||||
Recipe copyWith({int id, String title, String instructions, int category}) =>
|
|
||||||
Recipe(
|
|
||||||
id: id ?? this.id,
|
|
||||||
title: title ?? this.title,
|
|
||||||
instructions: instructions ?? this.instructions,
|
|
||||||
category: category ?? this.category,
|
|
||||||
);
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return (StringBuffer('Recipe(')
|
|
||||||
..write('id: $id, ')
|
|
||||||
..write('title: $title, ')
|
|
||||||
..write('instructions: $instructions, ')
|
|
||||||
..write('category: $category')
|
|
||||||
..write(')'))
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => $mrjf($mrjc(
|
|
||||||
$mrjc(
|
|
||||||
$mrjc($mrjc(0, id.hashCode), title.hashCode), instructions.hashCode),
|
|
||||||
category.hashCode));
|
|
||||||
@override
|
|
||||||
bool operator ==(other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
(other is Recipe &&
|
|
||||||
other.id == id &&
|
|
||||||
other.title == title &&
|
|
||||||
other.instructions == instructions &&
|
|
||||||
other.category == category);
|
|
||||||
}
|
|
||||||
|
|
||||||
class RecipesCompanion extends UpdateCompanion<Recipe> {
|
|
||||||
final Value<int> id;
|
|
||||||
final Value<String> title;
|
|
||||||
final Value<String> instructions;
|
|
||||||
final Value<int> category;
|
|
||||||
const RecipesCompanion({
|
|
||||||
this.id = const Value.absent(),
|
|
||||||
this.title = const Value.absent(),
|
|
||||||
this.instructions = const Value.absent(),
|
|
||||||
this.category = const Value.absent(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class $RecipesTable extends Recipes with TableInfo<$RecipesTable, Recipe> {
|
|
||||||
final GeneratedDatabase _db;
|
|
||||||
final String _alias;
|
|
||||||
$RecipesTable(this._db, [this._alias]);
|
|
||||||
final VerificationMeta _idMeta = const VerificationMeta('id');
|
|
||||||
GeneratedIntColumn _id;
|
|
||||||
@override
|
|
||||||
GeneratedIntColumn get id => _id ??= _constructId();
|
|
||||||
GeneratedIntColumn _constructId() {
|
|
||||||
return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
final VerificationMeta _titleMeta = const VerificationMeta('title');
|
|
||||||
GeneratedTextColumn _title;
|
|
||||||
@override
|
|
||||||
GeneratedTextColumn get title => _title ??= _constructTitle();
|
|
||||||
GeneratedTextColumn _constructTitle() {
|
|
||||||
return GeneratedTextColumn('title', $tableName, false, maxTextLength: 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
final VerificationMeta _instructionsMeta =
|
|
||||||
const VerificationMeta('instructions');
|
|
||||||
GeneratedTextColumn _instructions;
|
|
||||||
@override
|
|
||||||
GeneratedTextColumn get instructions =>
|
|
||||||
_instructions ??= _constructInstructions();
|
|
||||||
GeneratedTextColumn _constructInstructions() {
|
|
||||||
return GeneratedTextColumn(
|
|
||||||
'instructions',
|
|
||||||
$tableName,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final VerificationMeta _categoryMeta = const VerificationMeta('category');
|
|
||||||
GeneratedIntColumn _category;
|
|
||||||
@override
|
|
||||||
GeneratedIntColumn get category => _category ??= _constructCategory();
|
|
||||||
GeneratedIntColumn _constructCategory() {
|
|
||||||
return GeneratedIntColumn(
|
|
||||||
'category',
|
|
||||||
$tableName,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<GeneratedColumn> get $columns => [id, title, instructions, category];
|
|
||||||
@override
|
|
||||||
$RecipesTable get asDslTable => this;
|
|
||||||
@override
|
|
||||||
String get $tableName => _alias ?? 'recipes';
|
|
||||||
@override
|
|
||||||
final String actualTableName = 'recipes';
|
|
||||||
@override
|
|
||||||
VerificationContext validateIntegrity(RecipesCompanion d,
|
|
||||||
{bool isInserting = false}) {
|
|
||||||
final context = VerificationContext();
|
|
||||||
if (d.id.present) {
|
|
||||||
context.handle(_idMeta, id.isAcceptableValue(d.id.value, _idMeta));
|
|
||||||
} else if (id.isRequired && isInserting) {
|
|
||||||
context.missing(_idMeta);
|
|
||||||
}
|
|
||||||
if (d.title.present) {
|
|
||||||
context.handle(
|
|
||||||
_titleMeta, title.isAcceptableValue(d.title.value, _titleMeta));
|
|
||||||
} else if (title.isRequired && isInserting) {
|
|
||||||
context.missing(_titleMeta);
|
|
||||||
}
|
|
||||||
if (d.instructions.present) {
|
|
||||||
context.handle(
|
|
||||||
_instructionsMeta,
|
|
||||||
instructions.isAcceptableValue(
|
|
||||||
d.instructions.value, _instructionsMeta));
|
|
||||||
} else if (instructions.isRequired && isInserting) {
|
|
||||||
context.missing(_instructionsMeta);
|
|
||||||
}
|
|
||||||
if (d.category.present) {
|
|
||||||
context.handle(_categoryMeta,
|
|
||||||
category.isAcceptableValue(d.category.value, _categoryMeta));
|
|
||||||
} else if (category.isRequired && isInserting) {
|
|
||||||
context.missing(_categoryMeta);
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Set<GeneratedColumn> get $primaryKey => {id};
|
|
||||||
@override
|
|
||||||
Recipe map(Map<String, dynamic> data, {String tablePrefix}) {
|
|
||||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
|
|
||||||
return Recipe.fromData(data, _db, prefix: effectivePrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, Variable> entityToSql(RecipesCompanion d) {
|
|
||||||
final map = <String, Variable>{};
|
|
||||||
if (d.id.present) {
|
|
||||||
map['id'] = Variable<int, IntType>(d.id.value);
|
|
||||||
}
|
|
||||||
if (d.title.present) {
|
|
||||||
map['title'] = Variable<String, StringType>(d.title.value);
|
|
||||||
}
|
|
||||||
if (d.instructions.present) {
|
|
||||||
map['instructions'] = Variable<String, StringType>(d.instructions.value);
|
|
||||||
}
|
|
||||||
if (d.category.present) {
|
|
||||||
map['category'] = Variable<int, IntType>(d.category.value);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
$RecipesTable createAlias(String alias) {
|
|
||||||
return $RecipesTable(_db, alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Ingredient extends DataClass implements Insertable<Ingredient> {
|
|
||||||
final int id;
|
|
||||||
final String name;
|
|
||||||
final int caloriesPer100g;
|
|
||||||
Ingredient(
|
|
||||||
{@required this.id, @required this.name, @required this.caloriesPer100g});
|
|
||||||
factory Ingredient.fromData(Map<String, dynamic> data, GeneratedDatabase db,
|
|
||||||
{String prefix}) {
|
|
||||||
final effectivePrefix = prefix ?? '';
|
|
||||||
final intType = db.typeSystem.forDartType<int>();
|
|
||||||
final stringType = db.typeSystem.forDartType<String>();
|
|
||||||
return Ingredient(
|
|
||||||
id: intType.mapFromDatabaseResponse(data['${effectivePrefix}id']),
|
|
||||||
name: stringType.mapFromDatabaseResponse(data['${effectivePrefix}name']),
|
|
||||||
caloriesPer100g:
|
|
||||||
intType.mapFromDatabaseResponse(data['${effectivePrefix}calories']),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
factory Ingredient.fromJson(Map<String, dynamic> json,
|
|
||||||
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
|
|
||||||
return Ingredient(
|
|
||||||
id: serializer.fromJson<int>(json['id']),
|
|
||||||
name: serializer.fromJson<String>(json['name']),
|
|
||||||
caloriesPer100g: serializer.fromJson<int>(json['caloriesPer100g']),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@override
|
|
||||||
Map<String, dynamic> toJson(
|
|
||||||
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
|
|
||||||
return {
|
|
||||||
'id': serializer.toJson<int>(id),
|
|
||||||
'name': serializer.toJson<String>(name),
|
|
||||||
'caloriesPer100g': serializer.toJson<int>(caloriesPer100g),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
T createCompanion<T extends UpdateCompanion<Ingredient>>(bool nullToAbsent) {
|
|
||||||
return IngredientsCompanion(
|
|
||||||
id: id == null && nullToAbsent ? const Value.absent() : Value(id),
|
|
||||||
name: name == null && nullToAbsent ? const Value.absent() : Value(name),
|
|
||||||
caloriesPer100g: caloriesPer100g == null && nullToAbsent
|
|
||||||
? const Value.absent()
|
|
||||||
: Value(caloriesPer100g),
|
|
||||||
) as T;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ingredient copyWith({int id, String name, int caloriesPer100g}) => Ingredient(
|
|
||||||
id: id ?? this.id,
|
|
||||||
name: name ?? this.name,
|
|
||||||
caloriesPer100g: caloriesPer100g ?? this.caloriesPer100g,
|
|
||||||
);
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return (StringBuffer('Ingredient(')
|
|
||||||
..write('id: $id, ')
|
|
||||||
..write('name: $name, ')
|
|
||||||
..write('caloriesPer100g: $caloriesPer100g')
|
|
||||||
..write(')'))
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => $mrjf($mrjc(
|
|
||||||
$mrjc($mrjc(0, id.hashCode), name.hashCode), caloriesPer100g.hashCode));
|
|
||||||
@override
|
|
||||||
bool operator ==(other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
(other is Ingredient &&
|
|
||||||
other.id == id &&
|
|
||||||
other.name == name &&
|
|
||||||
other.caloriesPer100g == caloriesPer100g);
|
|
||||||
}
|
|
||||||
|
|
||||||
class IngredientsCompanion extends UpdateCompanion<Ingredient> {
|
|
||||||
final Value<int> id;
|
|
||||||
final Value<String> name;
|
|
||||||
final Value<int> caloriesPer100g;
|
|
||||||
const IngredientsCompanion({
|
|
||||||
this.id = const Value.absent(),
|
|
||||||
this.name = const Value.absent(),
|
|
||||||
this.caloriesPer100g = const Value.absent(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class $IngredientsTable extends Ingredients
|
|
||||||
with TableInfo<$IngredientsTable, Ingredient> {
|
|
||||||
final GeneratedDatabase _db;
|
|
||||||
final String _alias;
|
|
||||||
$IngredientsTable(this._db, [this._alias]);
|
|
||||||
final VerificationMeta _idMeta = const VerificationMeta('id');
|
|
||||||
GeneratedIntColumn _id;
|
|
||||||
@override
|
|
||||||
GeneratedIntColumn get id => _id ??= _constructId();
|
|
||||||
GeneratedIntColumn _constructId() {
|
|
||||||
return GeneratedIntColumn('id', $tableName, false, hasAutoIncrement: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
final VerificationMeta _nameMeta = const VerificationMeta('name');
|
|
||||||
GeneratedTextColumn _name;
|
|
||||||
@override
|
|
||||||
GeneratedTextColumn get name => _name ??= _constructName();
|
|
||||||
GeneratedTextColumn _constructName() {
|
|
||||||
return GeneratedTextColumn(
|
|
||||||
'name',
|
|
||||||
$tableName,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final VerificationMeta _caloriesPer100gMeta =
|
|
||||||
const VerificationMeta('caloriesPer100g');
|
|
||||||
GeneratedIntColumn _caloriesPer100g;
|
|
||||||
@override
|
|
||||||
GeneratedIntColumn get caloriesPer100g =>
|
|
||||||
_caloriesPer100g ??= _constructCaloriesPer100g();
|
|
||||||
GeneratedIntColumn _constructCaloriesPer100g() {
|
|
||||||
return GeneratedIntColumn(
|
|
||||||
'calories',
|
|
||||||
$tableName,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<GeneratedColumn> get $columns => [id, name, caloriesPer100g];
|
|
||||||
@override
|
|
||||||
$IngredientsTable get asDslTable => this;
|
|
||||||
@override
|
|
||||||
String get $tableName => _alias ?? 'ingredients';
|
|
||||||
@override
|
|
||||||
final String actualTableName = 'ingredients';
|
|
||||||
@override
|
|
||||||
VerificationContext validateIntegrity(IngredientsCompanion d,
|
|
||||||
{bool isInserting = false}) {
|
|
||||||
final context = VerificationContext();
|
|
||||||
if (d.id.present) {
|
|
||||||
context.handle(_idMeta, id.isAcceptableValue(d.id.value, _idMeta));
|
|
||||||
} else if (id.isRequired && isInserting) {
|
|
||||||
context.missing(_idMeta);
|
|
||||||
}
|
|
||||||
if (d.name.present) {
|
|
||||||
context.handle(
|
|
||||||
_nameMeta, name.isAcceptableValue(d.name.value, _nameMeta));
|
|
||||||
} else if (name.isRequired && isInserting) {
|
|
||||||
context.missing(_nameMeta);
|
|
||||||
}
|
|
||||||
if (d.caloriesPer100g.present) {
|
|
||||||
context.handle(
|
|
||||||
_caloriesPer100gMeta,
|
|
||||||
caloriesPer100g.isAcceptableValue(
|
|
||||||
d.caloriesPer100g.value, _caloriesPer100gMeta));
|
|
||||||
} else if (caloriesPer100g.isRequired && isInserting) {
|
|
||||||
context.missing(_caloriesPer100gMeta);
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Set<GeneratedColumn> get $primaryKey => {id};
|
|
||||||
@override
|
|
||||||
Ingredient map(Map<String, dynamic> data, {String tablePrefix}) {
|
|
||||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
|
|
||||||
return Ingredient.fromData(data, _db, prefix: effectivePrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, Variable> entityToSql(IngredientsCompanion d) {
|
|
||||||
final map = <String, Variable>{};
|
|
||||||
if (d.id.present) {
|
|
||||||
map['id'] = Variable<int, IntType>(d.id.value);
|
|
||||||
}
|
|
||||||
if (d.name.present) {
|
|
||||||
map['name'] = Variable<String, StringType>(d.name.value);
|
|
||||||
}
|
|
||||||
if (d.caloriesPer100g.present) {
|
|
||||||
map['calories'] = Variable<int, IntType>(d.caloriesPer100g.value);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
$IngredientsTable createAlias(String alias) {
|
|
||||||
return $IngredientsTable(_db, alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class IngredientInRecipe extends DataClass
|
|
||||||
implements Insertable<IngredientInRecipe> {
|
|
||||||
final int recipe;
|
|
||||||
final int ingredient;
|
|
||||||
final int amountInGrams;
|
|
||||||
IngredientInRecipe(
|
|
||||||
{@required this.recipe,
|
|
||||||
@required this.ingredient,
|
|
||||||
@required this.amountInGrams});
|
|
||||||
factory IngredientInRecipe.fromData(
|
|
||||||
Map<String, dynamic> data, GeneratedDatabase db,
|
|
||||||
{String prefix}) {
|
|
||||||
final effectivePrefix = prefix ?? '';
|
|
||||||
final intType = db.typeSystem.forDartType<int>();
|
|
||||||
return IngredientInRecipe(
|
|
||||||
recipe: intType.mapFromDatabaseResponse(data['${effectivePrefix}recipe']),
|
|
||||||
ingredient:
|
|
||||||
intType.mapFromDatabaseResponse(data['${effectivePrefix}ingredient']),
|
|
||||||
amountInGrams:
|
|
||||||
intType.mapFromDatabaseResponse(data['${effectivePrefix}amount']),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
factory IngredientInRecipe.fromJson(Map<String, dynamic> json,
|
|
||||||
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
|
|
||||||
return IngredientInRecipe(
|
|
||||||
recipe: serializer.fromJson<int>(json['recipe']),
|
|
||||||
ingredient: serializer.fromJson<int>(json['ingredient']),
|
|
||||||
amountInGrams: serializer.fromJson<int>(json['amountInGrams']),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@override
|
|
||||||
Map<String, dynamic> toJson(
|
|
||||||
{ValueSerializer serializer = const ValueSerializer.defaults()}) {
|
|
||||||
return {
|
|
||||||
'recipe': serializer.toJson<int>(recipe),
|
|
||||||
'ingredient': serializer.toJson<int>(ingredient),
|
|
||||||
'amountInGrams': serializer.toJson<int>(amountInGrams),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
T createCompanion<T extends UpdateCompanion<IngredientInRecipe>>(
|
|
||||||
bool nullToAbsent) {
|
|
||||||
return IngredientInRecipesCompanion(
|
|
||||||
recipe:
|
|
||||||
recipe == null && nullToAbsent ? const Value.absent() : Value(recipe),
|
|
||||||
ingredient: ingredient == null && nullToAbsent
|
|
||||||
? const Value.absent()
|
|
||||||
: Value(ingredient),
|
|
||||||
amountInGrams: amountInGrams == null && nullToAbsent
|
|
||||||
? const Value.absent()
|
|
||||||
: Value(amountInGrams),
|
|
||||||
) as T;
|
|
||||||
}
|
|
||||||
|
|
||||||
IngredientInRecipe copyWith(
|
|
||||||
{int recipe, int ingredient, int amountInGrams}) =>
|
|
||||||
IngredientInRecipe(
|
|
||||||
recipe: recipe ?? this.recipe,
|
|
||||||
ingredient: ingredient ?? this.ingredient,
|
|
||||||
amountInGrams: amountInGrams ?? this.amountInGrams,
|
|
||||||
);
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return (StringBuffer('IngredientInRecipe(')
|
|
||||||
..write('recipe: $recipe, ')
|
|
||||||
..write('ingredient: $ingredient, ')
|
|
||||||
..write('amountInGrams: $amountInGrams')
|
|
||||||
..write(')'))
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode => $mrjf($mrjc(
|
|
||||||
$mrjc($mrjc(0, recipe.hashCode), ingredient.hashCode),
|
|
||||||
amountInGrams.hashCode));
|
|
||||||
@override
|
|
||||||
bool operator ==(other) =>
|
|
||||||
identical(this, other) ||
|
|
||||||
(other is IngredientInRecipe &&
|
|
||||||
other.recipe == recipe &&
|
|
||||||
other.ingredient == ingredient &&
|
|
||||||
other.amountInGrams == amountInGrams);
|
|
||||||
}
|
|
||||||
|
|
||||||
class IngredientInRecipesCompanion extends UpdateCompanion<IngredientInRecipe> {
|
|
||||||
final Value<int> recipe;
|
|
||||||
final Value<int> ingredient;
|
|
||||||
final Value<int> amountInGrams;
|
|
||||||
const IngredientInRecipesCompanion({
|
|
||||||
this.recipe = const Value.absent(),
|
|
||||||
this.ingredient = const Value.absent(),
|
|
||||||
this.amountInGrams = const Value.absent(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class $IngredientInRecipesTable extends IngredientInRecipes
|
|
||||||
with TableInfo<$IngredientInRecipesTable, IngredientInRecipe> {
|
|
||||||
final GeneratedDatabase _db;
|
|
||||||
final String _alias;
|
|
||||||
$IngredientInRecipesTable(this._db, [this._alias]);
|
|
||||||
final VerificationMeta _recipeMeta = const VerificationMeta('recipe');
|
|
||||||
GeneratedIntColumn _recipe;
|
|
||||||
@override
|
|
||||||
GeneratedIntColumn get recipe => _recipe ??= _constructRecipe();
|
|
||||||
GeneratedIntColumn _constructRecipe() {
|
|
||||||
return GeneratedIntColumn(
|
|
||||||
'recipe',
|
|
||||||
$tableName,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final VerificationMeta _ingredientMeta = const VerificationMeta('ingredient');
|
|
||||||
GeneratedIntColumn _ingredient;
|
|
||||||
@override
|
|
||||||
GeneratedIntColumn get ingredient => _ingredient ??= _constructIngredient();
|
|
||||||
GeneratedIntColumn _constructIngredient() {
|
|
||||||
return GeneratedIntColumn(
|
|
||||||
'ingredient',
|
|
||||||
$tableName,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final VerificationMeta _amountInGramsMeta =
|
|
||||||
const VerificationMeta('amountInGrams');
|
|
||||||
GeneratedIntColumn _amountInGrams;
|
|
||||||
@override
|
|
||||||
GeneratedIntColumn get amountInGrams =>
|
|
||||||
_amountInGrams ??= _constructAmountInGrams();
|
|
||||||
GeneratedIntColumn _constructAmountInGrams() {
|
|
||||||
return GeneratedIntColumn(
|
|
||||||
'amount',
|
|
||||||
$tableName,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
List<GeneratedColumn> get $columns => [recipe, ingredient, amountInGrams];
|
|
||||||
@override
|
|
||||||
$IngredientInRecipesTable get asDslTable => this;
|
|
||||||
@override
|
|
||||||
String get $tableName => _alias ?? 'recipe_ingredients';
|
|
||||||
@override
|
|
||||||
final String actualTableName = 'recipe_ingredients';
|
|
||||||
@override
|
|
||||||
VerificationContext validateIntegrity(IngredientInRecipesCompanion d,
|
|
||||||
{bool isInserting = false}) {
|
|
||||||
final context = VerificationContext();
|
|
||||||
if (d.recipe.present) {
|
|
||||||
context.handle(
|
|
||||||
_recipeMeta, recipe.isAcceptableValue(d.recipe.value, _recipeMeta));
|
|
||||||
} else if (recipe.isRequired && isInserting) {
|
|
||||||
context.missing(_recipeMeta);
|
|
||||||
}
|
|
||||||
if (d.ingredient.present) {
|
|
||||||
context.handle(_ingredientMeta,
|
|
||||||
ingredient.isAcceptableValue(d.ingredient.value, _ingredientMeta));
|
|
||||||
} else if (ingredient.isRequired && isInserting) {
|
|
||||||
context.missing(_ingredientMeta);
|
|
||||||
}
|
|
||||||
if (d.amountInGrams.present) {
|
|
||||||
context.handle(
|
|
||||||
_amountInGramsMeta,
|
|
||||||
amountInGrams.isAcceptableValue(
|
|
||||||
d.amountInGrams.value, _amountInGramsMeta));
|
|
||||||
} else if (amountInGrams.isRequired && isInserting) {
|
|
||||||
context.missing(_amountInGramsMeta);
|
|
||||||
}
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Set<GeneratedColumn> get $primaryKey => {recipe, ingredient};
|
|
||||||
@override
|
|
||||||
IngredientInRecipe map(Map<String, dynamic> data, {String tablePrefix}) {
|
|
||||||
final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : null;
|
|
||||||
return IngredientInRecipe.fromData(data, _db, prefix: effectivePrefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Map<String, Variable> entityToSql(IngredientInRecipesCompanion d) {
|
|
||||||
final map = <String, Variable>{};
|
|
||||||
if (d.recipe.present) {
|
|
||||||
map['recipe'] = Variable<int, IntType>(d.recipe.value);
|
|
||||||
}
|
|
||||||
if (d.ingredient.present) {
|
|
||||||
map['ingredient'] = Variable<int, IntType>(d.ingredient.value);
|
|
||||||
}
|
|
||||||
if (d.amountInGrams.present) {
|
|
||||||
map['amount'] = Variable<int, IntType>(d.amountInGrams.value);
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
$IngredientInRecipesTable createAlias(String alias) {
|
|
||||||
return $IngredientInRecipesTable(_db, alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class _$Database extends GeneratedDatabase {
|
|
||||||
_$Database(QueryExecutor e) : super(const SqlTypeSystem.withDefaults(), e);
|
|
||||||
$CategoriesTable _categories;
|
|
||||||
$CategoriesTable get categories => _categories ??= $CategoriesTable(this);
|
|
||||||
$RecipesTable _recipes;
|
|
||||||
$RecipesTable get recipes => _recipes ??= $RecipesTable(this);
|
|
||||||
$IngredientsTable _ingredients;
|
|
||||||
$IngredientsTable get ingredients => _ingredients ??= $IngredientsTable(this);
|
|
||||||
$IngredientInRecipesTable _ingredientInRecipes;
|
|
||||||
$IngredientInRecipesTable get ingredientInRecipes =>
|
|
||||||
_ingredientInRecipes ??= $IngredientInRecipesTable(this);
|
|
||||||
@override
|
|
||||||
List<TableInfo> get allTables =>
|
|
||||||
[categories, recipes, ingredients, ingredientInRecipes];
|
|
||||||
}
|
|
|
@ -28,6 +28,7 @@ class UseMoor {
|
||||||
/// Optionally, a list of queries. Moor will generate matching methods for the
|
/// Optionally, a list of queries. Moor will generate matching methods for the
|
||||||
/// variables and return types.
|
/// variables and return types.
|
||||||
// todo better documentation
|
// todo better documentation
|
||||||
|
@experimental
|
||||||
final List<Sql> queries;
|
final List<Sql> queries;
|
||||||
|
|
||||||
/// Use this class as an annotation to inform moor_generator that a database
|
/// Use this class as an annotation to inform moor_generator that a database
|
||||||
|
@ -64,6 +65,7 @@ class UseDao {
|
||||||
/// The tables accessed by this DAO.
|
/// The tables accessed by this DAO.
|
||||||
final List<Type> tables;
|
final List<Type> tables;
|
||||||
// todo better documentation
|
// todo better documentation
|
||||||
|
@experimental
|
||||||
final List<Sql> queries;
|
final List<Sql> queries;
|
||||||
|
|
||||||
const UseDao({@required this.tables, this.queries});
|
const UseDao({@required this.tables, this.queries});
|
||||||
|
|
|
@ -52,7 +52,15 @@ class TableWithoutPK extends Table {
|
||||||
RealColumn get someFloat => real()();
|
RealColumn get someFloat => real()();
|
||||||
}
|
}
|
||||||
|
|
||||||
@UseMoor(tables: [TodosTable, Categories, Users, SharedTodos, TableWithoutPK])
|
@UseMoor(
|
||||||
|
tables: [TodosTable, Categories, Users, SharedTodos, TableWithoutPK],
|
||||||
|
queries: [
|
||||||
|
Sql(
|
||||||
|
'allTodosWithCategory',
|
||||||
|
'SELECT t.*, c.id as catId, c."desc" as catDesc '
|
||||||
|
'FROM todos t INNER JOIN categories c ON c.id = t.category'),
|
||||||
|
],
|
||||||
|
)
|
||||||
class TodoDb extends _$TodoDb {
|
class TodoDb extends _$TodoDb {
|
||||||
TodoDb(QueryExecutor e) : super(e);
|
TodoDb(QueryExecutor e) : super(e);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,11 +1,13 @@
|
||||||
import 'package:analyzer/dart/element/element.dart';
|
import 'package:analyzer/dart/element/element.dart';
|
||||||
import 'package:analyzer/dart/element/type.dart';
|
import 'package:analyzer/dart/element/type.dart';
|
||||||
import 'package:moor_generator/src/model/specified_table.dart';
|
import 'package:moor_generator/src/model/specified_table.dart';
|
||||||
|
import 'package:moor_generator/src/model/sql_query.dart';
|
||||||
|
|
||||||
class SpecifiedDatabase {
|
class SpecifiedDatabase {
|
||||||
final ClassElement fromClass;
|
final ClassElement fromClass;
|
||||||
final List<SpecifiedTable> tables;
|
final List<SpecifiedTable> tables;
|
||||||
final List<DartType> daos;
|
final List<DartType> daos;
|
||||||
|
final List<SqlQuery> queries;
|
||||||
|
|
||||||
SpecifiedDatabase(this.fromClass, this.tables, this.daos);
|
SpecifiedDatabase(this.fromClass, this.tables, this.daos, this.queries);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import 'package:moor_generator/src/model/specified_column.dart';
|
||||||
|
import 'package:moor_generator/src/model/specified_table.dart';
|
||||||
|
|
||||||
|
abstract class SqlQuery {
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
SqlQuery(this.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
class SqlSelectQuery extends SqlQuery {
|
||||||
|
final List<SpecifiedTable> readsFrom;
|
||||||
|
final InferredResultSet resultSet;
|
||||||
|
|
||||||
|
SqlSelectQuery(String name, this.readsFrom, this.resultSet) : super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
class InferredResultSet {
|
||||||
|
/// If the result columns of a SELECT statement exactly match one table, we
|
||||||
|
/// can just use the data class generated for that table. Otherwise, we'd have
|
||||||
|
/// to create another class.
|
||||||
|
// todo implement this check
|
||||||
|
final SpecifiedTable matchingTable;
|
||||||
|
final List<ResultColumn> columns;
|
||||||
|
|
||||||
|
InferredResultSet(this.matchingTable, this.columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
class ResultColumn {
|
||||||
|
final String name;
|
||||||
|
final ColumnType type;
|
||||||
|
final bool nullable;
|
||||||
|
|
||||||
|
ResultColumn(this.name, this.type, this.nullable);
|
||||||
|
}
|
|
@ -13,6 +13,9 @@ import 'package:moor_generator/src/parser/table_parser.dart';
|
||||||
import 'package:moor_generator/src/writer/database_writer.dart';
|
import 'package:moor_generator/src/writer/database_writer.dart';
|
||||||
import 'package:source_gen/source_gen.dart';
|
import 'package:source_gen/source_gen.dart';
|
||||||
|
|
||||||
|
import 'model/sql_query.dart';
|
||||||
|
import 'parser/sql/sql_parser.dart';
|
||||||
|
|
||||||
class MoorGenerator extends GeneratorForAnnotation<UseMoor> {
|
class MoorGenerator extends GeneratorForAnnotation<UseMoor> {
|
||||||
//final Map<String, ParsedLibraryResult> _astForLibs = {};
|
//final Map<String, ParsedLibraryResult> _astForLibs = {};
|
||||||
final ErrorStore errors = ErrorStore();
|
final ErrorStore errors = ErrorStore();
|
||||||
|
@ -47,11 +50,13 @@ class MoorGenerator extends GeneratorForAnnotation<UseMoor> {
|
||||||
.listValue
|
.listValue
|
||||||
.map((obj) => obj.toTypeValue())
|
.map((obj) => obj.toTypeValue())
|
||||||
.toList();
|
.toList();
|
||||||
|
final queries = annotation.peek('queries')?.listValue ?? [];
|
||||||
|
|
||||||
tableParser ??= TableParser(this);
|
tableParser ??= TableParser(this);
|
||||||
columnParser ??= ColumnParser(this);
|
columnParser ??= ColumnParser(this);
|
||||||
|
|
||||||
final tablesForThisDb = <SpecifiedTable>[];
|
final tablesForThisDb = <SpecifiedTable>[];
|
||||||
|
var resolvedQueries = <SqlQuery>[];
|
||||||
|
|
||||||
for (var table in tableTypes) {
|
for (var table in tableTypes) {
|
||||||
if (!tableTypeChecker.isAssignableFrom(table.element)) {
|
if (!tableTypeChecker.isAssignableFrom(table.element)) {
|
||||||
|
@ -67,7 +72,7 @@ class MoorGenerator extends GeneratorForAnnotation<UseMoor> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errors.errors.isNotEmpty) {
|
if (errors.errors.isNotEmpty) {
|
||||||
print('Warning: There were some errors whily running moor_generator:');
|
print('Warning: There were some errors while running moor_generator:');
|
||||||
|
|
||||||
for (var error in errors.errors) {
|
for (var error in errors.errors) {
|
||||||
print(error.message);
|
print(error.message);
|
||||||
|
@ -80,10 +85,17 @@ class MoorGenerator extends GeneratorForAnnotation<UseMoor> {
|
||||||
errors.errors.clear();
|
errors.errors.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (queries.isNotEmpty) {
|
||||||
|
final parser = SqlParser(options, tablesForThisDb, queries)..parse();
|
||||||
|
errors.errors.addAll(parser.errors);
|
||||||
|
|
||||||
|
resolvedQueries = parser.foundQueries;
|
||||||
|
}
|
||||||
|
|
||||||
if (_foundTables.isEmpty) return '';
|
if (_foundTables.isEmpty) return '';
|
||||||
|
|
||||||
final specifiedDb =
|
final specifiedDb = SpecifiedDatabase(
|
||||||
SpecifiedDatabase(element as ClassElement, tablesForThisDb, daoTypes);
|
element as ClassElement, tablesForThisDb, daoTypes, resolvedQueries);
|
||||||
|
|
||||||
final buffer = StringBuffer()
|
final buffer = StringBuffer()
|
||||||
..write('// ignore_for_file: unnecessary_brace_in_string_interps\n');
|
..write('// ignore_for_file: unnecessary_brace_in_string_interps\n');
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import 'package:sqlparser/sqlparser.dart';
|
||||||
|
|
||||||
|
/// An AST-visitor that walks sql statements and finds all tables referenced in
|
||||||
|
/// them.
|
||||||
|
class AffectedTablesVisitor extends RecursiveVisitor<void> {
|
||||||
|
final Set<Table> foundTables = {};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void visitReference(Reference e) {
|
||||||
|
final column = e.resolved as Column;
|
||||||
|
if (column is TableColumn) {
|
||||||
|
foundTables.add(column.table);
|
||||||
|
}
|
||||||
|
|
||||||
|
visitChildren(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void visitQueryable(Queryable e) {
|
||||||
|
if (e is TableReference) {
|
||||||
|
foundTables.add(e.resolved as Table);
|
||||||
|
}
|
||||||
|
|
||||||
|
visitChildren(e);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,126 @@
|
||||||
|
import 'package:analyzer/dart/constant/value.dart';
|
||||||
|
import 'package:moor_generator/src/errors.dart';
|
||||||
|
import 'package:moor_generator/src/model/specified_column.dart';
|
||||||
|
import 'package:moor_generator/src/model/specified_table.dart';
|
||||||
|
import 'package:moor_generator/src/model/sql_query.dart';
|
||||||
|
import 'package:moor_generator/src/options.dart';
|
||||||
|
import 'package:sqlparser/sqlparser.dart' hide ResultColumn;
|
||||||
|
|
||||||
|
import 'affected_tables_visitor.dart';
|
||||||
|
|
||||||
|
class SqlParser {
|
||||||
|
final MoorOptions options;
|
||||||
|
final List<SpecifiedTable> tables;
|
||||||
|
final List<DartObject> definedQueries;
|
||||||
|
|
||||||
|
SqlEngine _engine;
|
||||||
|
final Map<Table, SpecifiedTable> _engineTablesToSpecified = {};
|
||||||
|
|
||||||
|
final List<SqlQuery> foundQueries = [];
|
||||||
|
final List<MoorError> errors = [];
|
||||||
|
|
||||||
|
SqlParser(this.options, this.tables, this.definedQueries);
|
||||||
|
|
||||||
|
void _spawnEngine() {
|
||||||
|
_engine = SqlEngine();
|
||||||
|
tables.map(_extractStructure).forEach(_engine.registerTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Convert a [SpecifiedTable] from moor into something that can be understood
|
||||||
|
/// by the sqlparser library.
|
||||||
|
Table _extractStructure(SpecifiedTable table) {
|
||||||
|
final columns = <TableColumn>[];
|
||||||
|
for (var specified in table.columns) {
|
||||||
|
final type = _resolveForColumnType(specified.type)
|
||||||
|
.withNullable(specified.nullable);
|
||||||
|
columns.add(TableColumn(specified.name.name, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
final engineTable = Table(name: table.sqlName, resolvedColumns: columns);
|
||||||
|
_engineTablesToSpecified[engineTable] = table;
|
||||||
|
return engineTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResolvedType _resolveForColumnType(ColumnType type) {
|
||||||
|
switch (type) {
|
||||||
|
case ColumnType.integer:
|
||||||
|
return const ResolvedType(type: BasicType.int);
|
||||||
|
case ColumnType.text:
|
||||||
|
return const ResolvedType(type: BasicType.text);
|
||||||
|
case ColumnType.boolean:
|
||||||
|
return const ResolvedType(type: BasicType.int, hint: IsBoolean());
|
||||||
|
case ColumnType.datetime:
|
||||||
|
return const ResolvedType(type: BasicType.int, hint: IsDateTime());
|
||||||
|
case ColumnType.blob:
|
||||||
|
return const ResolvedType(type: BasicType.blob);
|
||||||
|
case ColumnType.real:
|
||||||
|
return const ResolvedType(type: BasicType.real);
|
||||||
|
}
|
||||||
|
throw StateError('cant happen');
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnType _resolvedToMoor(ResolvedType type) {
|
||||||
|
switch (type.type) {
|
||||||
|
case BasicType.nullType:
|
||||||
|
return ColumnType.text;
|
||||||
|
case BasicType.int:
|
||||||
|
if (type.hint is IsBoolean) {
|
||||||
|
return ColumnType.boolean;
|
||||||
|
} else if (type.hint is IsDateTime) {
|
||||||
|
return ColumnType.datetime;
|
||||||
|
}
|
||||||
|
return ColumnType.integer;
|
||||||
|
case BasicType.real:
|
||||||
|
return ColumnType.real;
|
||||||
|
case BasicType.text:
|
||||||
|
return ColumnType.text;
|
||||||
|
case BasicType.blob:
|
||||||
|
return ColumnType.blob;
|
||||||
|
}
|
||||||
|
throw StateError('Unexpected type: $type');
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse() {
|
||||||
|
_spawnEngine();
|
||||||
|
|
||||||
|
for (var query in definedQueries) {
|
||||||
|
final name = query.getField('name').toStringValue();
|
||||||
|
final sql = query.getField('query').toStringValue();
|
||||||
|
|
||||||
|
final context = _engine.analyze(sql);
|
||||||
|
|
||||||
|
for (var error in context.errors) {
|
||||||
|
errors.add(MoorError(
|
||||||
|
message: 'The sql query $sql is invalid: ${error.message}',
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
final root = context.root;
|
||||||
|
if (root is SelectStatement) {
|
||||||
|
_handleSelect(name, root, context);
|
||||||
|
} else {
|
||||||
|
throw StateError('Unexpected sql');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _handleSelect(
|
||||||
|
String queryName, SelectStatement stmt, AnalysisContext ctx) {
|
||||||
|
final tableFinder = AffectedTablesVisitor();
|
||||||
|
stmt.accept(tableFinder);
|
||||||
|
|
||||||
|
final foundTables = tableFinder.foundTables;
|
||||||
|
final moorTables = foundTables.map((t) => _engineTablesToSpecified[t]);
|
||||||
|
final resultColumns = stmt.resolvedColumns;
|
||||||
|
|
||||||
|
final moorColumns = <ResultColumn>[];
|
||||||
|
for (var column in resultColumns) {
|
||||||
|
final type = ctx.typeOf(column).type;
|
||||||
|
moorColumns
|
||||||
|
.add(ResultColumn(column.name, _resolvedToMoor(type), type.nullable));
|
||||||
|
}
|
||||||
|
|
||||||
|
final resultSet = InferredResultSet(null, moorColumns);
|
||||||
|
foundQueries.add(SqlSelectQuery(queryName, moorTables.toList(), resultSet));
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,8 @@ dependencies:
|
||||||
build_config: '>=0.3.1 <1.0.0'
|
build_config: '>=0.3.1 <1.0.0'
|
||||||
moor: ^1.4.0
|
moor: ^1.4.0
|
||||||
meta: '>= 1.0.0 <2.0.0'
|
meta: '>= 1.0.0 <2.0.0'
|
||||||
|
sqlparser:
|
||||||
|
path: ../sqlparser
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
test: ^1.6.0
|
test: ^1.6.0
|
||||||
test_api: ^0.2.0
|
test_api: ^0.2.0
|
||||||
|
|
|
@ -11,7 +11,9 @@ class TableColumn extends Column {
|
||||||
final String name;
|
final String name;
|
||||||
final ResolvedType type;
|
final ResolvedType type;
|
||||||
|
|
||||||
const TableColumn(this.name, this.type);
|
Table table;
|
||||||
|
|
||||||
|
TableColumn(this.name, this.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExpressionColumn extends Column {
|
class ExpressionColumn extends Column {
|
||||||
|
|
|
@ -23,5 +23,9 @@ class Table with ResultSet, VisibleToChildren {
|
||||||
@override
|
@override
|
||||||
final List<TableColumn> resolvedColumns;
|
final List<TableColumn> resolvedColumns;
|
||||||
|
|
||||||
Table({@required this.name, this.resolvedColumns});
|
Table({@required this.name, this.resolvedColumns}) {
|
||||||
|
for (var column in resolvedColumns) {
|
||||||
|
column.table = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ class ColumnResolver extends RecursiveVisitor<void> {
|
||||||
availableColumns.addAll(select.statement.resolvedColumns);
|
availableColumns.addAll(select.statement.resolvedColumns);
|
||||||
},
|
},
|
||||||
isJoin: (join) {
|
isJoin: (join) {
|
||||||
|
_handle(join.primary, availableColumns);
|
||||||
for (var query in join.joins.map((j) => j.query)) {
|
for (var query in join.joins.map((j) => j.query)) {
|
||||||
_handle(query, availableColumns);
|
_handle(query, availableColumns);
|
||||||
}
|
}
|
||||||
|
@ -52,6 +53,7 @@ class ColumnResolver extends RecursiveVisitor<void> {
|
||||||
relevantNode: resultColumn,
|
relevantNode: resultColumn,
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
usedColumns.addAll(tableResolver.resultSet.resolvedColumns);
|
usedColumns.addAll(tableResolver.resultSet.resolvedColumns);
|
||||||
} else {
|
} else {
|
||||||
// we have a * column, that would be all available columns
|
// we have a * column, that would be all available columns
|
||||||
|
|
|
@ -18,6 +18,7 @@ part 'expressions/subquery.dart';
|
||||||
part 'expressions/variables.dart';
|
part 'expressions/variables.dart';
|
||||||
|
|
||||||
part 'statements/select.dart';
|
part 'statements/select.dart';
|
||||||
|
part 'statements/statement.dart';
|
||||||
|
|
||||||
abstract class AstNode {
|
abstract class AstNode {
|
||||||
/// The parent of this node, or null if this is the root node. Will be set
|
/// The parent of this node, or null if this is the root node. Will be set
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
part of '../ast.dart';
|
part of '../ast.dart';
|
||||||
|
|
||||||
class SelectStatement extends AstNode with ResultSet {
|
class SelectStatement extends Statement with ResultSet {
|
||||||
final bool distinct;
|
final bool distinct;
|
||||||
final List<ResultColumn> columns;
|
final List<ResultColumn> columns;
|
||||||
final List<Queryable> from;
|
final List<Queryable> from;
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
part of '../ast.dart';
|
||||||
|
|
||||||
|
abstract class Statement extends AstNode {}
|
|
@ -37,7 +37,7 @@ class SqlEngine {
|
||||||
// todo error handling from scanner
|
// todo error handling from scanner
|
||||||
|
|
||||||
final parser = Parser(tokens);
|
final parser = Parser(tokens);
|
||||||
return parser.select();
|
return parser.statement();
|
||||||
}
|
}
|
||||||
|
|
||||||
AnalysisContext analyze(String sql) {
|
AnalysisContext analyze(String sql) {
|
||||||
|
|
|
@ -92,6 +92,12 @@ class Parser {
|
||||||
_error(message);
|
_error(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Statement statement() {
|
||||||
|
final stmt = select();
|
||||||
|
_matchOne(TokenType.semicolon);
|
||||||
|
return stmt;
|
||||||
|
}
|
||||||
|
|
||||||
/// Parses a [SelectStatement], or returns null if there is no select token
|
/// Parses a [SelectStatement], or returns null if there is no select token
|
||||||
/// after the current position.
|
/// after the current position.
|
||||||
///
|
///
|
||||||
|
|
|
@ -112,6 +112,9 @@ class Scanner {
|
||||||
case ':':
|
case ':':
|
||||||
_addToken(TokenType.colon);
|
_addToken(TokenType.colon);
|
||||||
break;
|
break;
|
||||||
|
case ';':
|
||||||
|
_addToken(TokenType.semicolon);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'x':
|
case 'x':
|
||||||
if (_match("'")) {
|
if (_match("'")) {
|
||||||
|
|
|
@ -76,6 +76,7 @@ enum TokenType {
|
||||||
limit,
|
limit,
|
||||||
offset,
|
offset,
|
||||||
|
|
||||||
|
semicolon,
|
||||||
eof,
|
eof,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,9 @@ void main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('correctly resolves return columns', () {
|
test('correctly resolves return columns', () {
|
||||||
final id = const TableColumn('id', ResolvedType(type: BasicType.int));
|
final id = TableColumn('id', const ResolvedType(type: BasicType.int));
|
||||||
final content =
|
final content =
|
||||||
const TableColumn('content', ResolvedType(type: BasicType.text));
|
TableColumn('content', const ResolvedType(type: BasicType.text));
|
||||||
|
|
||||||
final demoTable = Table(
|
final demoTable = Table(
|
||||||
name: 'demo',
|
name: 'demo',
|
||||||
|
|
|
@ -11,9 +11,9 @@ Map<String, ResolveResult> _types = {
|
||||||
};
|
};
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
final id = const TableColumn('id', ResolvedType(type: BasicType.int));
|
final id = TableColumn('id', const ResolvedType(type: BasicType.int));
|
||||||
final content =
|
final content =
|
||||||
const TableColumn('content', ResolvedType(type: BasicType.text));
|
TableColumn('content', const ResolvedType(type: BasicType.text));
|
||||||
|
|
||||||
final demoTable = Table(
|
final demoTable = Table(
|
||||||
name: 'demo',
|
name: 'demo',
|
||||||
|
|
Loading…
Reference in New Issue