[server] add module
This commit is contained in:
191
src/app/haxe/ru/m/data/DataStorage.hx
Normal file
191
src/app/haxe/ru/m/data/DataStorage.hx
Normal 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user