silentbalanceyh/vertx-zero

View on GitHub
vertx-pin/zero-vie/src/main/jib/io/mature/extension/uca/commerce/Arms.java

Summary

Maintainability
A
2 hrs
Test Coverage
package io.mature.extension.uca.commerce;

import io.horizon.eon.em.typed.ChangeFlag;
import io.horizon.uca.cache.Cc;
import io.mature.extension.refine.Ox;
import io.mature.extension.scaffold.plugin.AspectSwitcher;
import io.mature.extension.uca.log.TrackIo;
import io.modello.specification.action.HDao;
import io.vertx.core.Future;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.mod.atom.modeling.builtin.DataAtom;
import io.vertx.mod.atom.refine.Ao;
import io.vertx.up.atom.element.JSix;
import io.vertx.up.atom.exchange.DFabric;
import io.vertx.up.commune.record.Apt;
import io.vertx.up.fn.Fn;
import io.vertx.up.unity.Ux;
import io.vertx.up.util.Ut;

import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;

import static io.mature.extension.refine.Ox.LOG;

/**
 * @author <a href="http://www.origin-x.cn">Lang</a>
 */
@SuppressWarnings("all")
public class Arms {
    private static final Cc<String, Arms> CC_ARMS = Cc.open();
    private final transient DataAtom atom;
    private final transient HDao dao;
    private final transient TrackIo io;
    private final transient Set<ChangeFlag> types = new HashSet<ChangeFlag>() {
        {
            this.add(ChangeFlag.DELETE);
            this.add(ChangeFlag.UPDATE);
            this.add(ChangeFlag.ADD);
        }
    };
    private transient DFabric fabric;

    private Function<JsonArray, JsonArray> fnDefault;
    private Supplier<Future<JsonArray>> fnFetcher;

    public Arms(final HDao dao, final DataAtom atom) {
        this.dao = dao;
        this.atom = atom;
        this.io = TrackIo.create(atom, dao);
    }

    public static <T extends Arms> T create(final HDao dao, final DataAtom atom) {
        return (T) CC_ARMS.pick(() -> new Arms(dao, atom), atom.identifier());
    }

    protected DataAtom atom() {
        return this.atom;
    }

    protected HDao dao() {
        return this.dao;
    }

    public <T extends Arms> T bind(final DFabric fabric) {
        this.fabric = fabric;
        return (T) this;
    }

    public <T extends Arms> T bind(final ChangeFlag... types) {
        this.types.clear();
        this.types.addAll(Arrays.asList(types));
        return (T) this;
    }

    public <T extends Arms> T bindFn(final Function<JsonArray, JsonArray> fnDefault) {
        this.fnDefault = fnDefault;
        return (T) this;
    }

    public <T extends Arms> T bindFn(final Supplier<Future<JsonArray>> fnFetcher) {
        this.fnFetcher = fnFetcher;
        return (T) this;
    }

    /*
     * 两种方式读取数据
     * 1. 带条件
     * 2. 不带条件
     */
    public Future<JsonArray> saveAsync(final JsonArray recordData, final JsonObject options) {
        return this.saveAsync(null, recordData, options);
    }

    public Future<JsonArray> saveAsync(final JsonObject criteria, final JsonArray recordData, final JsonObject options) {
        LOG.Uca.info(this.getClass(), "原始输入数据:{0},原始配置:{1}", recordData.encode(), options.encode());
        /*
         * 构造 AoHex
         * {
         *     "components": {
         *     }
         * }
         */
        final JSix hex = JSix.create(options);
        /*
         * 第一步:清洗数据
         * 1)检查数据合法性
         * 2)写日志、做过滤
         * Record[] -> JsonArray
         */
        return this.fetchAsync(criteria)

            /* 合并旧数据和新数据 */
            .compose(original -> Ux.future(Apt.create(original, recordData)))

            /* 按标识规则对比结果 */
            .compose(apt -> Ux.future(Ao.diffPure(apt, this.atom, Ox.ignorePure(this.atom)).compared()))

            /* 变更表 */
            .compose(map -> {
                /*
                 * 处理不同类型的数据
                 */
                LOG._I.report(this.getClass(), map);
                final List<Future<JsonArray>> futures = new ArrayList<>();
                /*
                 * 只执行操作类型
                 */
                if (this.types.contains(ChangeFlag.ADD)) {
                    futures.add(this.addRecord(map.get(ChangeFlag.ADD), hex.batch(ChangeFlag.ADD)));
                }
                if (this.types.contains(ChangeFlag.UPDATE)) {
                    futures.add(this.updateRecord(map.get(ChangeFlag.UPDATE), hex.batch(ChangeFlag.UPDATE)));
                }
                if (this.types.contains(ChangeFlag.DELETE)) {
                    futures.add(this.deleteRecord(map.get(ChangeFlag.DELETE), hex.batch(ChangeFlag.DELETE)));
                }
                return Fn.compressA(futures);
            });
    }

    protected Class<?> completerCls() {
        return CompleterDefault.class;
    }

    // ------------------- 下边全是私有函数 --------------------

    private Future<JsonArray> fetchAsync(final JsonObject criteria) {
        if (Objects.isNull(this.fnFetcher)) {
            if (Ut.isNil(criteria)) {
                return this.dao.fetchAllAsync().compose(Ux::futureA);
            } else {
                return this.dao.fetchAsync(Ut.valueJObject(criteria)).compose(Ux::futureA);
            }
        } else {
            return this.fnFetcher.get();
        }
    }

    private Future<JsonArray> deleteRecord(final JsonArray data, final JsonObject options) {
        return this.processAsync(data, options, (atomy, aspect) -> {
            /* Completer构造 */
            final Completer completer = Completer.create(this.completerCls(), this.dao, this.atom).bind(options);
            final JsonArray original = atomy.dataO();
            return aspect.run(original, processed -> completer.remove(processed)
                /* 变更历史 */
                .compose(nil -> this.io.procAsync(null, original, options, original.size()))
            );
        });
    }

    private Future<JsonArray> updateRecord(final JsonArray data, final JsonObject options) {
        return this.processAsync(data, options, (atomy, aspect) -> {
            /* Completer构造 */
            final Completer completer = Completer.create(this.completerCls(), this.dao, this.atom).bind(options);
            final JsonArray input = atomy.comparedU();
            /* Input / Assert */
            return aspect.run(input, processed -> completer.update(processed)
                /* 变更历史 */
                .compose(updated -> this.io.procAsync(updated, atomy.dataO(), options, updated.size()))
            );
        });
    }

    private Future<JsonArray> addRecord(final JsonArray data, final JsonObject options) {
        return this.processAsync(data, options, (atomy, aspect) -> {
            /* Completer构造 */
            final Completer completer = Completer.create(this.completerCls(), this.dao, this.atom).bind(options);
            JsonArray input = atomy.comparedA();
            /* fnDefault默认值专用函数 */
            if (Objects.nonNull(this.fnDefault)) {
                input = this.fnDefault.apply(input);
            }
            return aspect.run(input, processed -> completer.create(processed)
                /* 变更历史 */
                .compose(created -> this.io.procAsync(created, null, options, created.size()))
            );
        });
    }

    private Future<JsonArray> processAsync(final JsonArray input, final JsonObject options,
                                           final BiFunction<Apt, AspectSwitcher, Future<JsonArray>> consumer) {
        if (input.isEmpty()) {
            return Ux.future(new JsonArray());
        } else {
            final Apt apt = Ux.ruleApt(input, false);
            /* Aspect插件 */
            final AspectSwitcher aspect = new AspectSwitcher(this.atom, options, this.fabric);
            return consumer.apply(apt, aspect);
        }
    }
}