Add table creation

This commit is contained in:
Andrew 2023-04-11 02:42:20 +07:00
parent 09c9549004
commit 4a5039cb19
19 changed files with 1132 additions and 141 deletions

View file

@ -3,6 +3,8 @@ import 'dart:convert';
import 'package:tuuli_app/api/model/access_token_model.dart';
import 'package:http/browser_client.dart';
import 'package:http/http.dart';
import 'package:tuuli_app/api/model/table_field_model.dart';
import 'package:tuuli_app/api/model/tables_list_model.dart';
class ErrorOrData<T> {
final T? data;
@ -58,6 +60,8 @@ class ApiClient {
} else {
data = AccessTokenModel(accessToken: body['access_token']);
}
} else if (response.statusCode == 422) {
error = Exception('Invalid request parameters');
} else {
error = Exception('HTTP ${response.statusCode}');
}
@ -65,6 +69,54 @@ class ApiClient {
return ErrorOrData(data, error);
}
FutureErrorOrData<TablesListModel> tablesList() async {
TablesListModel? data;
Exception? error;
final response = await get('/api/listTables');
if (response.statusCode == 200) {
final body = json.decode(await response.stream.bytesToString());
if (body['error'] != null) {
error = Exception(body['error']);
} else if (body['tables'] == null) {
error = Exception('Server error');
} else {
data = TablesListModel.fromJson(body);
}
} else if (response.statusCode == 422) {
error = Exception('Invalid request parameters');
} else {
error = Exception('HTTP ${response.statusCode}');
}
return ErrorOrData(data, error);
}
FutureErrorOrData<void> createTable(
String tableName, List<TableField> columns) async {
Exception? error;
final response =
await post('/api/createTable/${Uri.encodeComponent(tableName)}', body: {
'columns':
columns.map((e) => e.toColumnDefinition()).toList(growable: false),
}, headers: {
'Content-Type': 'application/json',
});
if (response.statusCode == 200) {
final body = json.decode(await response.stream.bytesToString());
if (body['error'] != null) {
error = Exception(body['error']);
}
} else if (response.statusCode == 422) {
error = Exception('Invalid request parameters');
} else {
error = Exception('HTTP ${response.statusCode}');
}
return ErrorOrData(null, error);
}
Future<StreamedResponse> get(
String path, {
Map<String, String>? headers,

View file

@ -0,0 +1,127 @@
import 'package:uuid/uuid.dart';
typedef SerialTableField = TableField<int>;
typedef UUIDTableField = TableField<UuidValue>;
typedef StringTableField = TableField<String>;
typedef BigIntTableField = TableField<BigInt>;
typedef BoolTableField = TableField<bool>;
typedef DateTableField = TableField<DateTime>;
typedef DateTimeTableField = TableField<DateTime>;
typedef FloatTableField = TableField<double>;
typedef IntTableField = TableField<int>;
final possibleFieldTypes = {
"serial": SerialTableField,
"uuid": UUIDTableField,
"str": StringTableField,
"bigint": BigIntTableField,
"bool": BoolTableField,
"date": DateTableField,
"datetime": DateTimeTableField,
"float": FloatTableField,
"int": IntTableField,
};
class TableField<T> {
final String fieldName;
final String fieldType;
final bool isUnique;
final bool isPrimary;
final Type type = T;
TableField({
required this.fieldName,
required this.fieldType,
required this.isUnique,
required this.isPrimary,
});
bool canBePrimary() {
return fieldType == "serial" || fieldType == "uuid";
}
@override
String toString() {
return "TableField<$T>(fieldName: $fieldName, fieldType: $fieldType, isUnique: $isUnique, isPrimary: $isPrimary)";
}
String toColumnDefinition() {
return "$fieldName:$fieldType${isPrimary ? ":primary" : ""}${isUnique ? ":unique" : ""}";
}
static TableField parseTableField(String definition) {
final parts = definition.split(":");
final fieldName = parts[0];
final fieldType = parts[1];
final isUnique = parts.contains("unique");
final isPrimary = parts.contains("primary");
switch (fieldType) {
case "serial":
return SerialTableField(
fieldName: fieldName,
fieldType: fieldType,
isUnique: isUnique,
isPrimary: isPrimary,
);
case "uuid":
return UUIDTableField(
fieldName: fieldName,
fieldType: fieldType,
isUnique: isUnique,
isPrimary: isPrimary,
);
case "str":
return StringTableField(
fieldName: fieldName,
fieldType: fieldType,
isUnique: isUnique,
isPrimary: isPrimary,
);
case "bigint":
return BigIntTableField(
fieldName: fieldName,
fieldType: fieldType,
isUnique: isUnique,
isPrimary: isPrimary,
);
case "bool":
return BoolTableField(
fieldName: fieldName,
fieldType: fieldType,
isUnique: isUnique,
isPrimary: isPrimary,
);
case "date":
return DateTableField(
fieldName: fieldName,
fieldType: fieldType,
isUnique: isUnique,
isPrimary: isPrimary,
);
case "datetime":
return DateTimeTableField(
fieldName: fieldName,
fieldType: fieldType,
isUnique: isUnique,
isPrimary: isPrimary,
);
case "float":
return FloatTableField(
fieldName: fieldName,
fieldType: fieldType,
isUnique: isUnique,
isPrimary: isPrimary,
);
case "int":
return IntTableField(
fieldName: fieldName,
fieldType: fieldType,
isUnique: isUnique,
isPrimary: isPrimary,
);
default:
throw Exception("Unknown field type: $fieldType");
}
}
}

View file

@ -0,0 +1,42 @@
import 'package:tuuli_app/api/model/table_field_model.dart';
class TablesListModel {
final List<TableModel> tables;
TablesListModel(this.tables);
factory TablesListModel.fromJson(Map<String, dynamic> json) =>
TablesListModel(
List<TableModel>.from(
json["tables"].map((x) => TableModel.fromJson(x)),
),
);
}
class TableModel {
final String tableId;
final String tableName;
final String columnsDefinition;
final List<TableField> columns;
final bool system;
final bool hidden;
TableModel({
required this.tableId,
required this.tableName,
required this.columnsDefinition,
required this.system,
required this.hidden,
}) : columns = columnsDefinition
.split(",")
.map(TableField.parseTableField)
.toList(growable: false);
factory TableModel.fromJson(Map<String, dynamic> json) => TableModel(
tableId: json["table_id"],
tableName: json["table_name"],
columnsDefinition: json["columns"],
system: json["system"],
hidden: json["hidden"],
);
}