Youwei low code: Transform data conversion

Introduction

The low code technology column of Youwei is a brand-new and technology-based column written by the members of Youwei Technology Committee. Based on the research and development and operation and maintenance achievements of low code technology of Youwei in the past 7 years, it mainly introduces the technical principles and architecture logic related to low code, with the purpose of providing a platform for technical exchange and learning for the vast number of operation and maintenance personnel.

Serial No. 17

Advanced Guide: Transform data transformation

In Brick Next, dataSource+fields is an unwritten agreement practiced by our developers. However, since there is no prior mandatory agreement and in-depth investigation, its implementation looks similar in different components, but is actually different. This is very confusing to the downstream users of related components. Therefore, it is urgent to unify these data conversion logic.

However, since Storyboard is declarative, it is not good at logic processing. In addition, there are scenarios in which components render components and convert data by themselves. We need to take them into account.

Therefore, we have provided a set of uniform data transformation mode, which is used in the scene where useresolutions and components render components by themselves and transfer and transform data. For the latter, we provide a unified React Component for rendering sub components in container components: < brickascomponent >.

#Example:

For example, useresolutions can be used as follows:

useResolves:  useProvider: "your.provider"  transform:    descriptions:      - label: "Username"        value: "@{name}"      - label: "Email"        value: "@{email}"

It is now recommended to use Evaluate Placeholders.

transform is a key value pair that defines propertyname = > propertyvalue. It defines how the data request will be converted into properties and output to the component. Where @ {...} is a placeholder similar to parameter injection. For more information about it, please see the next section of this article.

For example, for the above configuration, suppose the data provided by the provider is: {Name: "Eve", email:“ eve@example.com "}, the component will receive the attribute:

properties:  descriptions:    - label: "Username"      value: "Eve"    - label: "Email"      value: "eve@example.com"

Similar processing is also performed where the component renders the sub component. ​​​​​​​

brick: "your.table-brick"properties:  columns:    - title: "User"      dataIndex: "name"      useBrick:        brick: "your.column-brick"        transform:          descriptions:            - label: "Username"              value: "@{cellData}"            - label: "Email"              value: "@{rowData.email}"

Note that the container component here plays a role similar to useresolutions for cell components (columns): it transfers data and provides an interface for data conversion. It may be implemented in the container component as follows:

import { BrickAsComponent } from "@next-core/brick-kit";import { UseBrickConf } from "@next-core/brick-types";
class BrickTable() {  private renderColumn(useBrick: UseBrickConf, rowData, dataIndex) {    return (      <BrickAsComponent        useBrick={useBrick}        // Pass data to the child component for use by the transform data = {{celldata: rowdata [dataindex], rowdata: rowdata}} / >)} / /...}

Note: data is the original data passed by the container to the sub component (for example, the table component may need to fill the cell component with the data of the whole row and the data of a single field at the same time).

#Interface definition

interface ResolveConf {  useProvider?: string;  provider?: string;  method?: string;  args?: any[];  field?: string | string[];  name?: string;  // `Transformfrom ` defines which field of the original data is taken (use ` _. get(data, transformFrom) `). If it is not filled in, the whole original data is taken. transformFrom?: string | string[];  transform?: GeneralTransform;}
type GeneralTransform = string | TransformMap | TransformItem[];
interface TransformMap {  [propName: string]: any;}
interface TransformItem {  from?: string | string[];  to: string | TransformMap;  mapArray?: boolean | "auto";}
// `< brickascomponent / > ` the rendering of sub components will be completed in a unified manner, including data conversion, assignment attributes and binding events. type UseBrickConf = UseSingleBrickConf | UseSingleBrickConf[];
interface UseSingleBrickConf {  brick: string;  properties?: Record<string, any>;  events?: BrickEventsMap;  transformFrom?: string | string[];  transform?: GeneralTransform;  if?: string | ResolveConf;  slots?: UseBrickSlotsConf;}
interface UseBrickSlotsConf {  [slotName: string]: UseBrickSlotConf;}
interface UseBrickSlotConf {  type?: "bricks";  bricks: UseSingleBrickConf[];}

#Placeholder

@{...} is a placeholder used by transform. For example, for @ {someField}, the parsed data is _ get(data, "someField"), so you can use such as @ {some[0].field} to obtain the data within the nested structure. In addition, you can use @ {} to get the entire data.

For more information about Placeholders, see Placeholders.

Note: data in useresolutions represents the data provided by the provider component, and the data passed when the container component renders its own sub components.

#Grammar sugar

In order to simplify the configuration of some common scenarios, we provide some syntax sugar (also known as hidden rules):

#The entire data is assigned to a single attribute

You can use transform: "plainString" to directly assign the entire data to a single attribute plainString. In this case, transform is equivalent to useresolutions []. Name

#Automatic Map of array data source

If the data source is an array, transform will automatically use Array.prototype.map() to implement array mapping. For example, for the following configurations:

useResolves:  - useProvider: "your.provider"    transform:      tagList:        label: "@{name}"        value: "@{email}"

If the data source returns:

# Provider returns:- name: "Eve"  email: "eve@example.com"- name: "Wall E"  email: "wall-e@example.com"

Then the attribute obtained by the component will be:

properties:  tagList:    - label: "Eve"      value: "eve@example.com"    - label: "Wall E"      value: "wall-e@example.com"

#Advanced

Sometimes we need to convert data of mixed array and common type. For example, for the query list interface that provides paging capability, in addition to processing the list of array types, it may also process common types of data such as page pageSize. It is necessary to perform automatic array map ping as required. At this time, we can use the transform configuration in the form of an array.

The transform configuration in the form of an array can perform multiple transformations in order, for example, for the following configurations:

useResolves:  - useProvider: "your.provider"    transform:      - from: "list"        to:          tagList:            label: "@{name}"            value: "@{email}"      - from: "pageSize"        to: "pageSize"

The above configuration will automatically map the array for the list field, but pageSize will not. In addition, you can additionally specify mapArray: false to avoid automatic array mapping.

The configuration of from + to here is similar to that of transformFrom + transform.

If the data source returns:

# Provider returns:list:  - name: "Eve"    email: "eve@example.com"  - name: "Wall E"    email: "wall-e@example.com"pageSize: 10

Then the attribute obtained by the component will be:

properties:  tagList:    - label: "Eve"      value: "eve@example.com"    - label: "Wall E"      value: "wall-e@example.com"  pageSize: 10

#Using slots in useBrick

Now you can use slots in useBrick:

brick: "basic-bricks.list-container"properties:  useBrick:    brick: "your.awesome-brick"    slots:      content:        bricks:          - brick: "your.another-brick"            transform:              textContent: "<% DATA.label %>"  data:    - label: "one"    - label: "two"

The slot configuration is similar to that of ordinary components. The difference is that the slot of type: "routes" cannot be set, and the configuration format of each sub component in bricks is consistent with that of ordinary usebricks. It can also consume the same data source as the parent component.

Tags: Java servlet programming language

Posted by bhola on Tue, 16 Aug 2022 12:30:16 +0300