|
@@ -0,0 +1,209 @@
|
|
|
+import { getChangePart } from "../../shared";
|
|
|
+import {
|
|
|
+ Entity,
|
|
|
+ EntityShape,
|
|
|
+ EntityTransmit,
|
|
|
+ EntityTree,
|
|
|
+ EntityType,
|
|
|
+} from "./entity";
|
|
|
+
|
|
|
+const getEntityTransmitProps = (parent: Entity): EntityTransmit => {
|
|
|
+ return {
|
|
|
+ root: parent.root,
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+export const entityFactory = <
|
|
|
+ P extends Entity,
|
|
|
+ T,
|
|
|
+ S extends EntityShape,
|
|
|
+ C extends EntityType<T, S, EntityTree<P>>
|
|
|
+>(
|
|
|
+ attrib: T,
|
|
|
+ key: string,
|
|
|
+ Type: C,
|
|
|
+ parent?: P,
|
|
|
+ extra?: (self: InstanceType<C>) => void,
|
|
|
+ created?: (self: InstanceType<C>) => void
|
|
|
+): InstanceType<C> => {
|
|
|
+ const entity = new Type({
|
|
|
+ attrib,
|
|
|
+ key,
|
|
|
+ }) as InstanceType<C>;
|
|
|
+
|
|
|
+ extra && extra(entity);
|
|
|
+
|
|
|
+ if (parent) {
|
|
|
+ const transmit = getEntityTransmitProps(parent);
|
|
|
+ for (const key in transmit) {
|
|
|
+ entity[key] = parent[key];
|
|
|
+ }
|
|
|
+ entity.setParent(parent);
|
|
|
+ }
|
|
|
+
|
|
|
+ entity.init();
|
|
|
+ entity.mount();
|
|
|
+ if (parent?.isMounted) {
|
|
|
+ entity.mounted();
|
|
|
+ }
|
|
|
+
|
|
|
+ created && created(entity);
|
|
|
+ return entity;
|
|
|
+};
|
|
|
+
|
|
|
+export type IncEntitys<
|
|
|
+ P extends Entity,
|
|
|
+ T,
|
|
|
+ C extends EntityType<T, S, EntityTree<P>>,
|
|
|
+ S extends EntityShape
|
|
|
+> = {
|
|
|
+ adds: InstanceType<C>[];
|
|
|
+ dels: InstanceType<C>[];
|
|
|
+ upds: InstanceType<C>[];
|
|
|
+};
|
|
|
+
|
|
|
+export type IncEntitysFactory<
|
|
|
+ P extends Entity,
|
|
|
+ T,
|
|
|
+ C extends EntityType<T, S, EntityTree<P>>,
|
|
|
+ S extends EntityShape = EntityShape
|
|
|
+> = (attribs: T[]) => IncEntitys<P, T, C, S>;
|
|
|
+
|
|
|
+// 增量工厂
|
|
|
+export const incEntitysFactoryGenerate = <
|
|
|
+ P extends Entity,
|
|
|
+ T,
|
|
|
+ S extends EntityShape,
|
|
|
+ C extends EntityType<T, S, EntityTree<P>>
|
|
|
+>(
|
|
|
+ Type: C,
|
|
|
+ parent?: P,
|
|
|
+ extra?: (self: InstanceType<C>) => void,
|
|
|
+ created?: (self: InstanceType<C>) => void
|
|
|
+): IncEntitysFactory<P, T, C, S> => {
|
|
|
+ let oldKeys: string[] = [];
|
|
|
+ let useIndex = false;
|
|
|
+ let inited = false;
|
|
|
+
|
|
|
+ const cache: { [key in string]: InstanceType<C> } = {};
|
|
|
+
|
|
|
+ const findAttrib = (attribs: any[], key: string) => {
|
|
|
+ if (useIndex) {
|
|
|
+ return attribs[key];
|
|
|
+ } else {
|
|
|
+ return attribs.find((attrib) => attrib.id === key);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const destory = (key: string) => {
|
|
|
+ const delEntity = cache[key];
|
|
|
+ delEntity.destory();
|
|
|
+ delete cache[key];
|
|
|
+ return delEntity;
|
|
|
+ };
|
|
|
+
|
|
|
+ const add = (attrib: T, key: string) => {
|
|
|
+ const addEntity = entityFactory(attrib, key, Type, parent, extra, created);
|
|
|
+ return (cache[key] = addEntity);
|
|
|
+ };
|
|
|
+
|
|
|
+ return (attribsRaw: T[]) => {
|
|
|
+ const attribs = attribsRaw as any[];
|
|
|
+ if (!inited && attribs.length && typeof attribs[0] === "object") {
|
|
|
+ useIndex = !!attribs[0].id;
|
|
|
+ inited = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (
|
|
|
+ !useIndex &&
|
|
|
+ attribs.length &&
|
|
|
+ attribs.some(
|
|
|
+ (item) => typeof item !== "object" || typeof item.id !== "string"
|
|
|
+ )
|
|
|
+ ) {
|
|
|
+ throw "attribs 不合法,缺少id";
|
|
|
+ }
|
|
|
+ const newKeys = attribs.map((attrib, ndx) =>
|
|
|
+ useIndex ? ndx.toString() : attrib.id
|
|
|
+ );
|
|
|
+
|
|
|
+ if (new Set(newKeys).size !== newKeys.length) {
|
|
|
+ throw "attribs 的id不合法 不可重复";
|
|
|
+ }
|
|
|
+
|
|
|
+ const { addPort, delPort, holdPort } = getChangePart(newKeys, oldKeys);
|
|
|
+
|
|
|
+ const dels = delPort.map(destory);
|
|
|
+ const adds = addPort.map((key) => add(findAttrib(attribs, key), key));
|
|
|
+ const upds = holdPort.map((key) => {
|
|
|
+ const newAttrib = findAttrib(attribs, key);
|
|
|
+ cache[key].setAttrib(newAttrib);
|
|
|
+ return cache[key];
|
|
|
+ });
|
|
|
+ oldKeys = newKeys;
|
|
|
+
|
|
|
+ return {
|
|
|
+ adds,
|
|
|
+ dels,
|
|
|
+ upds,
|
|
|
+ };
|
|
|
+ };
|
|
|
+};
|
|
|
+
|
|
|
+export type SingleEntity<
|
|
|
+ P extends Entity,
|
|
|
+ T,
|
|
|
+ C extends EntityType<T, S, EntityTree<P>>,
|
|
|
+ S extends EntityShape
|
|
|
+> = {
|
|
|
+ add?: InstanceType<C>;
|
|
|
+ del?: InstanceType<C>;
|
|
|
+ upd?: InstanceType<C>;
|
|
|
+};
|
|
|
+
|
|
|
+export type SingleEntityFactory<
|
|
|
+ P extends Entity,
|
|
|
+ T,
|
|
|
+ C extends EntityType<T, S, EntityTree<P>>,
|
|
|
+ S extends EntityShape = EntityShape
|
|
|
+> = (data: { attrib: T; key?: string }) => SingleEntity<P, T, C, S>;
|
|
|
+
|
|
|
+export const singleEntityFactory = <
|
|
|
+ P extends Entity,
|
|
|
+ T,
|
|
|
+ S extends EntityShape,
|
|
|
+ C extends EntityType<T, S, EntityTree<P>>
|
|
|
+>(
|
|
|
+ Type: C,
|
|
|
+ parent?: P,
|
|
|
+ extra?: (self: InstanceType<C>) => void,
|
|
|
+ created?: (self: InstanceType<C>) => void
|
|
|
+): SingleEntityFactory<P, T, C, S> => {
|
|
|
+ let entity: InstanceType<C> | null = null;
|
|
|
+
|
|
|
+ return ({ attrib, key }) => {
|
|
|
+ const result: SingleEntity<P, T, C, S> = {};
|
|
|
+
|
|
|
+ if (entity) {
|
|
|
+ if (!key) {
|
|
|
+ entity.destory();
|
|
|
+ result.del = entity;
|
|
|
+ entity = null;
|
|
|
+ } else if (key !== entity.getKey()) {
|
|
|
+ console.error("entity 主键更改 销毁重建");
|
|
|
+ entity.destory();
|
|
|
+ result.del = entity;
|
|
|
+ result.add = entityFactory(attrib, key, Type, parent, extra, created);
|
|
|
+ entity = result.add;
|
|
|
+ } else {
|
|
|
+ entity.setAttrib(attrib);
|
|
|
+ result.upd = entity;
|
|
|
+ }
|
|
|
+ } else if (key && attrib) {
|
|
|
+ result.add = entityFactory(attrib, key, Type, parent, extra, created);
|
|
|
+ entity = result.add;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ };
|
|
|
+};
|