Skip to content

Commit 4c48b30

Browse files
authored
Merge pull request #99 from amtrack/feat/read-in-parallel
feat: read metadata of the same type in parallel in chunks of 10
2 parents 264a150 + f41b6ac commit 4c48b30

File tree

1 file changed

+63
-17
lines changed

1 file changed

+63
-17
lines changed

src/commands/force/source/read.ts

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
11
import type { MetadataType } from "@jsforce/jsforce-node/lib/api/metadata.js";
2-
import { Flags, SfCommand, requiredOrgFlagWithDeprecations } from "@salesforce/sf-plugins-core";
3-
import { ComponentSetBuilder, SourceComponent } from "@salesforce/source-deploy-retrieve";
2+
import {
3+
Flags,
4+
SfCommand,
5+
requiredOrgFlagWithDeprecations,
6+
} from "@salesforce/sf-plugins-core";
7+
import {
8+
ComponentSetBuilder,
9+
SourceComponent,
10+
} from "@salesforce/source-deploy-retrieve";
411
import { filePathsFromMetadataComponent } from "@salesforce/source-deploy-retrieve/lib/src/utils/filePathGenerator.js";
512
import { mkdir, writeFile } from "fs/promises";
613
import { dirname, join } from "path";
714
import { convertToXml, parseCommaSeparatedValues } from "../../../utils.js";
815

916
export class SourceReadCommand extends SfCommand<any> {
1017
public static readonly summary = "Read Metadata using the CRUD Metadata API";
11-
public static readonly description = "Read Metadata using the CRUD Metadata API";
18+
public static readonly description =
19+
"Read Metadata using the CRUD Metadata API";
1220

1321
public static readonly examples = [
1422
`$ <%= config.bin %> <%= command.id %> -m "Profile:Admin"`,
@@ -39,29 +47,67 @@ export class SourceReadCommand extends SfCommand<any> {
3947
const defaultPackageDirectory = this.project.getDefaultPackage().path;
4048
const sourcePaths = packageDirectories.map((dir) => dir.path);
4149
const componentSet = await ComponentSetBuilder.build({
42-
sourcepath: flags.sourcepath && parseCommaSeparatedValues(flags.sourcepath),
50+
sourcepath:
51+
flags.sourcepath && parseCommaSeparatedValues(flags.sourcepath),
4352
...(flags.metadata && {
4453
metadata: {
4554
metadataEntries: parseCommaSeparatedValues(flags.metadata),
4655
directoryPaths: sourcePaths,
47-
}
56+
},
4857
}),
4958
});
50-
for (const component of componentSet) {
51-
this.log("reading", `${component.type.name}:${component.fullName}`, "...");
52-
const mdJson = await conn.metadata.read(component.type.name as MetadataType, component.fullName);
53-
let filePath;
54-
if (component instanceof SourceComponent) {
55-
filePath = component.xml;
56-
} else {
57-
filePath = filePathsFromMetadataComponent(component, join(defaultPackageDirectory, "main", "default")).find(
58-
(p) => p.endsWith(`.${component.type.suffix}-meta.xml`),
59+
const manifestObject = await componentSet.getObject();
60+
const sourceComponents = componentSet.getSourceComponents();
61+
for (const typeMember of manifestObject.Package.types) {
62+
const typeName = typeMember.name;
63+
// https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_readMetadata.htm
64+
const chunkSize =
65+
typeName === "CustomApplication" || typeName === "CustomMetadata"
66+
? 200
67+
: 10;
68+
for (const chunkOfMemberNames of chunk(typeMember.members, chunkSize)) {
69+
const componentNames = chunkOfMemberNames.map(
70+
(memberName) => `${typeName}:${memberName}`
71+
);
72+
this.log("reading", `${componentNames.join(", ")}`, "...");
73+
const metadataResults = await conn.metadata.read(
74+
typeName as MetadataType,
75+
chunkOfMemberNames
5976
);
60-
await mkdir(dirname(filePath), { recursive: true });
77+
for (const metadataResult of metadataResults) {
78+
let filePath;
79+
const component =
80+
sourceComponents.find(
81+
(cmp) =>
82+
cmp.type.name === typeName &&
83+
cmp.fullName === metadataResult.fullName
84+
) ||
85+
componentSet.find(
86+
(cmp) =>
87+
cmp.type.name === typeName &&
88+
cmp.fullName === metadataResult.fullName
89+
);
90+
if (component instanceof SourceComponent) {
91+
filePath = component.xml;
92+
} else {
93+
filePath = filePathsFromMetadataComponent(
94+
component,
95+
join(defaultPackageDirectory, "main", "default")
96+
).find((p) => p.endsWith(`.${component.type.suffix}-meta.xml`));
97+
await mkdir(dirname(filePath), { recursive: true });
98+
}
99+
await writeFile(filePath, convertToXml(component, metadataResult));
100+
}
61101
}
62-
await writeFile(filePath, convertToXml(component, mdJson));
63102
}
64-
65103
return;
66104
}
67105
}
106+
107+
const chunk = (input, size) => {
108+
return input.reduce((arr, item, idx) => {
109+
return idx % size === 0
110+
? [...arr, [item]]
111+
: [...arr.slice(0, -1), [...arr.slice(-1)[0], item]];
112+
}, []);
113+
};

0 commit comments

Comments
 (0)