primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
- initialRoute: '/configuration/list',
+ initialRoute: '/user/list',
onGenerateRoute: _getRoute,
);
}
export 'src/helper/settings.dart';
export 'src/helper/string_helper.dart';
export 'src/helper/validators.dart';
+export 'src/helper/helper_async.dart';
export 'src/model/button_model.dart';
export 'src/model/checkbox_model.dart';
export 'src/model/combobox_model.dart';
--- /dev/null
+/// Waits for a given amount of [millisec] and call then a [callback] function (if given).
+Future wait({int millisec = 50, Function callback}) {
+ callback ??= () => null;
+ return Future.delayed(Duration(milliseconds: millisec), callback());
+}
/// Returns the name including the names of the parent
@override
- String fullName() => '${section.name}.$name';
+ String fullName() => '${section?.name}.$name';
/// Parses the map and stores the data in the instance.
void parse() {
if (foreignKey != null &&
regExprForeignKey.firstMatch(foreignKey) == null) {
logger.error(
- 'invalid foreign key: $foreignKey expected: "<table>.<primary> <colName>" e.g. "role.role_id role_name"');
+ 'invalid foreign key in ${fullName()}: $foreignKey expected: "<table>.<primary> <colName>" e.g. "role.role_id role_name"');
}
checkOptionsByRegExpr(options, regExprOptions);
if (options.contains('primary')) {
/// A base class for combobox items like ComboboxModel, ColumnModel and DbReferenceModel.
abstract class ComboBaseModel extends FieldModel {
static final regExprListDbOption =
- RegExp(r'^\w+\.\w+;\w+ \w+(?:;(:? ?:\w+=[^ ]*?)+)?$');
+ RegExp(r'^\w+\.\w+\.\w+;\w+ \w+(?:;( ?:\w+=[^ ])*)?$');
static final regExprListConfiguration = RegExp(r'^scope:\w+$');
List<String> texts;
List values;
String listOption;
ComboboxListType listType;
+ ComboboxData data;
ComboBaseModel(SectionModel section, PageModel page, Map map,
WidgetModelType widgetType, BaseLogger logger)
: super.direct(section, page, map, widgetType, name, label, toolTip,
dataType, options, logger);
-/*
- SectionModel section,
- PageModel page,
- this.map,
- WidgetModelType fieldModelType,
- String name,
- String label,
- String toolTip,
- DataType dataType,
- List<String> options,
- BaseLogger logger,
-
- */
-
/// Parses the map and stores the data in the instance.
void parse() {
super.parse();
if (texts.isEmpty) {
logger.error('missing attribute "texts" in ${fullName()}');
listType = ComboboxListType.undef;
- } else if (values.isNotEmpty && texts.length != values.length) {
+ } else if (values != null &&
+ values.isNotEmpty &&
+ texts.length != values.length) {
logger.error(
'different sizes of "Texts" and "values": ${texts.length}/${values.length}');
listType = ComboboxListType.undef;
case ComboboxListType.dbColumn:
if (regExprListDbOption.firstMatch(listOption) == null) {
logger.error(
- 'wrong syntax in "listOption". Example: "role.list;role_name role_id;:role_name=%"');
+ 'wrong syntax in "listOption". Example: "all.role.list;role_name role_id;:role_name=%"');
listType = ComboboxListType.undef;
}
break;
}
}
+
+ /// Returns a [ComboboxData] related to the [dataType] with given [texts]
+ /// and [values].
+ static ComboboxData createByType(
+ DataType dataType, List<String> texts, Iterable values) {
+ ComboboxData rc;
+ switch (dataType) {
+ case DataType.bool:
+ rc = ComboboxData<bool>(texts, values);
+ break;
+ case DataType.currency:
+ case DataType.int:
+ case DataType.reference:
+ rc = ComboboxData<int>(texts, values);
+ break;
+ case DataType.date:
+ case DataType.dateTime:
+ rc = ComboboxData<DateTime>(texts, values);
+ break;
+ case DataType.float:
+ rc = ComboboxData<double>(texts, values);
+ break;
+ case DataType.string:
+ rc = ComboboxData<String>(texts, values);
+ break;
+ }
+ return rc;
+ }
}
class ComboboxData<T> {
/// Parses the map and stores the data in the instance.
void parse() {
- super.parse();
checkSuperfluousAttributes(
map,
- 'column label maxSize listOption listType name options rows toolTip texts values'
+ 'column filterType label maxSize listOption listType name options rows toolTip texts widgetType values'
.split(' '));
+ super.parse();
final columnName = parseString('column', map, required: true);
column = page.module.getColumn(columnName, this);
maxSize = parseInt('maxSize', map, required: false);
import '../module_model.dart';
class UserModel extends ModuleModel {
- static final model = <String, dynamic>{
+ static final mapUser = <String, dynamic>{
"module": "user",
"tables": [
{
'dataType': 'reference',
'label': 'Role',
'foreignKey': 'role.role_id role_name',
- 'listType': 'explicite',
- 'texts': ';-;Administrator;Benutzer;Gast;Verwalter',
- 'values': ';;1;2;3;4',
- //"listType": "dbColumn",
- //"listOption": "role.list;role_name role_id;:role_name=%",
+ //'listType': 'explicite',
+ //'texts': ';-;Administrator;Benutzer;Gast;Verwalter',
+ //'values': ';;1;2;3;4',
+ "listType": "dbColumn",
+ "listOption": "all.role.list;role_name role_id;:role_name=%",
},
]
},
"sectionType": "filterPanel",
"children": [
{
- "widgetType": "textField",
+ "widgetType": "dbReference",
"filterType": "pattern",
"name": "user_name",
- "label": "Name",
+ "column": "user_name",
+ "toolTip":
+ "Filter bezüglich des Names der anzuzeigenden Einträge: Joker '*' (beliebiger String) ist erlaubt."
},
{
- "widgetType": "combobox",
- "filterType": "equals",
+ "widgetType": "dbReference",
"name": "user_role",
- "label": "Rolle",
- "listType": "explicite",
- "texts": ";Alle Rollen;Administrator;Benutzer;Gast;Verwalter",
- "values": ";;1;2;3;4"
- //"listType": "dbColumn",
- //"listOption": "role.list;role_name role_id;:role_name=%",
+ "filterType": "equals",
+ "column": "user_role",
+ "toolTip":
+ "Filter bezüglich der Rolle der anzuzeigenden Einträge. '-' bedeutet keine Einschränkung"
}
]
}
]
};
- UserModel(BaseLogger logger) : super(model, logger);
+ UserModel(BaseLogger logger) : super(mapUser, logger);
/// Returns the name including the names of the parent
@override
int rows;
var value;
- final Map<String, dynamic> map;
-
TextFieldModel(
- SectionModel section, PageModel page, this.map, BaseLogger logger)
+ SectionModel section, PageModel page, Map map, BaseLogger logger)
: super(section, page, map, WidgetModelType.textField, logger);
+ TextFieldModel.direct(
+ SectionModel section,
+ PageModel page,
+ Map map,
+ String name,
+ String label,
+ String toolTip,
+ DataType dataType,
+ List<String> options,
+ BaseLogger logger)
+ : super.direct(section, page, null, WidgetModelType.textField, name,
+ label, toolTip, dataType, options, logger);
+
/// Dumps the internal structure into a [stringBuffer]
StringBuffer dump(StringBuffer stringBuffer) {
stringBuffer
import 'package:flutter/material.dart';
import 'package:flutter_bones/src/widget/callback_controller_bones.dart';
-import '../../widget/filter_set.dart';
+import '../../widget/widget_list.dart';
import '../../widget/list_form.dart';
import '../application_data.dart';
import 'configuration_controller.dart';
GlobalKey<FormState>(debugLabel: 'configuration_list');
Iterable<dynamic> rowsDeprecated;
ConfigurationController controller;
- FilterSet filters;
+ WidgetList filters;
ConfigurationListPageState(this.applicationData);
import 'package:flutter/material.dart';
import 'package:flutter_bones/src/widget/callback_controller_bones.dart';
-import '../../widget/filter_set.dart';
+import '../../widget/widget_list.dart';
import '../../widget/list_form.dart';
import '../application_data.dart';
import 'role_controller.dart';
GlobalKey<FormState>(debugLabel: 'role_list');
Iterable<dynamic> rowsDeprecated;
RoleController controller;
- FilterSet filters;
+ WidgetList filters;
RoleListPageState(this.applicationData);
import 'package:flutter/material.dart';
import 'package:flutter_bones/src/widget/callback_controller_bones.dart';
-import '../../widget/filter_set.dart';
+import '../../widget/widget_list.dart';
import '../../widget/list_form.dart';
import '../application_data.dart';
import 'user_controller.dart';
GlobalKey<FormState>(debugLabel: 'user_list');
Iterable<dynamic> rowsDeprecated;
UserController controller;
- FilterSet filters;
+ WidgetList filters;
UserListPageState(this.applicationData);
+ @override
+ void initState() {
+ super.initState();
+ controller =
+ UserController(_formKey, this, 'list', context, applicationData,
+ redrawCallback: (RedrawReason reason,
+ {String customString, RedrawCallbackFunctionSimple callback}) {
+ switch (reason) {
+ case RedrawReason.fetchList:
+ controller.buildRows();
+ break;
+ case RedrawReason.callback:
+ callback(RedrawReason.custom, customString);
+ setState(() {});
+ break;
+ default:
+ setState(() {});
+ break;
+ }
+ });
+ controller.initialize();
+ controller.buildWidgetList();
+ controller.buildRows();
+ controller.widgetList
+ .waitForCompletion(controller)
+ .then((result) => setState(() => null));
+ }
+
@override
Widget build(BuildContext context) {
- if (controller == null) {
- controller =
- UserController(_formKey, this, 'list', context, applicationData,
- redrawCallback: (RedrawReason reason,
- {String customString,
- RedrawCallbackFunctionSimple callback}) {
- switch (reason) {
- case RedrawReason.fetchList:
- controller.buildRows();
- break;
- case RedrawReason.callback:
- callback(RedrawReason.custom, customString);
- setState(() {});
- break;
- default:
- setState(() {});
- break;
- }
- });
- controller.initialize();
- controller.buildWidgetList();
- controller.buildRows();
- } else {
- controller = controller;
- }
- filters ??= controller.filterSet(pageName: 'list');
return Scaffold(
appBar: applicationData.appBarBuilder('Benutzer'),
drawer: applicationData.drawerBuilder(context),
/// Returns a record with primary key [id] of the [module] with the
/// SQL statement [sqlName].
- Future<Map<String, dynamic>> record(
+ Future<Map<String, dynamic>> recordById(
{@required String module, String sqlName, @required int id});
+ /// Returns a record specified by one or more [parameters] of the [module] with the
+ /// SQL statement [sqlName].
+ Future<Map<String, dynamic>> recordByParameter(
+ {@required String module,
+ @required String sqlName,
+ @required Map<String, dynamic> parameters});
+
/// Updates a record of [module] with the [data] using the SQL statement [sqlName].
Future update(
{@required String module,
import 'package:dart_bones/dart_bones.dart';
import 'package:flutter_bones/flutter_bones.dart';
import 'package:flutter_bones/src/model/combo_base_model.dart';
-import 'package:meta/meta.dart';
-import 'persistence.dart';
+
+/// Specifies an cache entry.
+class CacheEntry {
+ final String key;
+ final CacheEntryType entryType;
+ final List list;
+ bool ready;
+ bool oneTime;
+ CacheEntry(this.key, this.entryType, this.list,
+ {this.ready = false, this.oneTime = false});
+}
+
+enum CacheEntryType {
+ combobox,
+ record,
+ list,
+}
/// A cache for objects coming from a persistence layer.
/// Uses the least recently used algorithm to avoid overflow.
class PersistenceCache {
static PersistenceCache _instance;
- //static final regExpCombobox = RegExp(r'^\w\.\w+\.\w+;\w+ \w+;( ?:\w+=\S*)*$');
static final regExpCombobox =
RegExp(r'^\w+\.\w+\.\w+;\w+ \w+;( ?:\w+=\S*)*$');
+ static final regExpRecord = RegExp(r'^\w+\.\w+\.\w+;( ?:\w+=\S*)+$');
+ static int nextRecordNo = 0;
final leastReasentlyUsed = <CacheEntry>[];
final map = <String, CacheEntry>{};
final maxEntries;
- factory PersistenceCache() {
- return _instance;
- }
final ApplicationData application;
BaseLogger logger;
- PersistenceCache.internal(this.application, this.maxEntries) {
- this.logger = this.application.logger;
+ factory PersistenceCache() {
+ return _instance;
}
/// True constructor (of the singleton instance).
return _instance;
}
+ PersistenceCache.internal(this.application, this.maxEntries) {
+ this.logger = this.application.logger;
+ }
+
+ /// Returns a unique key for using record().
+ String buildRecordKeyPrefix() {
+ final rc = 'key${++nextRecordNo}';
+ return rc;
+ }
+
/// Returns the data (text, values) of a combobox specified by [key].
/// If the data are unavailable (e.g. a asynchronous request is running) the
/// result is null.
- /// [key] has the format:
+ /// The format of [key]:
/// "<id>.<module>.<sqlName>;<colText> <colValue>;<param1> <param2>..."
/// e.g. "x99.role.list;role_name role_id;:role_name=% :role_active=T"
/// If [hasUndef] is true the first combobox list entry is '-' with the value null.
- ComboboxData combobox(String key, {bool hasUndef = false}) {
+ /// If [oneTime] is true the result is only used one time, the LRU algoritm is
+ /// not used.
+ ComboboxData combobox(String key,
+ {bool hasUndef = false, bool oneTime = false}) {
ComboboxData rc;
if (regExpCombobox.firstMatch(key) == null) {
logger.error('wrong key syntax: $key');
final keyValue = element.split('=');
params2[keyValue[0]] = keyValue[1];
});
- final entry = CacheEntry(key, CacheEntryType.combobox, [
- hasUndef ? ['-'] : <String>[],
- hasUndef ? <dynamic>[null] : <dynamic>[]
- ]);
+ final entry = CacheEntry(
+ key,
+ CacheEntryType.combobox,
+ [
+ hasUndef ? ['-'] : <String>[],
+ hasUndef ? <dynamic>[null] : <dynamic>[]
+ ],
+ oneTime: oneTime);
insert(entry);
application.persistence
.list(
return rc;
}
+ /// Deletes an entry given by [key] from the cache.
+ /// Returns true on success.
+ bool deleteEntry(String key) {
+ bool rc = map.containsKey(key);
+ if (rc) {
+ leastReasentlyUsed.remove(map[key]);
+ map.remove(key);
+ }
+ return rc;
+ }
+
/// Inserts an [cacheEntry] into the cache.
void insert(CacheEntry cacheEntry) {
if (leastReasentlyUsed.length >= maxEntries) {
map.remove(leastReasentlyUsed[0].key);
leastReasentlyUsed.removeAt(0);
}
- leastReasentlyUsed.add(cacheEntry);
+ final offset = maxEntries > 50 ? 25 : maxEntries / 2;
+ if (cacheEntry.oneTime && leastReasentlyUsed.length > offset) {
+ leastReasentlyUsed.insert(offset, cacheEntry);
+ } else {
+ leastReasentlyUsed.add(cacheEntry);
+ }
map[cacheEntry.key] = cacheEntry;
}
+ /// Returns database record specified by [key].
+ /// If the data are unavailable (e.g. a asynchronous request is running) the
+ /// result is null, otherwise the result may be an empty list (record not found).
+ /// The format of [key]:
+ /// "<id>.<module>.<sqlName>;<param1> <param2>..."
+ /// e.g. "x99.role.by_name:role_name=eve :excluded=22"
+ /// If [oneTime] is true the result is only used one time, the LRU algoritm is
+ /// not used.
+ Map record(String key, {bool oneTime = true}) {
+ Map rc;
+ if (regExpRecord.firstMatch(key) == null) {
+ logger.error('wrong key syntax: $key');
+ } else if (map.containsKey(key)) {
+ final entry = updateLRU(key);
+ if (entry.ready) {
+ rc = entry.list[0];
+ }
+ } else {
+ final parts = key.split(';');
+ final idModuleName = parts[0].split('.');
+ final params = parts[1].split(' ');
+ final params2 = <String, dynamic>{};
+ params.forEach((element) {
+ final keyValue = element.split('=');
+ params2[keyValue[0]] = keyValue[1];
+ });
+ final entry =
+ CacheEntry(key, CacheEntryType.record, <Map>[null], oneTime: oneTime);
+ insert(entry);
+ application.persistence
+ .recordByParameter(
+ module: idModuleName[1],
+ sqlName: idModuleName[2],
+ parameters: params2)
+ .then((row) {
+ entry.list[0] = row;
+ entry.ready = true;
+ });
+ }
+ return rc;
+ }
+
/// Moves the entry specified by [key] at the top of the Least Recently Used
/// stack.
/// Returns the entry specified by [key].
CacheEntry updateLRU(String key) {
final entry = map[key];
- leastReasentlyUsed.remove(entry);
- leastReasentlyUsed.add(entry);
+ if (!entry.oneTime) {
+ leastReasentlyUsed.remove(entry);
+ leastReasentlyUsed.add(entry);
+ }
return entry;
}
}
-
-/// Specifies an cache entry.
-class CacheEntry {
- final String key;
- final CacheEntryType entryType;
- final List list;
- bool ready;
- CacheEntry(this.key, this.entryType, this.list, {this.ready = false});
-}
-
-enum CacheEntryType {
- combobox,
- record,
- list,
-}
@override
Future customQuery(
- {String module,
- String sqlName,
- String sqlType,
+ {@required String module,
+ @required String sqlName,
+ @required String sqlType,
Map<String, dynamic> params}) async {
var rc;
assert(['list', 'record', 'update'].contains(sqlType));
}
@override
- Future delete({String module, String sqlName, int id}) async {
+ Future delete(
+ {@required String module, String sqlName, @required int id}) async {
sqlName ??= 'delete';
await runRequest(module, sqlName, 'delete', body: '{":${module}_id":$id}');
}
@override
Future<int> insert(
- {String module, String sqlName, Map<String, dynamic> data}) async {
+ {@required String module,
+ String sqlName,
+ @required Map<String, dynamic> data}) async {
sqlName ??= 'insert';
var rc = 0;
final data2 = data == null ? '{}' : convert.jsonEncode(data);
}
@override
- Future<dynamic> list({String module, String sqlName, Map params}) async {
+ Future<dynamic> list(
+ {@required String module, String sqlName, Map params}) async {
sqlName ??= 'list';
Iterable<dynamic> rc;
final body = params == null ? '{}' : convert.jsonEncode(params);
}
@override
- Future<Map<String, dynamic>> record(
- {String module, String sqlName, int id}) async {
+ Future<Map<String, dynamic>> recordById(
+ {@required String module, String sqlName, @required int id}) async {
sqlName ??= 'record';
Map rc;
final answer = await runRequest(module, sqlName, 'record',
return rc;
}
+ @override
+ Future<Map<String, dynamic>> recordByParameter(
+ {@required String module,
+ @required String sqlName,
+ @required Map<String, dynamic> parameters}) async {
+ sqlName ??= 'record';
+ Map rc;
+ final answer = await runRequest(module, sqlName, 'record',
+ body: convert.jsonEncode(parameters));
+ if (answer.isNotEmpty) {
+ rc = convert.jsonDecode(answer);
+ }
+ return rc;
+ }
+
/// Handles a HTTP request with a single HTTP connection.
/// [module]: the module which implies the requested table.
/// [sqlName]: the name of the SQL statement.
@override
Future update(
- {String module, String sqlName, Map<String, dynamic> data}) async {
+ {@required String module,
+ String sqlName,
+ @required Map<String, dynamic> data}) async {
sqlName ??= 'update';
final data2 = data == null ? '{}' : convert.jsonEncode(data);
await runRequest(module, sqlName, 'update', body: data2);
import 'package:flutter/material.dart';
+import '../model/model_types.dart';
import '../model/combobox_model.dart';
import '../model/combo_base_model.dart';
import '../model/field_model.dart';
void buildRows();
/// Returns the [ComboboxData] (texts and values) of the [ComboboxModel] named [name].
- ComboboxData comboboxData<T>(String name);
+ ComboboxData comboboxData(String name, DataType dataType);
/// Frees all resources.
void dispose();
import 'package:flutter/material.dart';
import 'package:flutter_bones/flutter_bones.dart';
import 'package:flutter_bones/src/model/combo_base_model.dart';
-import 'package:flutter_bones/src/widget/dropdown_button_form_bone.dart';
import 'package:flutter_bones/src/widget/page_controller_bones.dart';
import 'text_form_field_bone.dart';
typedef FilterPredicate = bool Function(Map<String, dynamic> row);
+@deprecated
class FilterItem {
final String name;
final String label;
final FilterType filterType;
final String toolTip;
- final FilterPredicate filterPredicate;
var value;
FilterItem({
this.filterType,
this.toolTip,
this.name,
- this.filterPredicate,
});
-
- bool isValid(Map<String, dynamic> row) {
- bool rc = true;
- if (filterPredicate != null) {
- rc = filterPredicate(row);
- } else {
- final current = row[name].toString();
- final value2 = value ?? '';
- switch (filterType) {
- case FilterType.pattern:
- rc = value2 == ''
- ? true
- : (value2.startsWith('*')
- ? current.contains(value2.replaceAll('*', ''))
- : current.startsWith(value2));
- break;
- case FilterType.dateFrom:
- // TODO: Handle this case.
- break;
- case FilterType.dateTil:
- // TODO: Handle this case.
- break;
- case FilterType.dateTimeFrom:
- // TODO: Handle this case.
- break;
- case FilterType.dateTimeTil:
- // TODO: Handle this case.
- break;
- default:
- rc = true;
- break;
- }
- }
- return rc;
- }
}
+@deprecated
class FilterSet {
var filters = <FilterItem>[];
final BaseLogger logger;
return rc;
}
- /// Tests whether the [row] belongs to the result.
- bool isValid(Map<String, dynamic> row) {
- var rc = true;
- for (var filter in filters) {
- if (!filter.isValid(row)) {
- rc = false;
- break;
- }
- }
- return rc;
- }
-
dynamic valueOf(String name) => byName(name).value;
}
import 'package:flutter_bones/src/widget/page_controller_bones.dart';
import '../helper/string_helper.dart';
-import 'filter_set.dart';
+import 'widget_list.dart';
import 'page_controller_bones.dart';
import 'view.dart';
/// If [errorMessage] is not null this message will be shown.
static Form listForm(
{@required Key key,
- @required FilterSet filters,
+ @required WidgetList filters,
@required List<Widget> buttons,
@required List<Widget> titles,
@required List<String> columnNames,
String customString}) {
final padding =
configuration.asFloat('form.card.padding', defaultValue: 16.0);
+
final widgets = <Widget>[
- ...filters.getWidgets(),
+ ...filters.widgets,
SizedBox(
height: configuration.asFloat('form.gap.field_button.height',
defaultValue: 16.0)),
import 'package:flutter/material.dart';
+import 'package:flutter_bones/flutter_bones.dart';
import '../helper/string_helper.dart';
-import '../model/model_types.dart';
import '../model/column_model.dart';
import '../model/combo_base_model.dart';
-import '../model/page_model.dart';
-import '../model/module_model.dart';
import '../model/field_model.dart';
+import '../model/model_types.dart';
+import '../model/module_model.dart';
+import '../model/page_model.dart';
import '../page/application_data.dart';
import 'callback_controller_bones.dart';
-import 'filter_set.dart';
import 'view.dart';
import 'widget_list.dart';
widgetList.clear();
page.fields.forEach((model) {
final value = initialRow == null ? null : initialRow[model.name];
+ completeModelByPersistence(model);
widgetList.addWidget(model.name,
View(moduleModel.logger).modelToWidget(model, this, value));
});
}
+ /// Completes database based components to the model, e.g. the list for
+ /// comboboxes.
+ void completeModelByPersistence(WidgetModel model) {
+ if (model is ComboBaseModel) {
+ if (model.data == null) {
+ if (model.listType == ComboboxListType.explicite) {
+ model.data = ComboBaseModel.createByType(
+ model.dataType, model.texts, model.values);
+ model.data.waitState = WaitState.ready;
+ } else {
+ model.data = comboboxData(model.name, model.dataType);
+ }
+ }
+ }
+ }
+
@override
- ComboboxData comboboxData<T>(String name) {
+ ComboboxData comboboxData(String name, DataType dataType) {
+ ComboboxData rc;
+ switch (dataType) {
+ case DataType.bool:
+ rc = comboboxDataByType<bool>(name);
+ break;
+ case DataType.currency:
+ case DataType.int:
+ case DataType.reference:
+ rc = comboboxDataByType<int>(name);
+ break;
+ case DataType.date:
+ case DataType.dateTime:
+ rc = comboboxDataByType<DateTime>(name);
+ break;
+ case DataType.float:
+ rc = comboboxDataByType<double>(name);
+ break;
+ case DataType.string:
+ comboboxDataByType<String>(name);
+ break;
+ }
+ return rc;
+ }
+
+ ComboboxData<T> comboboxDataByType<T>(String name) {
ComboboxData rc = comboboxDataMap.containsKey(name)
? comboboxDataMap[name]
: ComboboxData<T>([], []);
comboboxDataMap[name] = rc;
break;
case ComboboxListType.dbColumn:
- comboboxDataDb(model, rc);
+ comboboxDataDb<T>(model, rc);
break;
case ComboboxListType.configuration:
break;
return rc;
}
- void comboboxDataDb(ComboBaseModel model, ComboboxData data) {
+ void comboboxDataDb<T>(ComboBaseModel model, ComboboxData<T> data) {
// example: role.list;role_displayname role_id;:role_name=% :excluded=0'
final parts = model.listOption.split(';');
final moduleName = parts[0].split('.');
/// Gets the data from the database using the [primaryId].
fetchData(int primaryId) async {
applicationData.persistence
- .record(module: moduleModel.name, id: primaryId)
+ .recordById(module: moduleModel.name, id: primaryId)
.then((row) {
page.fields.forEach((model) {
model.value = row[model.name];
});
}
- FilterSet filterSet({@required String pageName}) {
- final rc = FilterSet(globalKey, parent, this, moduleModel.logger);
+ /// Returns a [WidgetList] filled with widgets
+ WidgetList filterSet({@required String pageName}) {
+ final rc = WidgetList('${page.fullName()}.widgets', moduleModel.logger);
moduleModel
.pageByName(pageName)
.fields
.where((element) => element.filterType != null)
.forEach((element) {
- rc.add(FilterItem(
- label: element.label,
- filterType: element.filterType,
- toolTip: element.toolTip,
- name: element.name));
+ Widget widget = View().modelToWidget(element, this);
+ if (element.widgetModelType == WidgetModelType.combobox) {
+ rc.waitCandidates.add(element);
+ }
+ rc.addWidget(element.name, widget);
});
return rc;
}
ColumnModel primary = moduleModel.mainTable().primary;
final id = row[primary.name];
applicationData.persistence
- .record(module: moduleModel.name, id: id)
+ .recordById(module: moduleModel.name, id: id)
.then((row) => startChange(id, row));
}
return rc;
}
- /// Creates a combobox via the [controller].
- Widget combobox<T>(
+ /// Creates a combobox via the [controller] with an [initialValue].
+ Widget combobox(
FieldModel model, CallbackControllerBones controller, initialValue) {
- ComboboxData<T> comboboxData = controller.comboboxData(model.name);
+ Widget rc;
+ switch (model.dataType) {
+ case DataType.bool:
+ rc = comboboxByType<bool>(model, controller, initialValue);
+ break;
+ case DataType.currency:
+ case DataType.int:
+ case DataType.reference:
+ rc = comboboxByType<int>(model, controller, initialValue);
+ break;
+ case DataType.date:
+ case DataType.dateTime:
+ rc = comboboxByType<DateTime>(model, controller, initialValue);
+ break;
+ case DataType.float:
+ rc = comboboxByType<double>(model, controller, initialValue);
+ break;
+ case DataType.string:
+ comboboxByType<String>(model, controller, initialValue);
+ break;
+ }
+ return rc;
+ }
+
+ /// Creates a combobox via the [controller] depending on the type <T>
+ /// with an [initialValue].
+ Widget comboboxByType<T>(
+ FieldModel model, CallbackControllerBones controller, initialValue) {
+ ComboboxData<T> comboboxData = (model as ComboBaseModel).data;
final items = <DropdownMenuItem<T>>[];
for (var ix = 0; ix < comboboxData.texts.length; ix++) {
items.add(DropdownMenuItem(
return rc;
}
+ /// Creates a widget related to a [model] of type [DbReferenceModel]
+ /// via the [controller] with an [initialValue].
Widget dbReference(DbReferenceModel model, CallbackControllerBones controller,
dynamic initialValue) {
var rc;
import 'package:dart_bones/dart_bones.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/model/combo_base_model.dart';
import '../helper/string_helper.dart';
import '../model/model_types.dart';
final widgetMap = <String, Widget>{};
final widgets = <Widget>[];
+ /// Data that will be filled asynchronously.
+ final waitCandidates = <FieldModel>[];
+
WidgetList(this.name, this.logger);
/// Tests whether the widget list is empty.
widgets.clear();
widgetMap.clear();
}
+
+ /// Checks in a loop all open requests for completion.
+ /// If
+ Future waitForCompletion(PageControllerBones controller) async {
+ var again = true;
+ ComboboxData data;
+ // 30 sec:
+ int maxCount = 50 * 30;
+ while (again && maxCount > 0) {
+ again = false;
+ for (var model in waitCandidates) {
+ if (model is ComboBaseModel) {
+ data = controller.comboboxData(model.listOption, model.dataType);
+ if (data != null && data.waitState == WaitState.ready) {
+ model.data = data;
+ waitCandidates.remove(model);
+ } else {
+ again = true;
+ }
+ }
+ }
+ if (again) {
+ await wait(millisec: 20);
+ }
+ }
+ }
}
import 'package:dart_bones/dart_bones.dart';
import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/model/combo_base_model.dart';
import 'package:test/test.dart';
void main() {
final logger = MemoryLogger(LEVEL_FINE);
group('module', () {
test('module', () {
+ WidgetModel.lastId = 0;
logger.clear();
final module = Demo1(cloneOfMap(userModel), logger);
module.parse();
expect(table.fullName(), equals('demo1.user'));
expect(table.widgetName(), equals('user'));
final dump = module.dump(StringBuffer()).toString();
- expect(dump, '''= module demo1: options:
+ expect(dump, equals('''= module demo1: options:
== table user: options:
column user_id: DataType.int "Id" options: primary notnull unique
column user_name: DataType.string "User" options: unique
textField role: options:
button buttonStore: text: options: null
] # create.simpleForm1
-''');
+'''));
final userField = table.columnByName('user_id');
expect(userField, isNotNull);
expect(userField.widgetName(), 'user_id');
expect(userRef.widgetName(), equals('user'));
});
});
+ test('combobase-basic', () {
+ var data = ComboBaseModel.createByType(DataType.bool, ['x'], <bool>[true]);
+ expect(data, isNotNull);
+ data = ComboBaseModel.createByType(DataType.int, ['x'], <int>[3]);
+ expect(data, isNotNull);
+ data = ComboBaseModel.createByType(DataType.float, ['x'], <double>[3.9]);
+ expect(data, isNotNull);
+ data = ComboBaseModel.createByType(
+ DataType.date, ['x'], <DateTime>[DateTime(2020, 1, 1)]);
+ expect(data, isNotNull);
+ data = ComboBaseModel.createByType(DataType.string, ['x'], <String>["Hi"]);
+ expect(data, isNotNull);
+ });
+ test('combobase', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'tables': [
+ {
+ 'table': 'user',
+ 'columns': [
+ {
+ 'column': 'user_id',
+ 'dataType': 'int',
+ 'label': 'Id',
+ 'options': 'primary',
+ 'listType': 'explicite',
+ 'texts': ';a;b',
+ 'values': ';22;33'
+ },
+ ],
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final errors = logger.errors;
+ expect(errors.length, equals(1));
+ });
+ group('errors', () {
+ test('errors-combobase', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'tables': [
+ {
+ 'table': 'user',
+ 'columns': [
+ {
+ 'column': 'user_id',
+ 'dataType': 'int',
+ 'label': 'Id',
+ 'options': 'primary',
+ 'listType': 'undef',
+ },
+ ],
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final errors = logger.errors;
+ expect(errors.length, equals(2));
+ expect(
+ errors.contains(
+ 'wrong value "undef" in attribute "listType" in user.user_id'),
+ isTrue);
+ });
+ test('errors-missing-texts', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'tables': [
+ {
+ 'table': 'user',
+ 'columns': [
+ {
+ 'column': 'user_id',
+ 'dataType': 'int',
+ 'label': 'Id',
+ 'listType': 'explicite',
+ },
+ ],
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final errors = logger.errors;
+ expect(errors.length, equals(2));
+ expect(
+ errors.contains(
+ 'missing attribute "texts" in user.user_id'),
+ isTrue);
+ });
+ test('errors-#texts!=#values', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'tables': [
+ {
+ 'table': 'user',
+ 'columns': [
+ {
+ 'column': 'user_id',
+ 'dataType': 'int',
+ 'label': 'Id',
+ 'listType': 'explicite',
+ 'texts': ';a',
+ 'values': ';1;2',
+ },
+ ],
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final errors = logger.errors;
+ expect(errors.length, equals(2));
+ expect(
+ errors.contains(
+ 'different sizes of "Texts" and "values": 1/2'),
+ isTrue);
+ });
+ });
}
final userModel = <String, dynamic>{
'column': 'user_role',
'dataType': 'reference',
'label': 'Role',
- 'foreignKey': 'role.role_id',
+ 'foreignKey': 'role.role_id role_name',
'widgetType': 'combobox',
},
]
final logger = MemoryLogger(LEVEL_FINE);
group('module', () {
test('module', () {
+ WidgetModel.lastId = 0;
logger.clear();
final module = Demo1(cloneOfMap(userModel), logger);
module.parse();
expect(page?.fullName(), equals('demo1.create'));
expect(module.fullName(), equals('demo1'));
final dump = module.dump(StringBuffer()).toString();
- expect(dump, '''= module demo1: options:
+ expect(dump, equals('''= module demo1: options:
== table user: options:
- column user_id: DataType.int "Id" options: primary notnull unique
+ column user_id: DataType.int "Id" options: primary notnull unique readonly
column user_name: DataType.string "User" options: unique notnull
column user_role: DataType.reference "Role" options:
column user_createdat: DataType.dateTime "Erzeugt" options: hidden null
] # create.simpleForm1
== page change: PageModelType.change options:
= section simpleForm1: SectionModelType.simpleForm options: [
- allDbFields 12 options:
+ allDbFields 13 options:
] # change.simpleForm1
-''');
+'''));
final userField = page.fieldByName('user');
expect(userField, isNotNull);
expect(userField.widgetName(), 'user');
expect(button.section, equals(userField.section));
expect(button.fullName(), 'simpleForm1.buttonStore');
expect(button.widgetName(), 'buttonStore');
+ final all = module.pageByName('change').getWidgets(
+ (item) => item.widgetModelType == WidgetModelType.allDbFields);
+ expect(all.length, equals(1));
+ final widget = all[0];
+ final name = widget.fullName() + ' ' + widget.widgetName();
+ expect(name.contains('allDbFields'), isTrue);
+ });
+ });
+ group('page-errors', () {
+ test('add-button', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'tables': [
+ {
+ 'table': 'user',
+ 'columns': [
+ {
+ 'column': 'user_id',
+ 'dataType': 'int',
+ 'label': 'Id',
+ 'options': 'primary',
+ },
+ ]
+ },
+ ],
+ 'pages': [
+ {
+ "page": "list",
+ "pageType": "list",
+ "tableColumns": "user_id",
+ "tableTitles": ";Id;Name",
+ "sections": [
+ {
+ "sectionType": "filterPanel",
+ "children": [
+ {
+ "widgetType": "dbReference",
+ "filterType": "pattern",
+ "name": "user_name",
+ "column": "user_name",
+ },
+ ],
+ },
+ ],
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final page = module.pageByName('list');
+ page.addButton(ButtonModel.direct(
+ null,
+ page,
+ 'a',
+ 'b',
+ ButtonModelType.store,
+ [],
+ null,
+ logger));
+ page.addButton(ButtonModel.direct(
+ null,
+ page,
+ 'a',
+ 'b',
+ ButtonModelType.store,
+ [],
+ null,
+ logger));
+ page.buttonByName('unknown');
+ page.addField(TextFieldModel.direct(
+ null,
+ page,
+ null,
+ 'x',
+ 'y',
+ 'z',
+ DataType.int,
+ <String>[],
+ logger));
+ page.addField(TextFieldModel.direct(
+ null,
+ page,
+ null,
+ 'x',
+ 'y',
+ 'z',
+ DataType.int,
+ <String>[],
+ logger));
+ page.buttonByName('unknown');
+ page.fieldByName('nothing');
+ final errors = logger.errors;
+ expect(errors.length, equals(7));
+ expect(errors.contains('missing column user_name in table demo1.user'),
+ isTrue);
+ expect(
+ errors.contains('different sizes of tableTitles/tableColumns: 2/1'),
+ isTrue);
+ expect(errors.contains('button null.a already defined: null.a'),
+ isTrue);
+ expect(errors.contains('missing button unknown in page demo1.list'),
+ isTrue);
+ expect(errors.contains('missing field nothing in page demo1.list'),
+ isTrue);
+ expect(errors.contains('field list.x already defined: list.x'),
+ isTrue);
+ });
+ test('missing-section', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'pages': [
+ {
+ "page": "list",
+ "pageType": "list",
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final page = module.pageByName('list');
+ expect(page, isNotNull);
+ final errors = logger.errors;
+ expect(errors.length, equals(1));
+ expect(errors.contains('missing sections in page demo1.list'),
+ isTrue);
+ });
+ test('wrong-section', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'pages': [
+ {
+ "page": "list",
+ "pageType": "list",
+ "sections": "wrong"
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final page = module.pageByName('list');
+ expect(page, isNotNull);
+ final errors = logger.errors;
+ expect(errors.length, equals(1));
+ expect(errors.contains('"sections" is not an array in demo1.list: wrong'),
+ isTrue);
+ });
+ test('tableTitles not in list', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'pages': [
+ {
+ "page": "list",
+ "pageType": "change",
+ "tableTitles": ";a;b",
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final page = module.pageByName('list');
+ final errors = logger.errors;
+ expect(errors.length, equals(2));
+ expect(errors.contains(
+ 'tableTitles and tableColumns are only meaningful in list pages: demo1.list'),
+ isTrue);
+ expect(page.fullName() + page.widgetName(), equals('demo1.listlist'));
+ });
+ test('curious section', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'pages': [
+ {
+ "page": "list",
+ "pageType": "change",
+ "sections": [
+ [],
+ ]
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final page = module.pageByName('list');
+ final errors = logger.errors;
+ expect(errors.length, equals(1));
+ expect(errors.contains('curious item in section list of demo1.list: []'),
+ isTrue);
+ expect(page.fullName() + page.widgetName(), equals('demo1.listlist'));
});
});
group('ModelBase', () {
var errors = logger.errors;
expect(errors.length, equals(1));
expect(logger.contains('blub'), isTrue);
- logger.clearErrors();
+ logger.clear();
field['options'] = 3;
module = Demo1(map, logger);
+ logger.log('wrong option type: 3');
module.parse();
errors = logger.errors;
- expect(errors.length, equals(1));
+ expect(errors.length, greaterThan(0));
expect(logger.contains('wrong datatype'), isTrue);
// ===
logger.clear();
module = Demo1(map, logger);
module.parse();
errors = logger.errors;
- expect(errors.length, equals(3));
+ expect(errors.length, greaterThan(2));
expect(logger.contains('unknown attribute "newfeature"'), isTrue);
expect(
logger.contains(
// ===
logger.clear();
field.removeWhere(
- (key, value) => key == 'newfeature' || key == 'dataType');
+ (key, value) => key == 'newfeature' || key == 'dataType');
map['pages'][0].remove('pageType');
module = Demo1(map, logger);
module.parse();
map['pages'][0]['pageType'] = 'simpleForm';
errors = logger.errors;
- expect(errors.length, equals(2));
+ expect(errors.length, greaterThan(1));
expect(logger.contains('missing attribute \"pageType\" in demo1.create'),
isTrue);
});
});
group('CheckboxModel', () {
test('basic', () {
+ WidgetModel.lastId = 0;
logger.clear();
final map = cloneOfMap(userModel);
final field = <String, dynamic>{
expect(checkbox.value, isTrue);
});
test('errors', () {
+ WidgetModel.lastId = 0;
logger.clear();
final map = cloneOfMap(userModel);
final field = <String, dynamic>{
final dump = module.dump(StringBuffer()).toString();
expect(dump, equals('''= module demo1: options:
== table user: options:
- column user_id: DataType.int "Id" options: primary notnull unique
+ column user_id: DataType.int "Id" options: primary notnull unique readonly
column user_name: DataType.string "User" options: unique notnull
column user_role: DataType.reference "Role" options:
column user_createdat: DataType.dateTime "Erzeugt" options: hidden null
] # create.simpleForm1
== page change: PageModelType.change options:
= section simpleForm1: SectionModelType.simpleForm options: [
- allDbFields 102 options:
+ allDbFields 13 options:
] # change.simpleForm1
'''));
});
});
group('ComboboxModel', () {
+ WidgetModel.lastId = 0;
logger.clear();
test('basic', () {
final map = cloneOfMap(userModel);
final dump = module.dump(StringBuffer()).toString();
expect(dump, equals('''= module demo1: options:
== table user: options:
- column user_id: DataType.int "Id" options: primary notnull unique
+ column user_id: DataType.int "Id" options: primary notnull unique readonly
column user_name: DataType.string "User" options: unique notnull
column user_role: DataType.reference "Role" options:
column user_createdat: DataType.dateTime "Erzeugt" options: hidden null
] # create.simpleForm1
== page change: PageModelType.change options:
= section simpleForm1: SectionModelType.simpleForm options: [
- allDbFields 117 options:
+ allDbFields 30 options:
] # change.simpleForm1
'''));
});
});
- group('allDbFields', (){
- test('allDbFields', (){
+ group('allDbFields', () {
+ test('allDbFields', () {
+ WidgetModel.lastId = 0;
logger.clear();
final map = cloneOfMap(userModel);
var module = Demo1(map, logger);
});
group('Non field widgets', () {
test('basic', () {
+ WidgetModel.lastId = 0;
logger.clear();
final map = cloneOfMap(userModel);
final list = [
' ' + element.widgetName() + '/' + element.fullName();
});
expect(names.contains('null'), isFalse);
- final nonFieldWidgets = page.getWidgets((item) => [
+ final nonFieldWidgets = page.getWidgets((item) =>
+ [
WidgetModelType.text,
WidgetModelType.emptyLine
].contains(item.widgetModelType));
expect(nonFieldWidgets.length, equals(2));
});
});
+ group('section-errors', () {
+ test('missing children', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'pages': [
+ {
+ "page": "list",
+ "pageType": "list",
+ "sections": [
+ {
+ "sectionType": "filterPanel",
+ },
+ ],
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final errors = logger.errors;
+ expect(errors.length, equals(1));
+ expect(errors.contains('missing children in list.filterPanel1'),
+ isTrue);
+ });
+ test('wrong children', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'pages': [
+ {
+ "page": "list",
+ "pageType": "list",
+ "sections": [
+ {
+ "sectionType": "filterPanel",
+ "children": "a"
+ },
+ ],
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final errors = logger.errors;
+ expect(errors.length, equals(1));
+ expect(errors.contains('"children" is not a list in list.filterPanel1: a'),
+ isTrue);
+ });
+ test('not a map in children', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'pages': [
+ {
+ "page": "list",
+ "pageType": "list",
+ "sections": [
+ {
+ "sectionType": "filterPanel",
+ "children": [
+ []
+ ]
+ },
+ ],
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final errors = logger.errors;
+ expect(errors.length, equals(1));
+ expect(errors.contains('child 1 of "children" is not a map in list.filterPanel1: []'),
+ isTrue);
+ });
+ test('missing type in child', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'pages': [
+ {
+ "page": "list",
+ "pageType": "list",
+ "sections": [
+ {
+ "sectionType": "filterPanel",
+ "children": [
+ {},
+ ]
+ },
+ ],
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final errors = logger.errors;
+ expect(errors.length, equals(1));
+ expect(errors.contains('child 1 of "children" does not have "widgetType" in list.filterPanel1: {}'),
+ isTrue);
+ });
+ test('unknown type in child', () {
+ WidgetModel.lastId = 0;
+ logger.clear();
+ final map = <String, dynamic>{
+ 'module': 'demo1',
+ 'pages': [
+ {
+ "page": "list",
+ "pageType": "list",
+ "sections": [
+ {
+ "sectionType": "filterPanel",
+ "children": [
+ {
+ "widgetType": ""
+ },
+ ]
+ },
+ ],
+ },
+ ],
+ };
+ final module = ModuleModel(map, logger);
+ module.parse();
+ final errors = logger.errors;
+ expect(errors.length, equals(1));
+ expect(errors.contains('Section: unknown "widgetType" in list.filterPanel1'),
+ isTrue);
+ });
+ });
}
final userModel = <String, dynamic>{
'column': 'user_role',
'dataType': 'reference',
'label': 'Role',
- 'foreignKey': 'role.role_id',
+ 'foreignKey': 'role.role_id role_name',
'widgetType': 'combobox',
},
]
final logger = MemoryLogger(LEVEL_FINE);
group('module', () {
test('role', () {
+ WidgetModel.lastId = 0;
logger.clear();
final module = RoleModel(logger);
module.parse();
final dump = module.dump(StringBuffer()).toString();
expect(dump, '''= module role: options:
== table role: options:
- column role_id: DataType.int "Id" options: primary notnull unique
+ column role_id: DataType.int "Id" options: primary notnull unique readonly
column role_name: DataType.string "Rolle" options: unique notnull
column role_priority: DataType.int "Priorität" options:
column role_active: DataType.bool "Aktiv" options:
] # create.simpleForm1
== page change: PageModelType.change options:
= section simpleForm1: SectionModelType.simpleForm options: [
- allDbFields 13 options:
+ allDbFields 16 options:
] # change.simpleForm1
== page list: PageModelType.list options:
= section filterPanel1: SectionModelType.filterPanel options: [
''');
});
test('user', () {
+ WidgetModel.lastId = 0;
logger.clear();
final module = UserModel(logger);
module.parse();
final errors = logger.errors;
expect(errors.length, equals(0));
final dump = module.dump(StringBuffer()).toString();
- expect(dump, '''= module user: options:
+ expect(dump, equals('''= module user: options:
== table user: options:
- column user_id: DataType.int "Id" options: primary notnull unique
+ column user_id: DataType.int "Id" options: primary notnull unique readonly
column user_name: DataType.string "User" options: unique notnull
column user_displayname: DataType.string "Anzeigename" options: unique
column user_email: DataType.string "EMail" options: unique
- column user_password: DataType.string "User" options: password
+ column user_password: DataType.string "Passwort" options: password
column user_role: DataType.reference "Role" options:
column user_createdat: DataType.dateTime "Erzeugt" options: hidden null
column user_createdby: DataType.string "Erzeugt von" options: hidden
column user_changedby: DataType.string "Geändert von" options: hidden
== page create: PageModelType.create options:
= section simpleForm1: SectionModelType.simpleForm options: [
- allDbFields 31 options:
+ allDbFields 12 options:
] # create.simpleForm1
== page change: PageModelType.change options:
= section simpleForm1: SectionModelType.simpleForm options: [
- allDbFields 34 options:
+ allDbFields 20 options:
] # change.simpleForm1
== page list: PageModelType.list options:
= section filterPanel1: SectionModelType.filterPanel options: [
textField user_name: options:
- combobox user_role: texts: options:
+ textField user_role: options:
] # list.filterPanel1
-''');
+'''));
});
test('configuration', () {
+ WidgetModel.lastId = 0;
logger.clear();
final module = ConfigurationModel(logger);
module.parse();
final errors = logger.errors;
expect(errors.length, equals(0));
final dump = module.dump(StringBuffer()).toString();
- expect(dump, startsWith('''= module configuration: options:
+ expect(dump, equals('''= module configuration: options:
== table configuration: options:
- column configuration_id: DataType.int "Id" options: primary notnull unique
- column configuration_scope: DataType.string "Bereich" options: unique notnull
+ column configuration_id: DataType.int "Id" options: primary notnull unique readonly
+ column configuration_scope: DataType.string "Bereich" options: notnull
column configuration_property: DataType.string "Eigenschaft" options:
column configuration_order: DataType.int "Reihe" options:
column configuration_type: DataType.string "Datentyp" options:
column configuration_changedby: DataType.string "Geändert von" options: hidden
== page create: PageModelType.create options:
= section simpleForm1: SectionModelType.simpleForm options: [
- allDbFields'''));
- /*
- expect(dump.contains('''text: options:
+ allDbFields 13 options:
] # create.simpleForm1
== page change: PageModelType.change options:
= section simpleForm1: SectionModelType.simpleForm options: [
- allDbFields '''), isTrue);
- */
- expect(dump,
- contains('combobox configuration_scope: texts: options: undef'));
- expect(dump, contains('textField configuration_name: options:'));
+ allDbFields 22 options:
+ ] # change.simpleForm1
+== page list: PageModelType.list options:
+ = section filterPanel1: SectionModelType.filterPanel options: [
+ textField configuration_scope: options:
+ textField configuration_property: options:
+ ] # list.filterPanel1
+'''));
});
});
}
--- /dev/null
+import 'package:dart_bones/dart_bones.dart';
+import 'package:flutter_bones/flutter_bones.dart';
+import 'package:flutter_bones/src/widget/page_controller_bones.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() async {
+ final logger = MemoryLogger(LEVEL_FINE);
+ RestPersistence persistence;
+ BaseConfiguration configuration;
+ PageControllerBones pageControllerBones;
+ ApplicationData applicationData;
+ setUpAll(() {
+ configuration = BaseConfiguration({
+ 'client': {
+ 'host': 'localhost',
+ 'port': 58011,
+ 'schema': 'http',
+ 'application': 'unittest',
+ 'version': '1.0.0',
+ }
+ }, logger);
+ persistence = RestPersistence.fromConfig(configuration, logger);
+ pageControllerBones = PageControllerBones(
+ null, null, UserModel(logger), 'list', null, applicationData);
+ applicationData =
+ ApplicationData(configuration, null, null, persistence, logger);
+ });
+ group('Basics', () {
+ test('basic', () async {
+ expect(applicationData, isNotNull);
+ expect(pageControllerBones, isNotNull);
+ applicationData.pushCaller(pageControllerBones);
+ applicationData.popCaller();
+ applicationData.setLastErrorMessage('list', 'True error');
+ expect(applicationData.lastErrorMessage('list'), 'True error');
+ });
+ });
+}
});
group('basics', () {
test('combobox', () async {
+ logger.clear();
final cache2 = PersistenceCache();
expect(cache2, isNotNull);
const key = 'id1.role.list;role_name role_id;:role_name=%';
var data2 = cache.combobox(key2, hasUndef: false);
expect(data, isNull);
expect(data2, isNull);
- await sleep(200);
+ await wait(millisec: 200);
data = cache.combobox(key);
- await sleep(200);
+ await wait(millisec: 200);
data2 = cache.combobox(key2);
expect(logger.errors.length, equals(0));
expect(data, isNotNull);
expect(cache.leastReasentlyUsed.length, equals(2));
const key3 = 'id3.role.list;role_name role_id;:role_name=%';
var data3 = cache.combobox(key3, hasUndef: false);
+ expect(data3, isNull);
expect(cache.leastReasentlyUsed.length, equals(2));
expect(cache.map.containsKey(key), isFalse);
expect(cache.map.containsKey(key2), isTrue);
+ expect(cache.deleteEntry(key3), isTrue);
});
test('error', () {
logger.clear();
expect(logger.errors.length, equals(1));
expect(logger.contains('wrong key syntax: id1.role.list;role_name+role_id;:role_name=%'), isTrue);
});
+ test('record', () async {
+ logger.clear();
+ final cache2 = PersistenceCache();
+ expect(cache2, isNotNull);
+ const key = 'id1.role.by_role_name;:role_name=Administrator :excluded=0';
+ const key2 = 'id2.role.by_role_name;:role_name=Admistrator :excluded=1';
+ var data = cache.record(key, oneTime: true);
+ var data2 = cache.record(key2, oneTime: false);
+ expect(data, isNull);
+ expect(data2, isNull);
+ await wait(millisec: 200);
+ data = cache.record(key);
+ data2 = cache.record(key2);
+ await wait(millisec: 200);
+ expect(logger.errors.length, equals(0));
+ expect(data, isNotNull);
+ expect(data.containsKey('role_id'), isTrue);
+ expect(data2.isEmpty, isTrue);
+ });
});
}
-Future sleep(int millisec) {
- return Future.delayed(Duration(milliseconds: millisec), () => null);
-}
expect(list.length, greaterThanOrEqualTo(4));
expect(list[0].containsKey('role_id'), isTrue);
});
- test('record', () async {
+ test('recordById', () async {
final rest = RestPersistence();
- final record = await rest.record(module: 'role', id: 2);
+ final record = await rest.recordById(module: 'role', id: 2);
+ expect(record, isNotNull);
+ expect(record.length, greaterThan(4));
+ expect(record.containsKey('role_id'), isTrue);
+ });
+ test('recordByName', () async {
+ final rest = RestPersistence();
+ final record = await rest.recordByParameter(
+ module: 'role',
+ sqlName: 'by_role_name',
+ parameters: {':role_name': 'Administrator', ':excluded': 0});
expect(record, isNotNull);
expect(record.length, greaterThan(4));
expect(record.containsKey('role_id'), isTrue);
':role_active': 'T',
':role_changedby': 'eve'
});
- final answer = rest.record(module: 'role', id: id);
+ final answer = rest.recordById(module: 'role', id: id);
logger.log('log: $answer');
await rest.delete(module: 'role', id: id);
});
sql: "SELECT * from role WHERE role_name=:role_name&&role_id!=:excluded;"
- name: list
type: list
- sql: "SELECT * from role
+ sql: "SELECT t0.* from role t0
WHERE role_name like :role_name;"
'''));
});
import 'package:flutter/src/widgets/framework.dart' as x;
import 'package:flutter_bones/flutter_bones.dart';
import 'package:flutter_bones/src/widget/widget_helper.dart';
-import 'package:flutter_bones/src/private/bsettings.dart';
import 'package:test/test.dart';
void main() {
final logger = MemoryLogger();
final widgetConfiguration = BaseConfiguration({}, logger);
Settings(logger: logger, widgetConfiguration: widgetConfiguration);
-
+ Persistence persistence;
+ setUpAll(() {
+ final configuration = BaseConfiguration({
+ 'client': {
+ 'host': 'localhost',
+ 'port': 58011,
+ 'schema': 'http',
+ 'application': 'unittest',
+ 'version': '1.0.0',
+ }
+ }, logger);
+ persistence = RestPersistence.fromConfig(configuration, logger);
+ });
group('WidgetHelper', () {
test('toolTip', () {
final widget = Text('Hi');
});
group('ModuleController', () {
test('basic', () {
- ApplicationData appData = ApplicationData(
- BaseConfiguration({}, logger), (title) => null, (context) => null,
- BSettings.lastInstance.persistence, logger);
+ ApplicationData appData = ApplicationData(BaseConfiguration({}, logger),
+ (title) => null, (context) => null, persistence, logger);
final role = RoleCreatePage(appData);
if (appData.lastModuleState == null) {
role.createState();