Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Import/export for types with populated components #93

Merged
merged 17 commits into from
Oct 14, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 48 additions & 14 deletions server/config/type.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { logMessage, sanitizeConfig, dynamicSort, noLimit, getCombinedUid, getCom
const { difference, same } = require('../utils/getArrayDiff');

const ConfigType = class ConfigType {
constructor({ queryString, configName, uid, jsonFields, relations }) {
constructor({ queryString, configName, uid, jsonFields, relations, populate }) {
if (!configName) {
strapi.log.error(logMessage('A config type was registered without a config name.'));
process.exit(0);
Expand All @@ -25,6 +25,7 @@ const ConfigType = class ConfigType {
this.configPrefix = configName;
this.jsonFields = jsonFields || [];
this.relations = relations || [];
this.populate = populate || [];
}

/**
Expand Down Expand Up @@ -68,15 +69,11 @@ const ConfigType = class ConfigType {
});

await Promise.all(relations.map(async (relation) => {
await strapi.query(queryString).delete({
where: { id: relation.id },
});
await strapi.entityService.delete(this.queryString, relation.id);
}));
}));

await queryAPI.delete({
where: { id: existingConfig.id },
});
await strapi.entityService.delete(this.queryString, existingConfig.id);

return;
}
Expand All @@ -89,15 +86,17 @@ const ConfigType = class ConfigType {

// Create entity.
this.relations.map(({ relationName }) => delete query[relationName]);
const newEntity = await queryAPI.create({ data: query });
const newEntity = await strapi.entityService.create(this.queryString, {
data: query,
});

// Create relation entities.
await Promise.all(this.relations.map(async ({ queryString, relationName, parentName }) => {
const relationQueryApi = strapi.query(queryString);

await Promise.all(configContent[relationName].map(async (relationEntity) => {
const relationQuery = { ...relationEntity, [parentName]: newEntity };
await relationQueryApi.create({ data: relationQuery });
await strapi.entityService.create(queryString, {
data: relationQuery,
});
}));
}));
} else { // Config does exist in DB --> update config in DB
Expand All @@ -111,7 +110,21 @@ const ConfigType = class ConfigType {

// Update entity.
this.relations.map(({ relationName }) => delete query[relationName]);
const entity = await queryAPI.update({ where: combinedUidWhereFilter, data: query });

let entity;
switch (this.queryString) {
case "strapi::core-store":
boazpoolman marked this conversation as resolved.
Show resolved Hide resolved
entity = await queryAPI.update({
where: combinedUidWhereFilter,
data: query,
});
break;
default:
entity = await queryAPI.findOne({ where: combinedUidWhereFilter });
await strapi.entityService.update(this.queryString, entity.id, {
data: query,
});
}

// Delete/create relations.
await Promise.all(this.relations.map(async ({ queryString, relationName, parentName, relationSortFields }) => {
Expand All @@ -137,7 +150,7 @@ const ConfigType = class ConfigType {
}));

await Promise.all(configToAdd.map(async (config) => {
await relationQueryApi.create({
await strapi.entityService.create(queryString, {
data: { ...config, [parentName]: entity.id },
});
}));
Expand Down Expand Up @@ -192,7 +205,9 @@ const ConfigType = class ConfigType {
* @returns {object} Object with key value pairs of configs.
*/
getAllFromDatabase = async () => {
const AllConfig = await noLimit(strapi.query(this.queryString), {});
const AllConfig = await noLimit(strapi.query(this.queryString), {
populate: this.populate || null,
boazpoolman marked this conversation as resolved.
Show resolved Hide resolved
});
const configs = {};

await Promise.all(Object.values(AllConfig).map(async (config) => {
Expand Down Expand Up @@ -221,6 +236,25 @@ const ConfigType = class ConfigType {
formattedConfig[relationName] = relations;
}));

this.populate
.filter((populatedFields) => !populatedFields.includes("."))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you tell me why you explicitly exclude populate strings that contain a .?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can also use populate for multiple levels, for example:
image

The levels are separated by ".". At this point, we do not need to clean up each levels, the main level is enough.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah that makes sense. I guess that's something we would have to write in the README documentation as well.

.map((populatedFields) => {
formattedConfig[populatedFields] = formattedConfig[
populatedFields
].map((fields) => {
const sanitizeObjects = (fields) => {
sanitizeConfig(fields);
Object.keys(fields).map((key, index) => {
if (fields[key] && typeof fields[key] === "object") {
sanitizeObjects(fields[key]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This recursive config sanitization is great!

Could you add this directly to the sanitizeConfig utility.
That way we benefit from this logic on all places where we're using the sanitizeConfig utility.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have moved the logic according to your request ;)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. That's great!
There is just one eslint issue with this implementation.

Please see the pipeline output:
https://github.com/boazpoolman/strapi-plugin-config-sync/actions/runs/5819068278/job/15815463391?pr=93

}
});
};
sanitizeObjects(fields);
return fields;
});
});

this.jsonFields.map((field) => formattedConfig[field] = JSON.parse(config[field]));
configs[`${this.configPrefix}.${combinedUid}`] = formattedConfig;
}));
Expand Down