Skip to content

Commit

Permalink
Merge pull request #11 from a-givertzman/Schema-read/write
Browse files Browse the repository at this point in the history
Schema read/write
  • Loading branch information
a-givertzman authored Dec 25, 2023
2 parents a7ca577 + 8df118d commit 4eb3bf2
Show file tree
Hide file tree
Showing 17 changed files with 736 additions and 258 deletions.
13 changes: 11 additions & 2 deletions lib/ext_rw.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,17 @@ export 'src/api_client/reply/api_reply.dart';
export 'src/api_client/request/api_request.dart';

export 'src/sql/sql.dart';
export 'src/table_schema/field.dart';
export 'src/table_schema/field_value.dart';
export 'src/table_schema/field.dart';
export 'src/table_schema/relation.dart';
export 'src/table_schema/schema.dart';
export 'src/table_schema/relation_schema.dart';
export 'src/table_schema/schema_entry.dart';
export 'src/table_schema/schema.dart';
export 'src/table_schema/table_schema.dart';
export 'src/table_schema/table_schema_abstract.dart';
export 'src/table_schema/data_schema.dart';
export 'src/table_schema/schema_read.dart';
export 'src/table_schema/schema_write.dart';
export 'src/api_client/access/sql_read.dart';
export 'src/api_client/access/sql_write.dart';
export 'src/api_client/access/sql_builder.dart';
3 changes: 3 additions & 0 deletions lib/src/api_client/access/sql_builder.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import 'package:ext_rw/src/sql/sql.dart';

typedef SqlBuilder<T> = Sql Function(Sql sql, T entry);
88 changes: 88 additions & 0 deletions lib/src/api_client/access/sql_read.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import 'package:ext_rw/ext_rw.dart';
import 'package:hmi_core/hmi_core_failure.dart';
import 'package:hmi_core/hmi_core_log.dart';
import 'package:hmi_core/hmi_core_result_new.dart';

class SqlRead<T extends SchemaEntry, P> implements SchemaRead<T, P> {
late final Log _log;
final ApiAddress _address;
final String _authToken;
final String _database;
final bool _keepAlive;
final bool _debug;
final SqlBuilder<P> _sqlBuilder;
final Map<T, Function> _entryFromFactories;
Sql _sql = Sql(sql: '');
///
///
SqlRead({
required ApiAddress address,
required String authToken,
required String database,
bool keepAlive = false,
bool debug = false,
required SqlBuilder<P> sqlBuilder,
required Map<T, Function> entryFromFactories,
}) :
_address = address,
_authToken = authToken,
_database = database,
_keepAlive = keepAlive,
_debug = debug,
_sqlBuilder = sqlBuilder,
_entryFromFactories = entryFromFactories {
_log = Log("$runtimeType");
}
//
//
@override
Future<Result<List<T>, Failure>> fetch(P params) {
_sql = _sqlBuilder(_sql, params);
return _fetch(_sql);
}
///
/// Fetchs data with new [sql]
Future<Result<List<T>, Failure>> _fetch(Sql sql) {
final request = ApiRequest(
address: _address,
authToken: _authToken,
debug: _debug,
query: SqlQuery(
database: _database,
sql: sql.build(),
keepAlive: _keepAlive,
),
);
_log.debug("._fetch | request: $request");
return request.fetch().then((result) {
return switch (result) {
Ok(value :final reply) => () {
if (reply.hasError) {
return Err<List<T>, Failure>(Failure(message: reply.error.message, stackTrace: StackTrace.current));
} else {
final List<T> entries = [];
final rows = reply.data;
for (final row in rows) {
final entry = _makeEntry(row);
entries.add(entry);
}
return Ok<List<T>, Failure>(entries);
}
}(),
Err(:final error) => Err<List<T>, Failure>(error),
};
});
}
///
///
T _makeEntry(Map<String, dynamic> row) {
final constructor = _entryFromFactories[T];
if (constructor != null) {
return constructor(row);
}
throw Failure(
message: "$runtimeType._makeEntry | Can't find constructor for $T",
stackTrace: StackTrace.current,
);
}
}
187 changes: 187 additions & 0 deletions lib/src/api_client/access/sql_write.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
import 'package:ext_rw/ext_rw.dart';
import 'package:hmi_core/hmi_core_failure.dart';
import 'package:hmi_core/hmi_core_log.dart';
import 'package:hmi_core/hmi_core_result_new.dart';

class SqlWrite<T extends SchemaEntry> implements SchemaWrite<T> {
late final Log _log;
final ApiAddress _address;
final String _authToken;
final String _database;
final bool _keepAlive;
final bool _debug;
final SqlBuilder<T>? _insertSqlBuilder;
final SqlBuilder<T>? _updateSqlBuilder;
final SqlBuilder<T>? _deleteSqlBuilder;
final Map<T, Function> _entryFromFactories;
final Map<T, Function> _entryEmptyFactories;
///
///
SqlWrite({
required ApiAddress address,
required String authToken,
required String database,
bool keepAlive = false,
bool debug = false,
SqlBuilder<T>? insertSqlBuilder,
SqlBuilder<T>? updateSqlBuilder,
SqlBuilder<T>? deleteSqlBuilder,
required Map<T, Function> entryFromFactories,
required Map<T, Function> entryEmptyFactories,
}) :
_address = address,
_authToken = authToken,
_database = database,
_keepAlive = keepAlive,
_debug = debug,
_insertSqlBuilder = insertSqlBuilder,
_updateSqlBuilder = updateSqlBuilder,
_deleteSqlBuilder = deleteSqlBuilder,
_entryFromFactories = entryFromFactories,
_entryEmptyFactories = entryEmptyFactories {
_log = Log("$runtimeType");
}
//
//
@override
Future<Result<T, Failure>> insert(T? entry) {
T entry_;
if (entry != null) {
entry_ = entry;
} else {
entry_ = _makeEmptyEntry();
}
final builder = _insertSqlBuilder;
if (builder != null) {
final initialSql = Sql(sql: '');
final sql = builder(initialSql, entry_);
return _fetchWith(sql).then((result) {
return switch(result) {
Ok() => () {
return Ok<T, Failure>(entry_);
}(),
Err(:final error) => () {
return Err<T, Failure>(error);
}(),
};
});
}
return Future.value(
Err(Failure(
message: "$runtimeType.insert | insertSqlBuilder is not initialized",
stackTrace: StackTrace.current,
)),
);
}
//
//
@override
Future<Result<void, Failure>> update(T entry) {
final builder = _updateSqlBuilder;
if (builder != null) {
final initialSql = Sql(sql: '');
final sql = builder(initialSql, entry);
return _fetchWith(sql).then((result) {
return switch(result) {
Ok() => () {
return const Ok<void, Failure>(null);
}(),
Err(:final error) => () {
return Err<void, Failure>(error);
}(),
};
});
}
return Future.value(
Err(Failure(
message: "$runtimeType.update | updateSqlBuilder is not initialized",
stackTrace: StackTrace.current,
)),
);
}
//
//
@override
Future<Result<void, Failure>> delete(T entry) {
final builder = _deleteSqlBuilder;
if (builder != null) {
final initialSql = Sql(sql: '');
final sql = builder(initialSql, entry);
return _fetchWith(sql).then((result) {
return switch(result) {
Ok() => () {
return const Ok<void, Failure>(null);
}(),
Err(:final error) => () {
return Err<void, Failure>(error);
}(),
};
});
}
return Future.value(
Err(Failure(
message: "$runtimeType.delete | deleteSqlBuilder is not initialized",
stackTrace: StackTrace.current,
)),
);
}
///
/// Fetchs data with new [sql]
Future<Result<List<T>, Failure>> _fetchWith(Sql sql) {
final request = ApiRequest(
address: _address,
authToken: _authToken,
debug: _debug,
query: SqlQuery(
database: _database,
sql: sql.build(),
keepAlive: _keepAlive,
),
);
_log.debug("._fetchWith | request: $request");
return request.fetch().then((result) {
return switch (result) {
Ok(:final value) => () {
final reply = value;
if (reply.hasError) {
return Err<List<T>, Failure>(Failure(message: reply.error.message, stackTrace: StackTrace.current));
} else {
final List<T> entries = [];
final rows = reply.data;
for (final row in rows) {
final entry = _makeEntry(row);
entries.add(entry);
}
return Ok<List<T>, Failure>(entries);
}
}(),
Err(:final error) => Err<List<T>, Failure>(error),
};
});
}
///
///
T _makeEmptyEntry() {
final constructor = _entryEmptyFactories[T];
if (constructor != null) {
return constructor();
} else {
throw Failure(
message: "$runtimeType._makeEntry | Can't find constructor for $T",
stackTrace: StackTrace.current,
);
}
}
///
///
T _makeEntry(Map<String, dynamic> row) {
final constructor = _entryFromFactories[T];
if (constructor != null) {
return constructor(row);
}
throw Failure(
message: "$runtimeType._makeEntry | Can't find constructor for $T",
stackTrace: StackTrace.current,
);
}
}
4 changes: 1 addition & 3 deletions lib/src/api_client/query/api_query_type.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
abstract class ApiQueryType {
bool valid();
///
String buildJson();
///
String get authToken;
String buildJson({String authToken = '', bool debug = false});
///
String get id;
}
17 changes: 4 additions & 13 deletions lib/src/api_client/query/executable_query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,20 @@ import 'package:ext_rw/src/api_client/query/api_query_type.dart';
import 'package:uuid/uuid.dart';

class ExecutableQuery implements ApiQueryType {
final String _authToken;
late String _id;
final String _script;
final Map<String, dynamic> _params;
final bool _keepAlive;
final bool _debug;
///
/// Prapares query for some executable
ExecutableQuery({
required String authToken,
required String script,
required Map<String, dynamic> params,
bool keepAlive = false,
bool debug = false,
}) :
_authToken = authToken,
_script = script,
_params = params,
_keepAlive = keepAlive,
_debug = debug;
_keepAlive = keepAlive;
///
@override
bool valid() {
Expand All @@ -32,13 +26,13 @@ class ExecutableQuery implements ApiQueryType {
}
///
@override
String buildJson() {
String buildJson({String authToken = '', bool debug = false}) {
_id = const Uuid().v1();
final jsonString = json.encode({
'authToken': _authToken,
'authToken': authToken,
'id': _id,
'keepAlive': _keepAlive,
'debug': _debug,
'debug': debug,
'executable': {
'script': _script,
'params': _params,
Expand All @@ -48,9 +42,6 @@ class ExecutableQuery implements ApiQueryType {
}
///
@override
String get authToken => _authToken;
///
@override
String get id => _id;
///
String get script => _script;
Expand Down
Loading

0 comments on commit 4eb3bf2

Please sign in to comment.