fix: preload relational data (#1847)

* fix: getNesterAppends filter bug

* fix: associationSelect

* fix: associationSelect

* fix: associationSelect

* fix: getAssociationAppends

* fix: sub-form collection context

* refactor: code improve

* refactor: code improve

* refactor: code improve

* refactor: code improve

* refactor: code improve

* fix: appends

* fix: sub-table-appends

* fix: undefine id

* fix: sub-table appends

* fix: sub-table-appends

* fix: sub-table-appends

* fix:  association field appends

* fix:  association field appends

* fix:  association field appends

* fix: sub-table appends

* fix: runWhenParamsChanged

* fix: runWhenParamsChanged

* chore: eager loading tree

* feat: load eager loading tree

* fix: support mutiple row

* fix: support blockTemplate appends

* feat: merge stage of eager loading

* feat: merge stage of belongs to

* feat: merge stage of has one

* fix: dynamic appends not support template schema

* feat: merge stage of belongs to many

* chore: test

* chore: print tree

* chore: using eager loading tree in repository find

* fix: empty ids load

* fix: belongs to many query

* fix: load belongs to  association

* fix: eager load data accessor

* fix: has many

* fix: test

* fix: useAssociationNames

* fix: filter with appends

* chore: remove handle appends query

* chore: console.log

* chore: console.log

* fix: test

* fix: support template block schema

* fix: sub-nester-appends

---------

Co-authored-by: Chareice <chareice@live.com>
This commit is contained in:
katherinehhh 2023-05-20 17:42:26 +08:00 committed by GitHub
parent eac034cb23
commit cb2feb304d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 65 additions and 33 deletions

View File

@ -53,14 +53,13 @@ const useResource = (props: UseResourceProps) => {
const api = useAPIClient(); const api = useAPIClient();
const association = useAssociation(props); const association = useAssociation(props);
const sourceId = useSourceId?.(); const sourceId = useSourceId?.();
const field = useField<Field>(); const field = useField<Field>();
if (block === 'TableField') { if (block === 'TableField') {
const options = { const options = {
field, field,
api, api,
resource, resource,
sourceId: sourceId || record[association?.sourceKey || 'id'], sourceId: sourceId || record[association?.sourceKey || 'id'] || record?.__parent?.[association?.sourceKey || 'id'],
}; };
return new TableFieldResource(options); return new TableFieldResource(options);
} }

View File

@ -1,7 +1,7 @@
import { Schema, SchemaExpressionScopeContext, useField, useFieldSchema, useForm } from '@formily/react'; import { Schema, SchemaExpressionScopeContext, useField, useFieldSchema, useForm } from '@formily/react';
import { parse } from '@nocobase/utils/client'; import { parse } from '@nocobase/utils/client';
import { Modal, message } from 'antd'; import { Modal, message } from 'antd';
import { cloneDeep } from 'lodash'; import { cloneDeep, uniq } from 'lodash';
import get from 'lodash/get'; import get from 'lodash/get';
import omit from 'lodash/omit'; import omit from 'lodash/omit';
import { ChangeEvent, useContext, useEffect } from 'react'; import { ChangeEvent, useContext, useEffect } from 'react';
@ -21,6 +21,7 @@ import { useBlockRequestContext, useFilterByTk } from '../BlockProvider';
import { useDetailsBlockContext } from '../DetailsBlockProvider'; import { useDetailsBlockContext } from '../DetailsBlockProvider';
import { mergeFilter } from '../SharedFilterProvider'; import { mergeFilter } from '../SharedFilterProvider';
import { TableFieldResource } from '../TableFieldProvider'; import { TableFieldResource } from '../TableFieldProvider';
import { useSchemaTemplateManager } from '../../schema-templates';
export const usePickActionProps = () => { export const usePickActionProps = () => {
const form = useForm(); const form = useForm();
@ -1072,22 +1073,24 @@ export const useAssociationFilterBlockProps = () => {
}; };
}; };
export const useAssociationNames = (collection) => { const getTemplateSchema = (schema) => {
const { getCollectionFields, getCollectionJoinField } = useCollectionManager(); const conf = {
const { getField } = useCollection(); url: `/uiSchemas:getJsonSchema/${schema?.uid}`,
const collectionFields = getCollectionFields(collection); };
const associationFields = new Set(); const { data, loading, run } = useRequest(conf, { manual: true });
for (const collectionField of collectionFields) { if (loading) {
if (collectionField.target) {
associationFields.add(collectionField.name);
const fields = getCollectionFields(collectionField.target);
for (const field of fields) {
if (field.target) {
associationFields.add(`${collectionField.name}.${field.name}`);
}
}
}
} }
useEffect(() => {
if (schema?.uid) {
run();
}
}, [schema?.uid]);
return schema?.uid ? new Schema(data?.data) : null;
};
export const useAssociationNames = (collection) => {
const { getCollectionJoinField } = useCollectionManager();
const { getTemplateById } = useSchemaTemplateManager();
const fieldSchema = useFieldSchema(); const fieldSchema = useFieldSchema();
const associationValues = []; const associationValues = [];
const formSchema = fieldSchema.reduceProperties((buf, schema) => { const formSchema = fieldSchema.reduceProperties((buf, schema) => {
@ -1097,26 +1100,37 @@ export const useAssociationNames = (collection) => {
return buf; return buf;
}, new Schema({})); }, new Schema({}));
const templateSchema = formSchema.reduceProperties((buf, schema) => {
if (schema['x-component'] === 'BlockTemplate') {
return schema;
}
return buf;
}, null);
const getAssociationAppends = (schema, arr = []) => { const getAssociationAppends = (schema, arr = []) => {
const data = schema.reduceProperties((buf, s) => { const data = schema.reduceProperties((buf, s) => {
const collectionfield = const collectionfield = s['x-collection-field'] && getCollectionJoinField(s['x-collection-field']);
getField(s.name) || (s['x-collection-field'] && getCollectionJoinField(s['x-collection-field'])); if (
if (collectionfield && ['hasOne', 'hasMany', 'belongsTo', 'belongsToMany'].includes(collectionfield.type)) { collectionfield &&
['hasOne', 'hasMany', 'belongsTo', 'belongsToMany'].includes(collectionfield.type) &&
s['x-component'] !== 'TableField'
) {
buf.push(s.name);
if (['Nester', 'SubTable'].includes(s['x-component-props']?.mode)) { if (['Nester', 'SubTable'].includes(s['x-component-props']?.mode)) {
associationValues.push(s.name); associationValues.push(s.name);
} }
if (s['x-component-props'].mode === 'Nester') {
buf.push(s.name);
if (s['x-component-props'].mode === 'Nester' || s['x-component'] === 'TableField') {
return getAssociationAppends(s, buf); return getAssociationAppends(s, buf);
} }
return buf; return buf;
} else { } else {
if (s['x-component'] === 'Grid' || s['x-component'] === 'TableV2') { if (s['x-component'] === 'Grid.Row') {
const kk = buf?.concat?.(); const kk = buf?.concat?.();
return getNesterAppends(s, kk || []); return getNesterAppends(s, kk || []);
} else { } else {
return !s['x-component']?.includes('Action.') && getAssociationAppends(s, buf); return !s['x-component']?.includes('Action.') && s['x-component'] !== 'TableField'
? getAssociationAppends(s, buf)
: buf;
} }
} }
}, arr); }, arr);
@ -1130,15 +1144,24 @@ export const useAssociationNames = (collection) => {
if (Array.isArray(list[i])) { if (Array.isArray(list[i])) {
`${prefix}` !== `${list[i][0]}` && flattenHelper(list[i], `${prefix}.${list[i][0]}`); `${prefix}` !== `${list[i][0]}` && flattenHelper(list[i], `${prefix}.${list[i][0]}`);
} else { } else {
const str = prefix.replaceAll(`${list[i]}`, '').replace('..', '.').trim(); const searchTerm = `.${list[i]}`;
!list.includes(str) && flattenedList.push(`${str}${list[i]}`); const lastIndex = prefix.lastIndexOf(searchTerm);
let str = '';
if (lastIndex !== -1) {
str = prefix.slice(0, lastIndex) + prefix.slice(lastIndex + searchTerm.length);
}
if (!str) {
!list.includes(str) && flattenedList.push(`${list[i]}`);
} else {
!list.includes(str) ? flattenedList.push(`${str}.${list[i]}`) : flattenedList.push(str);
}
} }
} }
} }
for (let i = 0; i < nestedList.length; i++) { for (let i = 0; i < nestedList.length; i++) {
flattenHelper(nestedList[i], nestedList[i][0]); flattenHelper(nestedList[i], nestedList[i][0]);
} }
return flattenedList.filter((obj) => !obj.startsWith('.')); return uniq(flattenedList.filter((obj) => !obj?.startsWith('.')));
} }
const getNesterAppends = (gridSchema, data) => { const getNesterAppends = (gridSchema, data) => {
gridSchema.reduceProperties((buf, s) => { gridSchema.reduceProperties((buf, s) => {
@ -1147,8 +1170,18 @@ export const useAssociationNames = (collection) => {
}, data); }, data);
return data.filter((g) => g.length); return data.filter((g) => g.length);
}; };
const data = getAssociationAppends(formSchema);
const associations = data.filter((g) => g.length); const template = getTemplateById(templateSchema?.['x-component-props']?.templateId);
const appends = flattenNestedList(associations); const schema = getTemplateSchema(template);
return { appends, updateAssociationValues: appends.filter((v) => associationValues.includes(v)) }; if (schema) {
const associations = getAssociationAppends(schema);
const appends = flattenNestedList(associations);
console.log(appends, associations);
return { appends, updateAssociationValues: appends.filter((v) => associationValues.includes(v)) };
}
if (!schema) {
const associations = getAssociationAppends(formSchema);
const appends = flattenNestedList(associations);
return { appends, updateAssociationValues: appends.filter((v) => associationValues.includes(v)) };
}
}; };