--- /dev/null
+const theApplicationName = 'exhibition';
+const theVariantName = 'exhibition';
enum ServerEnvironment { productive, development }
typedef JsonMap = Map<String, dynamic>;
-typedef JsonList = List<JsonMap>;
+typedef JsonList = List<dynamic>;
///JsonMap or JsonList
typedef JsonData = Object;
-import 'package:exhibition/page/page_collection.dart';
+import 'package:exhibition/page/page_manager.dart';
import 'package:flutter/material.dart';
import 'package:dart_bones/dart_bones.dart';
page = LogPage();
break;
default:
- page = PageCollection().newPageByRoute(settings.name ?? '');
+ page = PageManager().newPageByRoute(settings.name ?? '');
break;
}
if (page != null) {
String moduleNameSingular = '',
String columnPrefix = '',
bool shortModifiedLabel = false}) {
- this.tableName = tableName.isEmpty ? moduleName : tableName;
+ this.tableName = tableName.isEmpty ? moduleName.toLowerCase() : tableName;
this.shortModifiedLabel = shortModifiedLabel;
if (moduleNameSingular.isEmpty) {
if (!moduleName.endsWith('s')) {
// DO NOT CHANGE. This file is created by the meta_tool
import 'module_meta_data.dart';
import 'roles_meta.dart';
+import 'structures_meta.dart';
import 'users_meta.dart';
+
/// Returns the meta data of the module given by [name].
/// Returns null if not found.
ModuleMetaData? moduleByName(String name) {
case 'Roles':
rc = RoleMeta();
break;
+ case 'Structures':
+ rc = StructureMeta();
+ break;
case 'Users':
rc = UserMeta();
break;
}
return rc;
}
+
/// Returns the module names as string list.
-List<String> moduleNames(){
+List<String> moduleNames() {
return [
'Roles',
+ 'Structures',
'Users',
];
}
--- /dev/null
+import '../base/defines.dart';
+import '../base/i18n.dart';
+import 'module_meta_data.dart';
+
+final i18n = I18N();
+final M = i18n.module("Structures");
+
+class StructureMeta extends ModuleMetaData {
+ static StructureMeta instance = StructureMeta.internal();
+ factory StructureMeta() {
+ return instance;
+ }
+ StructureMeta.internal()
+ : super('Structures', [
+ PropertyMetaData('id', i18n.tr('Id'), DataType.reference, ':primary:',
+ displayType: DisplayType.combobox),
+ PropertyMetaData(
+ 'scope', i18n.tr('Scope'), DataType.string, ':notnull:',
+ size: 64),
+ PropertyMetaData(
+ 'name', i18n.tr('Name', M), DataType.string, ':notnull:',
+ size: 64),
+ PropertyMetaData(
+ 'value', i18n.tr('Value', M), DataType.string, ':notnull:',
+ size: 32),
+ PropertyMetaData(
+ 'position', i18n.tr('Position', M), DataType.int, ''),
+ PropertyMetaData(
+ 'created', i18n.tr('Created'), DataType.datetime, ':hidden:'),
+ PropertyMetaData(
+ 'createdBy', i18n.tr('Created by'), DataType.string, ':hidden:',
+ size: 32),
+ PropertyMetaData(
+ 'changed', i18n.tr('Changed'), DataType.datetime, ':hidden:'),
+ PropertyMetaData(
+ 'changedBy', i18n.tr('Changed by'), DataType.string, ':hidden:',
+ size: 32),
+ ], [
+ PageMetaData('New Structure', PageType.create),
+ PageMetaData('Change Structure', PageType.edit),
+ PageMetaData('Delete Structure', PageType.delete),
+ PageMetaData('Structures Overview', PageType.list),
+ ]);
+}
size: 255),
PropertyMetaData(
'role', i18n.tr('Role'), DataType.reference, ':notnull:',
- displayType: DisplayType.combobox, foreignKey: 'roles.role_id;role_name;role'),
+ displayType: DisplayType.combobox,
+ foreignKey: 'roles.role_id;role_name;role'),
PropertyMetaData(
'created', i18n.tr('Created'), DataType.datetime, ':hidden:'),
PropertyMetaData(
+++ /dev/null
-// DO NOT CHANGE. This file is created by the meta_tool!
-import 'package:flutter/material.dart';
-import 'page_collection_custom.dart';
-
-import 'roles/create_role_page.dart';
-import 'roles/edit_role_page.dart';
-import 'roles/list_role_page.dart';
-import 'users/create_user_page.dart';
-import 'users/edit_user_page.dart';
-import 'users/delete_user_page.dart';
-import 'users/list_user_page.dart';
-
-
-/// Manages all meta data driven pages of the program.
-class PageCollection {
- static PageCollection? _instance;
- PageCollection.internal();
- factory PageCollection() {
- _instance ??= PageCollection.internal();
- return _instance!;
- }
- final map = <String, StatefulWidget>{};
-
- /// Creates a page defined by a [route].
- StatefulWidget? newPageByRoute(String route) {
- StatefulWidget? rc;
- final parts = route.split(';');
- final arg1 = parts.length < 2 ? 0 : int.parse(parts[1]);
- switch (parts[0]) {
- case '/roles/create':
- rc = CreateRolePage();
- break;
- case '/roles/edit':
- rc = EditRolePage(arg1);
- break;
- case '/roles/list':
- rc = ListRolePage();
- break;
- case '/users/create':
- rc = CreateUserPage();
- break;
- case '/users/edit':
- rc = EditUserPage(arg1);
- break;
- case '/users/delete':
- rc = DeleteUserPage(arg1);
- break;
- case '/users/list':
- rc = ListUserPage();
- break;
- default:
- rc = customPageByRoute(route);
- break;
- }
- if (rc != null) {
- map[route] = rc;
- }
- return rc;
- }
-
- /// Returns the last generated page of a given [route].
- StatefulWidget? existingPageByRoute(String route) {
- return map[route];
- }
-}
+++ /dev/null
-// This file is created by the meta_tool. But it can be customized.
-// It will never overridden by the meta_tool.
-import 'package:flutter/material.dart';
-import 'info_page.dart';
-import 'log_page.dart';
-
-/// Creates a page defined by a [route].
-///
-/// Note: only pages without meta data definitions should be handled here.
-StatefulWidget? customPageByRoute(String route) {
- StatefulWidget? rc;
- final parts = route.split(';');
- //final arg1 = parts.length < 2 ? 0 : int.parse(parts[1]);
- switch (parts[0]) {
- case '/info':
- rc = InfoPage();
- break;
- case '/log':
- rc = LogPage();
- break;
- default:
- break;
- }
- return rc;
-}
--- /dev/null
+// DO NOT CHANGE. This file is created by the meta_tool!
+import 'package:flutter/material.dart';
+import 'page_manager_custom.dart';
+
+import 'roles/create_role_page.dart';
+import 'roles/edit_role_page.dart';
+import 'roles/list_role_page.dart';
+import 'structures/create_structure_page.dart';
+import 'structures/edit_structure_page.dart';
+import 'structures/delete_structure_page.dart';
+import 'structures/list_structure_page.dart';
+import 'users/create_user_page.dart';
+import 'users/edit_user_page.dart';
+import 'users/delete_user_page.dart';
+import 'users/list_user_page.dart';
+
+/// Manages all meta data driven pages of the program.
+class PageManager {
+ static PageManager? _instance;
+ PageManager.internal();
+ factory PageManager() {
+ _instance ??= PageManager.internal();
+ return _instance!;
+ }
+ final map = <String, StatefulWidget>{};
+
+ /// Creates a page defined by a [route].
+ StatefulWidget? newPageByRoute(String route) {
+ StatefulWidget? rc;
+ final parts = route.split(';');
+ final arg1 = parts.length < 2 ? 0 : int.parse(parts[1]);
+ switch (parts[0]) {
+ case '/Roles/create':
+ rc = CreateRolePage();
+ break;
+ case '/Roles/edit':
+ rc = EditRolePage(arg1);
+ break;
+ case '/Roles/list':
+ rc = ListRolePage();
+ break;
+ case '/Structures/create':
+ rc = CreateStructurePage();
+ break;
+ case '/Structures/edit':
+ rc = EditStructurePage(arg1);
+ break;
+ case '/Structures/delete':
+ rc = DeleteStructurePage(arg1);
+ break;
+ case '/Structures/list':
+ rc = ListStructurePage();
+ break;
+ case '/Users/create':
+ rc = CreateUserPage();
+ break;
+ case '/Users/edit':
+ rc = EditUserPage(arg1);
+ break;
+ case '/Users/delete':
+ rc = DeleteUserPage(arg1);
+ break;
+ case '/Users/list':
+ rc = ListUserPage();
+ break;
+ default:
+ rc = customPageByRoute(route);
+ break;
+ }
+ if (rc != null) {
+ map[route] = rc;
+ }
+ return rc;
+ }
+
+ /// Returns the last generated page of a given [route].
+ StatefulWidget? existingPageByRoute(String route) {
+ return map[route];
+ }
+}
--- /dev/null
+// This file is created by the meta_tool. But it can be customized.
+// It will never overridden by the meta_tool.
+import 'package:flutter/material.dart';
+import 'info_page.dart';
+import 'log_page.dart';
+
+/// Creates a page defined by a [route].
+///
+/// Note: only pages without meta data definitions should be handled here.
+StatefulWidget? customPageByRoute(String route) {
+ StatefulWidget? rc;
+ final parts = route.split(';');
+ //final arg1 = parts.length < 2 ? 0 : int.parse(parts[1]);
+ switch (parts[0]) {
+ case '/info':
+ rc = InfoPage();
+ break;
+ case '/log':
+ rc = LogPage();
+ break;
+ default:
+ break;
+ }
+ return rc;
+}
appBar: globalData.appBarBuilder(i18n.tr('Change Role data')),
drawer: globalData.drawerBuilder(context),
body: SafeArea(
- child: WidgetForm.flexibleGrid(attendedPage!.attendedWidgets(),
+ child: WidgetForm.flexibleGridAttended(
+ attendedPage!.attendedWidgets(),
screenWidth: attendedPage!.pageStates.screenWidth,
padding: padding)));
return rc;
}
+
@override
void initState() {
super.initState();
}
class _CreateRolePageState extends CreateRoleCustom {
- _CreateRolePageState(): super();
+ _CreateRolePageState() : super();
@override
void didChangeDependencies() {
final size = MediaQuery.of(context).size;
appBar: globalData.appBarBuilder(i18n.tr('Change Role data')),
drawer: globalData.drawerBuilder(context),
body: SafeArea(
- child: WidgetForm.flexibleGrid(attendedPage!.attendedWidgets(),
+ child: WidgetForm.flexibleGridAttended(
+ attendedPage!.attendedWidgets(),
screenWidth: attendedPage!.pageStates.screenWidth,
padding: padding)));
return rc;
}
+
@override
void initState() {
super.initState();
}
class _EditRolePageState extends EditRoleCustom {
- _EditRolePageState(int primaryKey): super(primaryKey);
+ _EditRolePageState(int primaryKey) : super(primaryKey);
@override
void didChangeDependencies() {
final size = MediaQuery.of(context).size;
appBar: globalData.appBarBuilder(i18n.tr('Change Role data')),
drawer: globalData.drawerBuilder(context),
body: SafeArea(
- child: WidgetForm.flexibleGrid(attendedPage!.attendedWidgets(),
+ child: WidgetForm.flexibleGridAttended(
+ attendedPage!.attendedWidgets(),
screenWidth: attendedPage!.pageStates.screenWidth,
padding: padding)));
return rc;
}
+
@override
void initState() {
super.initState();
}
class _ListRolePageState extends ListRoleCustom {
- _ListRolePageState(): super();
+ _ListRolePageState() : super();
@override
void didChangeDependencies() {
final size = MediaQuery.of(context).size;
RestPersistence.fromConfig(configuration, logger),
logger);
globalData.initializeAsync().then((value) {
- globalData.navigate(context, '/users/edit');
+ globalData.navigate(context, '/Users/list');
});
}
});
--- /dev/null
+// This file is created by the meta_tool. But it can be customized.
+// It will never overridden by the meta_tool.
+import 'package:flutter/material.dart';
+
+import '../../base/i18n.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import '../../widget/widget_form.dart';
+import 'create_structure_page.dart';
+
+final i18n = I18N();
+
+class CreateStructureCustom extends State<CreateStructurePage> {
+ final globalData = GlobalData();
+ AttendedPage? attendedPage;
+
+ CreateStructureCustom();
+ @override
+ Widget build(BuildContext context) {
+ final padding = 16.0;
+ final rc = Scaffold(
+ appBar: globalData.appBarBuilder(i18n.tr('Change Structure data')),
+ drawer: globalData.drawerBuilder(context),
+ body: SafeArea(
+ child: WidgetForm.flexibleGridAttended(
+ attendedPage!.attendedWidgets(),
+ screenWidth: attendedPage!.pageStates.screenWidth,
+ padding: padding)));
+ return rc;
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ }
+}
--- /dev/null
+// DO NOT CHANGE. This file is created by the meta_tool!
+import 'package:flutter/material.dart';
+
+import '../../meta/structures_meta.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import 'create_structure_custom.dart';
+
+class CreateStructurePage extends StatefulWidget {
+ final PageStates pageStates = PageStates();
+ CreateStructurePage() : super();
+ @override
+ _CreateStructurePageState createState() {
+ final rc = _CreateStructurePageState();
+ rc.attendedPage = AttendedPage(
+ this, rc, GlobalData(), StructureMeta.instance, pageStates);
+ pageStates.attendedPage = rc.attendedPage;
+ return rc;
+ }
+}
+
+class _CreateStructurePageState extends CreateStructureCustom {
+ _CreateStructurePageState() : super();
+ @override
+ void didChangeDependencies() {
+ final size = MediaQuery.of(context).size;
+ attendedPage!.pageStates.screenWidth = size.width;
+ attendedPage!.pageStates.screenHeight = size.height;
+ super.didChangeDependencies();
+ }
+}
--- /dev/null
+// This file is created by the meta_tool. But it can be customized.
+// It will never overridden by the meta_tool.
+import 'package:flutter/material.dart';
+
+import '../../base/i18n.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import '../../widget/widget_form.dart';
+import 'delete_structure_page.dart';
+
+final i18n = I18N();
+
+class DeleteStructureCustom extends State<DeleteStructurePage> {
+ final int primaryKey;
+ final globalData = GlobalData();
+ AttendedPage? attendedPage;
+
+ DeleteStructureCustom(this.primaryKey);
+ @override
+ Widget build(BuildContext context) {
+ final padding = 16.0;
+ final rc = Scaffold(
+ appBar: globalData.appBarBuilder(i18n.tr('Change Structure data')),
+ drawer: globalData.drawerBuilder(context),
+ body: SafeArea(
+ child: WidgetForm.flexibleGridAttended(
+ attendedPage!.attendedWidgets(),
+ screenWidth: attendedPage!.pageStates.screenWidth,
+ padding: padding)));
+ return rc;
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ }
+}
--- /dev/null
+// DO NOT CHANGE. This file is created by the meta_tool!
+import 'package:flutter/material.dart';
+
+import '../../meta/structures_meta.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import 'delete_structure_custom.dart';
+
+class DeleteStructurePage extends StatefulWidget {
+ final int primaryKey;
+ final PageStates pageStates = PageStates();
+ DeleteStructurePage(this.primaryKey) : super();
+ @override
+ _DeleteStructurePageState createState() {
+ final rc = _DeleteStructurePageState(this.primaryKey);
+ rc.attendedPage = AttendedPage(
+ this, rc, GlobalData(), StructureMeta.instance, pageStates);
+ pageStates.attendedPage = rc.attendedPage;
+ return rc;
+ }
+}
+
+class _DeleteStructurePageState extends DeleteStructureCustom {
+ _DeleteStructurePageState(int primaryKey) : super(primaryKey);
+ @override
+ void didChangeDependencies() {
+ final size = MediaQuery.of(context).size;
+ attendedPage!.pageStates.screenWidth = size.width;
+ attendedPage!.pageStates.screenHeight = size.height;
+ super.didChangeDependencies();
+ }
+}
--- /dev/null
+// This file is created by the meta_tool. But it can be customized.
+// It will never overridden by the meta_tool.
+import 'package:flutter/material.dart';
+
+import '../../base/i18n.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import '../../widget/widget_form.dart';
+import 'edit_structure_page.dart';
+
+final i18n = I18N();
+
+class EditStructureCustom extends State<EditStructurePage> {
+ final int primaryKey;
+ final globalData = GlobalData();
+ AttendedPage? attendedPage;
+
+ EditStructureCustom(this.primaryKey);
+ @override
+ Widget build(BuildContext context) {
+ final padding = 16.0;
+ final rc = Scaffold(
+ appBar: globalData.appBarBuilder(i18n.tr('Change Structure data')),
+ drawer: globalData.drawerBuilder(context),
+ body: SafeArea(
+ child: WidgetForm.flexibleGridAttended(
+ attendedPage!.attendedWidgets(),
+ screenWidth: attendedPage!.pageStates.screenWidth,
+ padding: padding)));
+ return rc;
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ }
+}
--- /dev/null
+// DO NOT CHANGE. This file is created by the meta_tool!
+import 'package:flutter/material.dart';
+
+import '../../meta/structures_meta.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import 'edit_structure_custom.dart';
+
+class EditStructurePage extends StatefulWidget {
+ final int primaryKey;
+ final PageStates pageStates = PageStates();
+ EditStructurePage(this.primaryKey) : super();
+ @override
+ _EditStructurePageState createState() {
+ final rc = _EditStructurePageState(this.primaryKey);
+ rc.attendedPage = AttendedPage(
+ this, rc, GlobalData(), StructureMeta.instance, pageStates);
+ pageStates.attendedPage = rc.attendedPage;
+ return rc;
+ }
+}
+
+class _EditStructurePageState extends EditStructureCustom {
+ _EditStructurePageState(int primaryKey) : super(primaryKey);
+ @override
+ void didChangeDependencies() {
+ final size = MediaQuery.of(context).size;
+ attendedPage!.pageStates.screenWidth = size.width;
+ attendedPage!.pageStates.screenHeight = size.height;
+ super.didChangeDependencies();
+ }
+}
--- /dev/null
+// This file is created by the meta_tool. But it can be customized.
+// It will never overridden by the meta_tool.
+import 'package:flutter/material.dart';
+
+import '../../base/i18n.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import '../../widget/widget_form.dart';
+import 'list_structure_page.dart';
+
+final i18n = I18N();
+
+class ListStructureCustom extends State<ListStructurePage> {
+ final globalData = GlobalData();
+ AttendedPage? attendedPage;
+
+ ListStructureCustom();
+ @override
+ Widget build(BuildContext context) {
+ final padding = 16.0;
+ final rc = Scaffold(
+ appBar: globalData.appBarBuilder(i18n.tr('Change Structure data')),
+ drawer: globalData.drawerBuilder(context),
+ body: SafeArea(
+ child: WidgetForm.flexibleGridAttended(
+ attendedPage!.attendedWidgets(),
+ screenWidth: attendedPage!.pageStates.screenWidth,
+ padding: padding)));
+ return rc;
+ }
+
+ @override
+ void initState() {
+ super.initState();
+ }
+}
--- /dev/null
+// DO NOT CHANGE. This file is created by the meta_tool!
+import 'package:flutter/material.dart';
+
+import '../../meta/structures_meta.dart';
+import '../../setting/global_data.dart';
+import '../../widget/attended_page.dart';
+import 'list_structure_custom.dart';
+
+class ListStructurePage extends StatefulWidget {
+ final PageStates pageStates = PageStates();
+ ListStructurePage() : super();
+ @override
+ _ListStructurePageState createState() {
+ final rc = _ListStructurePageState();
+ rc.attendedPage = AttendedPage(
+ this, rc, GlobalData(), StructureMeta.instance, pageStates);
+ pageStates.attendedPage = rc.attendedPage;
+ return rc;
+ }
+}
+
+class _ListStructurePageState extends ListStructureCustom {
+ _ListStructurePageState() : super();
+ @override
+ void didChangeDependencies() {
+ final size = MediaQuery.of(context).size;
+ attendedPage!.pageStates.screenWidth = size.width;
+ attendedPage!.pageStates.screenHeight = size.height;
+ super.didChangeDependencies();
+ }
+}
appBar: globalData.appBarBuilder(i18n.tr('Change User data')),
drawer: globalData.drawerBuilder(context),
body: SafeArea(
- child: WidgetForm.flexibleGrid(attendedPage!.attendedWidgets(),
+ child: WidgetForm.flexibleGridAttended(
+ attendedPage!.attendedWidgets(),
screenWidth: attendedPage!.pageStates.screenWidth,
padding: padding)));
return rc;
}
+
@override
void initState() {
super.initState();
}
class _CreateUserPageState extends CreateUserCustom {
- _CreateUserPageState(): super();
+ _CreateUserPageState() : super();
@override
void didChangeDependencies() {
final size = MediaQuery.of(context).size;
appBar: globalData.appBarBuilder(i18n.tr('Change User data')),
drawer: globalData.drawerBuilder(context),
body: SafeArea(
- child: WidgetForm.flexibleGrid(attendedPage!.attendedWidgets(),
+ child: WidgetForm.flexibleGridAttended(
+ attendedPage!.attendedWidgets(),
screenWidth: attendedPage!.pageStates.screenWidth,
padding: padding)));
return rc;
}
+
@override
void initState() {
super.initState();
}
class _DeleteUserPageState extends DeleteUserCustom {
- _DeleteUserPageState(int primaryKey): super(primaryKey);
+ _DeleteUserPageState(int primaryKey) : super(primaryKey);
@override
void didChangeDependencies() {
final size = MediaQuery.of(context).size;
appBar: globalData.appBarBuilder(i18n.tr('Change User data')),
drawer: globalData.drawerBuilder(context),
body: SafeArea(
- child: WidgetForm.flexibleGrid(attendedPage!.attendedWidgets(),
+ child: WidgetForm.flexibleGridAttended(
+ attendedPage!.attendedWidgets(),
screenWidth: attendedPage!.pageStates.screenWidth,
padding: padding)));
return rc;
}
+
@override
void initState() {
super.initState();
}
class _EditUserPageState extends EditUserCustom {
- _EditUserPageState(int primaryKey): super(primaryKey);
+ _EditUserPageState(int primaryKey) : super(primaryKey);
@override
void didChangeDependencies() {
final size = MediaQuery.of(context).size;
class ListUserCustom extends State<ListUserPage> {
final globalData = GlobalData();
+ final fieldData = FieldData();
AttendedPage? attendedPage;
-
+ final textController = TextEditingController();
ListUserCustom();
@override
Widget build(BuildContext context) {
final padding = 16.0;
- final filters = WidgetForm.flexibleGrid(attendedPage!.attendedWidgets(),
- screenWidth: attendedPage!.pageStates.screenWidth, padding: padding);
+ final itemsRole = <DropdownMenuItem<int>>[];
+ final fieldWidgets = <Widget>[
+ TextFormField(
+ controller: textController,
+ decoration: InputDecoration(labelText: i18n.tr('Text')),
+ onChanged: (value) => fieldData.text = value,
+ ),
+ DropdownButtonFormField<int>(
+ value: fieldData.role,
+ items: itemsRole,
+ isExpanded: true,
+ decoration: InputDecoration(labelText: i18n.tr('Role')),
+ onChanged: (value) => fieldData.role = value ?? 0,
+ ),
+ ];
+ final weights = [6, 6];
+ final form = WidgetForm.flexibleGrid(fieldWidgets,
+ weights: weights,
+ screenWidth: attendedPage!.pageStates.screenWidth,
+ padding: padding);
final rows = attendedPage!.getRows(
- 'user_id;user_displayname;user_email;role',
- '/users/list',
- {},
- () => setState(() => 1),
- '/users/edit',
- context);
+ columnList: 'user_id;user_displayname;user_email;role',
+ what: 'query',
+ parameters: {
+ 'module': 'Users',
+ 'sql': 'list',
+ 'offset': '0',
+ 'size': '10'
+ },
+ onDone: () => setState(() => 1),
+ routeEdit: '/users/edit',
+ context: context);
final table = DataTable(
columns: <DataColumn>[
DataColumn(
rows: rows,
);
final frameWidget = Column(children: [
- filters,
+ form,
SizedBox(height: padding),
SizedBox(width: double.infinity, child: table),
]);
final rc = Scaffold(
appBar: globalData.appBarBuilder(i18n.tr('Change User data')),
drawer: globalData.drawerBuilder(context),
+ floatingActionButton: FloatingActionButton(
+ onPressed: () {
+ globalData.navigate(context, '/Users/create');
+ },
+ child: const Icon(Icons.add),
+ //backgroundColor: Colors.green,
+ ),
body: SafeArea(child: frameWidget));
return rc;
}
super.initState();
}
}
+
+class FieldData {
+ String text = '';
+ int role = 0;
+}
}
class _ListUserPageState extends ListUserCustom {
- _ListUserPageState(): super();
+ _ListUserPageState() : super();
@override
void didChangeDependencies() {
final size = MediaQuery.of(context).size;
} else {
final content = await file.readAsString();
final data = convert.jsonDecode(content);
- if (data is Map){
+ if (data is Map) {
rc = DbData.single(data as JsonMap);
- } else if (data is List){
- rc = DbData.list(data as JsonList, -1);
- } else if (data is String){
+ } else if (data is List) {
+ rc = DbData.list(data, -1);
+ } else if (data is String) {
rc = DbData.message(data);
} else {
rc = DbData.message('unknown data type: ${data.runtimeType}');
final int? count;
final String? message;
DbData(this.singleRecord, this.recordList, this.count, this.message);
- DbData.single(JsonMap record): this(record, null, null, null);
- DbData.list(JsonList records, int count): this(null, records, count, null);
- DbData.message(String message): this(null, null, null, message);
+ DbData.single(JsonMap record) : this(record, null, null, null);
+ DbData.list(JsonList records, int count) : this(null, records, count, null);
+ DbData.message(String message) : this(null, null, null, message);
}
+
abstract class Persistence {
/// Fetches data specified by [what] and some [data].
///
import 'package:dart_bones/dart_bones.dart';
import 'package:http/http.dart' as http;
+import '../../base/defines.dart';
import 'data_record.dart';
import 'persistence.dart';
import '../setting/error_handler_exhibition.dart';
{String? body, Map<String, String>? headers}) async {
var rc = '';
final uri =
- Uri(scheme: scheme, host: host, port: port, path: '/$what/$version');
+ Uri(scheme: scheme, host: host, port: port, path: '$what/$version');
http.Response response;
logger.log('request: POST $uri', LEVEL_LOOP);
try {
DbData rc;
final params2 = data == null ? '{}' : convert.jsonEncode(data);
final answer = await runRequest(what, body: params2, headers: jsonHeader);
- if (answer.isEmpty){
+ if (answer.isEmpty) {
rc = DbData.message('query(): empty result');
- } else if (answer.startsWith('{')){
+ } else if (answer.startsWith('{')) {
rc = DbData.single(convert.jsonDecode(answer));
} else if (answer.startsWith('[')) {
rc = DbData.list(convert.jsonDecode(answer), -1);
} else if (answer.startsWith('#')) {
int ix = answer.indexOf('[');
- if (ix > 2 && ix < 8){
+ if (ix >= 2 && ix < 8) {
final count = int.tryParse(answer.substring(1, ix));
- rc = DbData.list(convert.jsonDecode(answer.substring(ix)), count ?? -1);
+ final data = convert.jsonDecode(answer.substring(ix));
+ rc = DbData.list(data as JsonList, count ?? -1);
} else {
- rc = DbData.message(
- 'query(): unexpected answer prefix: '
+ rc = DbData.message('query(): unexpected answer prefix: '
'${answer.substring(0, min<int>(answer.length, 8))}');
}
} else {
- rc = DbData.message(answer.substring(0, max<int>(answer.length, 120)));
+ rc = DbData.message(answer.substring(0, max<int>(answer.length, 120)));
}
if (logger.logLevel >= LEVEL_FINE) {
logger.log('answer: ${limitString(answer, sqlTraceLimit)}');
import 'package:dart_bones/dart_bones.dart';
-import 'package:exhibition/page/page_collection.dart';
+import 'package:exhibition/page/page_manager.dart';
import 'package:flutter/material.dart';
import 'global_data.dart';
static List<MenuItem> menuItems(MenuConverter converter) {
final globalData = GlobalData();
final logger = globalData.logger;
- final collection = PageCollection();
+ final collection = PageManager();
return <MenuItem>[
MenuItem('Users', () => collection.newPageByRoute('/users/list'),
converter.iconByName('people_outlined', logger)),
+import 'dart:io';
import 'package:dart_bones/dart_bones.dart';
-import 'package:exhibition/page/page_collection.dart';
+import 'package:exhibition/page/page_manager.dart';
import 'package:exhibition/persistence/rest_persistence.dart';
import 'package:exhibition/widget/attended_page.dart';
import 'package:flutter/material.dart';
+import 'package:path/path.dart' as path;
+import 'package:path_provider/path_provider.dart';
+import '../base/application_name.dart';
import '../base/defines.dart';
import '../page/page_controller_exhibition.dart';
Widget widget(PageControllerExhibition controller);
}
+class HomeDirectories {
+ Directory configurations = Directory.current;
+ Directory localData = Directory.current;
+ HomeDirectories.dummy();
+ HomeDirectories(String applicationName) {
+ if (Platform.isLinux) {
+ configurations = Directory('/etc/$applicationName');
+ localData = Directory(path.join('/home', Platform.environment['LOGNAME'],
+ '.local/share/$applicationName'));
+ } else if (Platform.isAndroid) {
+ getExternalStorageDirectory().then((dir) => localData = dir!);
+ } else {
+ throw FormatException('HomeDirectory.getHomePath(): unknown platform');
+ }
+ }
+}
+
/// Storage for global resources. This is a singleton.
class GlobalData {
static const version = '2021.08.24.00';
static GlobalData? _instance;
static String baseDirectory = '';
static var serverEnvironment = ServerEnvironment.productive;
-
+ static final String applicationName = theApplicationName;
final BaseLogger logger;
final AppBarBuilder appBarBuilder;
final DrawerBuilder drawerBuilder;
final FooterBuilder footerBuilder;
final BaseConfiguration configuration;
final RestPersistence? restPersistence;
+ HomeDirectories homeDirectories = HomeDirectories.dummy();
AttendedPage? currentPage;
factory GlobalData() => _instance ?? GlobalData();
/// Switches the page given by a [route].
void navigate(BuildContext context, String route) {
- final page = PageCollection().existingPageByRoute(route);
+ final page = PageManager().existingPageByRoute(route);
if (page != null) {
currentPage = page as AttendedPage;
}
import 'dart:convert' as convert;
import 'dart:io';
+import 'package:yaml/yaml.dart';
import 'package:dart_bones/dart_bones.dart';
import 'package:path/path.dart' as path;
import 'package:permission_handler/permission_handler.dart';
import 'global_data.dart';
+import '../base/application_name.dart';
import '../base/defines.dart';
import '../base/i18n.dart';
static Installation? instance;
static ServerEnvironment serverEnvironment = ServerEnvironment.productive;
static int retries = 1;
+ static final homeDirectory = HomeDirectories(theApplicationName);
+
final neededPermissions = <Permission>[
Permission.camera,
Permission.location,
if (GlobalData.baseDirectory.isEmpty) {
GlobalData.baseDirectory = home.path;
}
- configurationFile = File(path.join(home.path, 'exhibition.json'));
+ configurationFile = File(
+ path.join(homeDirectory.configurations.path, '$theVariantName.yaml'));
if (!(forceInit ||
!configurationFile.existsSync() ||
!hasValidConfiguration())) {
final fileContent = configurationFile.readAsStringSync();
var rc = true;
try {
- final map = convert.jsonDecode(fileContent);
+ final map = loadYaml(fileContent);
final config = BaseConfiguration(map, logger);
final section = enumToString(serverEnvironment);
if (config.asString('host', section: section) == null ||
return rc;
}
- /// Prüft, ob eine gültige Datei mit den Bienenstockdaten existiert.
- /// Liefert true, wenn ja.
- bool hasValidHives() {
+ /// Checks whether there is a valid structures file.
+ ///
+ // / Returns true on success.
+ bool hasValidStructures() {
final fileContent = hivesFile.readAsStringSync();
final filename = hivesFile.path;
var rc = false;
final list = convert.jsonDecode(fileContent);
rc = list is Iterable;
if (!rc) {
- logger.error('$filename: "hives" ist kein Array');
+ logger.error('$filename: "structures" is not an array');
} else {
var ix = -1;
for (var item in list) {
ix++;
rc = item is Map;
if (!rc) {
- logger.error('$filename: hives[$ix] ist keine Map');
+ logger.error('$filename: structures[$ix] is not a map');
} else {
final map2 = item;
- rc = (map2.containsKey('hiveid') &&
- map2.containsKey('name') &&
- map2.containsKey('lat') &&
- map2.containsKey('long'));
+ rc = (map2.containsKey('structure_scope') &&
+ map2.containsKey('structure_name') &&
+ map2.containsKey('structure_value'));
if (!rc) {
- logger.error('$filename: Fehler in hives[$ix]');
+ logger.error('$filename: Error in structures[$ix]');
break;
}
}
}
}
} on FormatException catch (exc) {
- logger.error('$filename: kein JSon: $exc');
+ logger.error('$filename: not a Json file: $exc');
}
return rc;
}
- /// Liefert den Namen des Rechts [permission].
+ /// Returns the name of [permission].
static String nameOfPermission(Permission permission) {
var rc;
if (permission == Permission.storage) {
- rc = 'Speicher';
+ rc = i18n.tr('Storage');
} else if (permission == Permission.camera) {
- rc = 'Kamera';
+ rc = i18n.tr('Camera');
} else {
if (permission == Permission.location) {
- rc = 'Geo-Position';
+ rc = i18n.tr('Geo position');
} else {
rc = 'Permission-${permission.value}';
}
return rc;
}
- /// Liefert den Namen des [status].
+ /// Returns the human readable name of the [status].
static String nameOfStatus(PermissionStatus status) {
String rc;
switch (status) {
case PermissionStatus.granted:
- rc = 'erlaubt';
+ rc = i18n.tr('granted');
break;
case PermissionStatus.denied:
- rc = 'verweigert';
+ rc = i18n.tr('denied');
break;
case PermissionStatus.restricted:
- rc = 'eingeschränkt';
+ rc = i18n.tr('restricted');
break;
case PermissionStatus.limited:
- rc = 'begrenzt';
+ rc = i18n.tr('limited');
break;
case PermissionStatus.permanentlyDenied:
- rc = 'gesperrt';
+ rc = i18n.tr('locked');
break;
}
return rc;
}
- /// Initialisiert die einzige Instanz (Singleton).
+ /// Initializes the singleton instance.
static Future initialize(BaseLogger logger) async {
instance = Installation.internal(logger);
}
--- /dev/null
+import 'dart:convert' as convert;
+import 'dart:io';
+
+import 'package:exhibition/setting/global_data.dart';
+
+/// Defines an ([name], [value]) pair, grouped by a [scope] and ordered inside
+/// the scope by a [position].
+///
+/// Example: {'Status', 'Active', 'A', 1} and {'Status', 'Inactive', 'S', 2}
+/// represent a set of status information.
+class Structure {
+ final String scope;
+ final String name;
+ final String value;
+ final int position;
+ Structure(
+ {required this.scope,
+ required this.name,
+ required this.value,
+ this.position = 0});
+}
+
+/// Manages a list of [Structure] items.
+class Structures {
+ static Structures? _instance;
+ GlobalData? globalData;
+ final structures = <Structure>[];
+ final scopes = <String, List<Structure>>{};
+
+ /// Returns the singleton instance.
+ factory Structures() => _instance!;
+
+ /// Builds the singleton instance with items from a JSon file.
+ ///
+ /// The file named [filename] contains the items in a JSon format with
+ /// names given by the database table structures.
+ Structures.fromFile(String filename) {
+ this.globalData = GlobalData();
+ final file = File(filename);
+ if (!file.existsSync()) {
+ globalData!.logger.error('cannot read structures from $filename');
+ } else {
+ final content = file.readAsStringSync();
+ final data = convert.jsonDecode(content);
+ for (var record in data) {
+ structures.add(Structure(
+ scope: record['structure_scope'],
+ name: record['structure_name'],
+ value: record['structure_value'],
+ position: int.tryParse(record['structure_position']) ?? 0));
+ }
+ initialize();
+ }
+ }
+
+ /// Returns the [Structure] items belonging to a given [scope].
+ List<Structure>? byScope(String scope) {
+ final rc = scopes[scope];
+ return rc;
+ }
+
+ /// Initializes the internal structures.
+ ///
+ /// Should be called after the constructor.
+ void initialize() {
+ for (var structure in structures) {
+ if (scopes.containsKey(structure.scope)) {
+ scopes[structure.scope]!.add(structure);
+ scopes[structure.scope]!.sort((a, b) => a.position == b.position
+ ? a.name.compareTo(b.name)
+ : a.position - b.position);
+ } else {
+ scopes[structure.scope] = [structure];
+ }
+ }
+ }
+
+ /// Returns the value of a Structure given by [scope] and [name].
+ String valueOf(String scope, String name) {
+ final list = scopes[scope];
+ String rc = '';
+ if (list != null) {
+ rc = list
+ .firstWhere((element) => element.name == name,
+ orElse: () => list.first)
+ .value;
+ }
+ return rc;
+ }
+}
-import 'package:exhibition/persistence/persistence.dart';
-import 'package:exhibition/widget/attended_widget.dart';
import 'package:flutter/material.dart';
+import 'package:synchronized/synchronized.dart';
import '../../base/i18n.dart';
+import '../../persistence/persistence.dart';
import '../../setting/global_data.dart';
+import '../../widget/attended_widget.dart';
import '../meta/module_meta_data.dart';
final i18n = I18N();
/// database records in a [DataTable].
///
/// [columnList]: a ';' delimited list of column names, e.g. 'user_id;user_name'
- List<DataRow> getRows(String columnList, String what,
- Map<String, dynamic> parameters, Function() onDone, String routeEdit, BuildContext context) {
+ List<DataRow> getRows(
+ {required String columnList,
+ required String what,
+ required Map<String, dynamic> parameters,
+ required Function() onDone,
+ required String routeEdit,
+ required BuildContext context}) {
List<DataRow>? rc;
- if (!pageStates.openQuery) {
- pageStates.openQuery = true;
- globalData.restPersistence!
- .query(what: what, data: parameters)
- .then((value) {
- pageStates.dbData = value;
- pageStates.openQuery = false;
- onDone();
- });
- } else if (pageStates.dbData != null) {
- if (pageStates.dbData?.recordList != null) {
+ String name = 'rows';
+ if (!pageStates.dbDataState.hasEntry(name)) {
+ pageStates.dbDataState.addRequest(name).then((_) => globalData
+ .restPersistence!
+ .query(what: what, data: parameters)
+ .then((value) {
+ pageStates.dbDataState
+ .storeDbResult(name, value)
+ .then((_) => onDone());
+ }));
+ } else {
+ final dbData = pageStates.dbDataState.dataOf(name);
+ if (dbData != null && dbData.recordList != null) {
rc = <DataRow>[];
- pageStates.dbData?.recordList!.map((record) {
+ dbData.recordList!.forEach((record) {
final cells = <DataCell>[];
- for (var column in columnList.split(';')){
- final primaryKey = moduleMetaData.primaryOf();
+ for (var column in columnList.split(';')) {
+ final primaryKey = moduleMetaData.primaryOf()?.columnName;
cells.add(DataCell(Text(record[column].toString()),
- onTap: () => globalData.navigate(context, routeEdit + ';${record[primaryKey]}')));
+ onTap: () => globalData.navigate(
+ context, routeEdit + ';${record[primaryKey]}')));
}
final rc3 = DataRow(cells: cells);
- return rc3;
+ rc!.add(rc3);
});
}
}
}
}
+/// Manages multiple asynchronous database request from the backend.
+///
+/// This class can handle multiple request: Therefore each request needs a
+/// unique name to allow the access.
+class DbDataState {
+ final lock = Lock();
+ final dbDataMap = <String, DbData?>{};
+ int expectedCount = 0;
+ int currentCount = 0;
+
+ /// Adds a database request to the instance.
+ ///
+ /// [name] is a (over all requests) unique name to identify the request.
+ /// It is needed to fetch the db data.
+ Future addRequest(String name) async {
+ await lock.synchronized(() async {
+ dbDataMap[name] = null;
+ ++expectedCount;
+ });
+ }
+
+ /// Removes all current requests.
+ void clear() {
+ dbDataMap.clear();
+ expectedCount = currentCount = 0;
+ }
+
+ /// Returns the DB data given by the [name].
+ DbData? dataOf(String name) => dbDataMap[name];
+
+ /// Tests whether the map contains an entry with [name].
+ bool hasEntry(String name) => dbDataMap.containsKey(name);
+
+ /// Tests whether all requests are answered.
+ ///
+ /// Return true, if all answers of the requested DB data are stored in
+ /// [dbDataMap].
+ bool isWaiting() => currentCount < expectedCount;
+
+ /// Stores the DB data fetched from the backend.
+ ///
+ /// [name] is a (over all requests) unique name to identify the request.
+ ///
+ /// [data] is the result of a RestPersistence.query() call.
+ Future storeDbResult(String name, DbData data) async {
+ await lock.synchronized(() async {
+ dbDataMap[name] = data;
+ ++currentCount;
+ });
+ }
+}
+
enum DeliveryState { undef, waiting, delivered }
class PageStates {
double screenWidth = 0;
double screenHeight = 0;
AttendedPage? attendedPage;
- DbData? dbData;
- bool openQuery = false;
+ final dbDataState = DbDataState();
+ dynamic customData;
}
--- /dev/null
+import 'package:flutter/material.dart';
+import 'attended_page.dart';
+
+abstract class AttendedStateful extends StatefulWidget {
+ final PageStates pageStates = PageStates();
+}
/// [minWidth] is the minimum width of the above defined segment.
/// If the [screenwidth] has not place for 6 segments all widgets are placed
/// in a single row.
- static Widget flexibleGrid(List<AttendedWidget> widgets,
- {required double screenWidth,
+ static Widget flexibleGrid(List<Widget> widgets,
+ {required List<int> weights,
+ required double screenWidth,
double minWidth = 800,
double padding = 16.0}) {
Widget rc;
+ assert(widgets.length == weights.length);
if (minWidth > screenWidth) {
- final children = widgets.map((element) => element.widgetOf()).toList();
- rc = Column(children: children);
+ rc = Column(children: widgets);
} else {
int position = 0;
final List<Widget> childrenColumn = [];
List<Widget> childrenRow = [];
- for (var widget in widgets) {
- final flex = widget.propertyMetaData.weight;
+ for (var ix = 0; ix < widgets.length; ix++) {
+ final widget = widgets[ix];
+ final flex = weights[ix];
if (position + flex <= 12) {
var child2 = position == 0
- ? widget.widgetOf()
+ ? widget
: Row(
mainAxisAlignment: MainAxisAlignment.end,
- children: [
- SizedBox(width: padding),
- Expanded(child: widget.widgetOf())
- ],
+ children: [SizedBox(width: padding), Expanded(child: widget)],
);
childrenRow.add(Expanded(flex: flex, child: child2));
position += flex;
childrenColumn.add(Row(children: childrenRow));
childrenRow = [];
final child2 = position == 0
- ? widget.widgetOf()
+ ? widget
: Row(
- children: [
- SizedBox(width: padding),
- Expanded(child: widget.widgetOf())
- ],
+ children: [SizedBox(width: padding), Expanded(child: widget)],
);
childrenRow.add(Expanded(flex: flex, child: child2));
position = flex;
}
return rc;
}
+
+ /// Places the attended widgets in a flexible grid.
+ ///
+ /// Returns a column of rows.
+ ///
+ /// The place of the row is divided in 12 segments with the same width.
+ /// Each widget has a "weight" which means the count of segments to use.
+ ///
+ /// [widgets] is the list of attended widgets to position in the grid.
+ ///
+ /// [screenWidth] is the width of the output device in pixel.
+ ///
+ /// [minWidth] is the minimum width of the above defined segment.
+ /// If the [screenwidth] has not place for 6 segments all widgets are placed
+ /// in a single row.
+ static Widget flexibleGridAttended(List<AttendedWidget> widgets,
+ {required double screenWidth,
+ double minWidth = 800,
+ double padding = 16.0}) {
+ final weights =
+ widgets.map((element) => element.propertyMetaData.weight).toList();
+ final widgets2 = widgets.map((element) => element.widgetOf()).toList();
+ final rc =
+ flexibleGrid(widgets2, weights: weights, screenWidth: screenWidth);
+ return rc;
+ }
}
}
}
''';
- static final templateCollection = '''// DO NOT CHANGE. This file is created by the meta_tool!
+ static final templatePageManager = '''// DO NOT CHANGE. This file is created by the meta_tool!
import 'package:flutter/material.dart';
-import 'page_collection_custom.dart';
+import 'page_manager_custom.dart';
#IMPORTS#
/// Manages all meta data driven pages of the program.
-class PageCollection {
- static PageCollection? _instance;
- PageCollection.internal();
- factory PageCollection() {
- _instance ??= PageCollection.internal();
+class PageManager {
+ static PageManager? _instance;
+ PageManager.internal();
+ factory PageManager() {
+ _instance ??= PageManager.internal();
return _instance!;
}
final map = <String, StatefulWidget>{};
}
}
''';
- static final templateCollectionCustom = '''// This file is created by the meta_tool. But it can be customized.
+ static final templatePageManagerCustom = '''// This file is created by the meta_tool. But it can be customized.
// It will never overridden by the meta_tool.
import 'package:flutter/material.dart';
import 'info_page.dart';
return rc;
}
''';
- static final templateCase = ''' case '/users/edit':
+ static final templateCase = ''' case '/Users/edit':
rc = EditUserPage(ARG1);
break;
''';
return rc;
}
- /// Creates the file page_collection.dart and (if it does not exist) the file
- /// page_collection_custom.dart.
- void updateCollection(){
+ /// Creates the file page_manager.dart and (if it does not exist) the file
+ /// page_manager_custom.dart.
+ void updatePageManager(){
final modules = moduleNames();
final imports = StringBuffer();
final cases = StringBuffer();
cases.write(case1);
}
}
- final content = templateCollection.replaceFirst('#IMPORTS#', imports.toString())
+ final content = templatePageManager.replaceFirst('#IMPORTS#', imports.toString())
.replaceFirst('#CASES#', cases.toString());
- writeFile('../lib/page/page_collection.dart', content);
- final full = '../lib/page/page_collection_custom.dart';
+ writeFile('../lib/page/page_manager.dart', content);
+ final full = '../lib/page/page_manager_custom.dart';
if (File(full).existsSync()){
logger.log('$full already exists. We do not override');
} else {
- writeFile(full, templateCollectionCustom);
+ writeFile(full, templatePageManagerCustom);
}
}
/// Generates all modules defined in the meta data.
}
}
}
- updateCollection();
+ updatePageManager();
}
}
}
flutter:
sdk: flutter
path: ^1.8.0
+ yaml: ^3.1.0
dart_bones: ^1.2.2
url_launcher: ^6.0.9
flutter_markdown: ^0.6.1
flutter_bloc: ^7.1.0
equatable: ^2.0.3
permission_handler: ^8.1.6
+ path_provider: ^2.0.1
+ synchronized: ^3.0.0
+
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
parameters: []
sql: "SELECT
t0.*
- FROM Roles t0
+ FROM roles t0
;"
byId:
type: record
parameters: [ "id" ]
- sql: "SELECT * FROM Roles WHERE role_id=:id;"
+ sql: "SELECT * FROM roles WHERE role_id=:id;"
delete:
type: delete
parameters: [ "id" ]
- sql: "DELETE * FROM Roles WHERE role_id=:id;"
+ sql: "DELETE * FROM roles WHERE role_id=:id;"
update:
type: update
parameters: [":id",":name",":changedBy"]
- sql: "UPDATE Roles SET
+ sql: "UPDATE roles SET
role_id=:id,role_name=:name,role_changedby=:changedBy,role_changed=NOW()
WHERE role_id=:id;"
insert:
type: insert
parameters: [":id",":name",":createdBy"]
- sql: "INSERT INTO Roles(role_id,role_name,role_createdby,role_created)
+ sql: "INSERT INTO roles(role_id,role_name,role_createdby,role_created)
VALUES(:id,:name,:createdBy,NOW());"
--- /dev/null
+---
+# DO NOT CHANGE. This file is created by the meta_tool
+# SQL statements of the module "Structures":
+
+module: Structures
+list:
+ type: list
+ parameters: []
+ sql: "SELECT
+ t0.*
+ FROM structures t0
+
+ ;"
+byId:
+ type: record
+ parameters: [ "id" ]
+ sql: "SELECT * FROM structures WHERE structure_id=:id;"
+delete:
+ type: delete
+ parameters: [ "id" ]
+ sql: "DELETE * FROM structures WHERE structure_id=:id;"
+update:
+ type: update
+ parameters: [":id",":scope",":name",":value",":position",":changedBy"]
+ sql: "UPDATE structures SET
+ structure_id=:id,structure_scope=:scope,structure_name=:name,
+ structure_value=:value,structure_position=:position,
+ structure_changedby=:changedBy,structure_changed=NOW()
+ WHERE structure_id=:id;"
+insert:
+ type: insert
+ parameters: [":id",":scope",":name",":value",":position",":createdBy"]
+ sql: "INSERT INTO structures(structure_id,structure_scope,structure_name,
+ structure_value,structure_position,structure_createdby,structure_created)
+ VALUES(:id,:scope,:name,:value,:position,:createdBy,NOW());"
parameters: []
sql: "SELECT
t0.*,t1.role_name AS role
- FROM Users t0
+ FROM users t0
JOIN roles t1 ON t1.role_id=t0.user_role
;"
byId:
type: record
parameters: [ "id" ]
- sql: "SELECT * FROM Users WHERE user_id=:id;"
+ sql: "SELECT * FROM users WHERE user_id=:id;"
delete:
type: delete
parameters: [ "id" ]
- sql: "DELETE * FROM Users WHERE user_id=:id;"
+ sql: "DELETE * FROM users WHERE user_id=:id;"
update:
type: update
parameters: [":id",":name",":displayName",":email",":role",":changedBy"]
- sql: "UPDATE Users SET
+ sql: "UPDATE users SET
user_id=:id,user_name=:name,user_displayname=:displayName,user_email=:email,
user_role=:role,user_changedby=:changedBy,user_changed=NOW()
WHERE user_id=:id;"
insert:
type: insert
parameters: [":id",":name",":displayName",":email",":role",":createdBy"]
- sql: "INSERT INTO Users(user_id,user_name,user_displayname,user_email,
+ sql: "INSERT INTO users(user_id,user_name,user_displayname,user_email,
user_role,user_createdby,user_created)
VALUES(:id,:name,:displayName,:email,:role,:createdBy,NOW());"
final ix = sql.lastIndexOf(';');
sql2 = sql.substring(0, ix) +
' limit ${parameters["offset"]},${parameters["size"]};';
- final sqlCount =
- 'SELECT count(*) ' + sql.substring(sql.indexOf(' FROM'));
- final countParams = '?'.allMatches(sqlCount).length;
- final positionalParameters2 = countParams == positionalParameters.length
- ? positionalParameters
- : positionalParameters
- .skip(positionalParameters.length - countParams)
- .toList();
- prefix =
- '#${await db!.readOneInt(sqlCount, params: positionalParameters2)}';
+ final ix2 = sql.indexOf(' FROM ${module.toLowerCase()} t0 ');
+ if (ix2 > 0)
+ {
+ final sqlCount =
+ 'SELECT count(*) ' + sql.substring(ix2);
+ final countParams = '?'
+ .allMatches(sqlCount)
+ .length;
+ final positionalParameters2 = countParams ==
+ positionalParameters.length
+ ? positionalParameters
+ : positionalParameters
+ .skip(positionalParameters.length - countParams)
+ .toList();
+ prefix =
+ '#${await db!.readOneInt(sqlCount, params: positionalParameters2)}';
+ }
}
final records = await db!.readAll(sql2, params: positionalParameters);
rc = records == null
/// Reads multiple module data from a directory.
/// Only files ending with '.yaml' and containing '.sql.' are respected.
void read(String path) {
+ logger.log('reading SQL from $path', LEVEL_DETAIL);
for (var entry in Directory(path).listSync()) {
final full = entry.path;
final node = basename(full);