[server] add module

This commit is contained in:
2020-03-25 16:24:53 +03:00
parent 821ddbb2a7
commit 8e3b9e2830
99 changed files with 70 additions and 4 deletions

View File

@@ -0,0 +1,191 @@
package ru.m.data;
import flash.net.SharedObject;
import haxe.DynamicAccess;
import haxe.Serializer;
import haxe.Unserializer;
import promhx.Promise;
import ru.m.data.IDataSource;
class Converter<D, S> {
private var serializer:D -> S;
private var desirealizer:S -> D;
public function new(serializer:D -> S, desirealizer:S -> D) {
this.serializer = serializer;
this.desirealizer = desirealizer;
}
public inline function serialize(item:D):S {
return serializer(item);
}
public inline function deserialize(data:S):D {
return desirealizer(data);
}
}
class DefaultConverter<D> extends Converter<D, String> {
public function new () {
super(
item -> Serializer.run(item),
data -> new Unserializer(data).unserialize()
);
}
}
class EmptyConverter<T> extends Converter<T, T> {
public function new() {
super(item -> item, data -> data);
}
}
class MetaBuilder<D> extends DefaultConverter<DataMeta> {
private var builder:D -> DataMeta;
public function new(builder:D -> DataMeta) {
super();
this.builder = builder;
}
public function build(item:D):DataMeta {
return builder(item);
}
}
typedef DataMeta = Filter;
typedef IdValue<I> = {id:I, meta:DataMeta};
class DataStorage<I, D> implements IDataManager<I, D> implements IDataIndex<I> {
inline private static var DATA_KEY = "item";
private var name:String;
private var metaBuilder:MetaBuilder<D>;
private var idConverter:Converter<I, String>;
private var dataConverter:Converter<D, Dynamic>;
private var indexData:SharedObject;
public function new(
name:String,
metaBuilder:MetaBuilder<D>,
idConverter:Converter<I, String> = null,
dataConverter:Converter<D, Dynamic> = null
) {
this.name = name;
this.metaBuilder = metaBuilder;
this.idConverter = idConverter != null ? idConverter : new DefaultConverter();
this.dataConverter = dataConverter != null ? dataConverter : new DefaultConverter();
this.indexData = SharedObject.getLocal('${name}/index');
}
private function serializeId(id:I):String {
return idConverter.serialize(id);
}
private function desirealizeId(data:String):I {
return idConverter.deserialize(data);
}
private function buildMeta(item:D):DataMeta {
return metaBuilder.build(item);
}
private function checkFilter(filter:Null<Filter>, meta:DataMeta):Bool {
if (filter != null) {
for (k => v in filter) {
if (meta.exists(k) && meta.get(k) != v) {
return false;
}
}
}
return true;
}
private function sort(order:Order, values:Array<IdValue<I>>):Void {
if (order != null) {
values.sort((a:IdValue<I>, b:IdValue<I>) -> {
for (item in order) {
var av = a.meta.get(item.key);
var bv = b.meta.get(item.key);
if (av > bv) {
return item.reverse ? - 1 : 1;
} else if (av < bv) {
return item.reverse ? 1 : -1;
}
}
return 0;
});
}
}
private function serialize(item:D):Dynamic {
return dataConverter.serialize(item);
}
private function unserialize(data:Dynamic):D {
return dataConverter.deserialize(data);
}
public function getIndexPage(page:Page):Promise<DataPage<I>> {
var data:DynamicAccess<String> = indexData.data;
var values:Array<IdValue<I>> = [];
for (k => v in data) {
var meta = metaBuilder.deserialize(v);
if (checkFilter(page.filter, meta)) {
values.push({id: desirealizeId(k), meta: meta});
}
}
sort(page.order, values);
var result:Array<I> = values.slice(page.index * page.count, page.index * page.count + page.count).map(value -> value.id);
return Promise.promise({
page: page,
total: values.length,
data: result,
});
}
public function getPage(page:Page):Promise<DataPage<D>> {
return getIndexPage(page).pipe((indexPage:DataPage<I>) -> {
return Promise.whenAll([for (id in indexPage.data) get(id)]).then((data:Array<D>) -> {
return {
page: indexPage.page,
total: indexPage.total,
data: data,
}
});
});
}
public function get(id:I):Promise<D> {
var stringId = serializeId(id);
var itemData = SharedObject.getLocal('${name}/${stringId}');
var result:D = null;
if (Reflect.hasField(itemData.data, DATA_KEY)) {
result = unserialize(Reflect.field(itemData.data, DATA_KEY));
}
return Promise.promise(result);
}
public function save(item:D):Promise<D> {
var meta = metaBuilder.build(item);
var stringId = meta.get("id");
var itemData = SharedObject.getLocal('${name}/${stringId}');
itemData.setProperty(DATA_KEY, serialize(item));
itemData.flush();
indexData.setProperty(stringId, metaBuilder.serialize(meta));
indexData.flush();
return Promise.promise(item);
}
public function delete(id:I):Promise<Bool> {
var stringId = serializeId(id);
var itemData = SharedObject.getLocal('${name}/${stringId}');
itemData.clear();
var data:DynamicAccess<String> = indexData.data;
data.remove(stringId);
indexData.flush();
return Promise.promise(true);
}
}