1import * as integrations from "@distilled.cloud/gcp/integrations_v1";
2import * as Effect from "effect/Effect";
3import * as Stream from "effect/Stream";
4import { isDeleted, lastSegment, locationParent } from "./ownership.ts";
5
6export const parseResourceName = (
7 name: string,
8 collection: string,
9 defaultLocation: string,
10) => {
11 const parts = name.split("/").filter((part) => part.length > 0);
12 const collectionAt = parts.lastIndexOf(collection);
13 const locationsAt = parts.lastIndexOf("locations");
14 const projectsAt = parts.lastIndexOf("projects");
15 const instancesAt = parts.lastIndexOf("sfdcInstances");
16 return {
17 project:
18 projectsAt >= 0 && parts[projectsAt + 1] ? parts[projectsAt + 1]! : "",
19 location:
20 locationsAt >= 0 && parts[locationsAt + 1]
21 ? parts[locationsAt + 1]!
22 : defaultLocation,
23 id:
24 collectionAt >= 0 && parts[collectionAt + 1]
25 ? parts[collectionAt + 1]!
26 : lastSegment(name),
27 sfdcInstanceId:
28 instancesAt >= 0 && parts[instancesAt + 1] ? parts[instancesAt + 1]! : "",
29 sfdcInstance:
30 instancesAt >= 0
31 ? parts.slice(0, instancesAt + 2).join("/")
32 : parts.slice(0, Math.max(0, parts.length - 2)).join("/"),
33 parent:
34 collectionAt > 0
35 ? parts.slice(0, collectionAt).join("/")
36 : parts.slice(0, Math.max(0, parts.length - 1)).join("/"),
37 };
38};
39
40const collectPages = <Page, A, E, R>(
41 pages: Stream.Stream<Page, E, R>,
42 items: (page: Page) => readonly A[] | undefined,
43) =>
44 pages.pipe(
45 Stream.flatMap((page) => Stream.fromIterable(items(page) ?? [])),
46 Stream.runCollect,
47 Effect.map((chunk) => Array.from(chunk)),
48 );
49
50export const listSfdcInstances = (parent: string) =>
51 collectPages(
52 integrations.listProjectsLocationsSfdcInstances.pages({
53 parent,
54 pageSize: 1000,
55 }),
56 (page) => page.sfdcInstances,
57 ).pipe(
58 Effect.catchTag("NotFound", () =>
59 Effect.succeed(
60 [] as integrations.GoogleCloudIntegrationsV1alphaSfdcInstance[],
61 ),
62 ),
63 Effect.map((items) => items.filter((item) => !isDeleted(item))),
64 );
65
66export const listSfdcChannels = (parent: string) =>
67 collectPages(
68 integrations.listProjectsLocationsSfdcInstancesSfdcChannels.pages({
69 parent,
70 pageSize: 1000,
71 }),
72 (page) => page.sfdcChannels,
73 ).pipe(
74 Effect.catchTag("NotFound", () =>
75 Effect.succeed(
76 [] as integrations.GoogleCloudIntegrationsV1alphaSfdcChannel[],
77 ),
78 ),
79 Effect.map((items) => items.filter((item) => !isDeleted(item))),
80 );
81
82export const listTemplates = (parent: string) =>
83 collectPages(
84 integrations.listProjectsLocationsTemplates.pages({
85 parent,
86 pageSize: 1000,
87 }),
88 (page) => page.templates,
89 ).pipe(
90 Effect.catchTag("NotFound", () =>
91 Effect.succeed(
92 [] as integrations.GoogleCloudIntegrationsV1alphaTemplate[],
93 ),
94 ),
95 );
96
97export const listOwnedSfdcChannels = (project: string, location: string) =>
98 Effect.gen(function* () {
99 const instances = yield* listSfdcInstances(
100 locationParent(project, location),
101 );
102 const groups = yield* Effect.forEach(
103 instances.filter((instance) => (instance.name ?? "").length > 0),
104 (instance) => listSfdcChannels(instance.name!),
105 { concurrency: 4 },
106 );
107 return groups.flat();
108 });
109
110export const findSfdcInstanceByDescription = (
111 parent: string,
112 description: string,
113) =>
114 listSfdcInstances(parent).pipe(
115 Effect.map((items) =>
116 items.find((item) => item.description === description),
117 ),
118 );
119
120export const findSfdcChannelByDescription = (
121 parent: string,
122 description: string,
123) =>
124 listSfdcChannels(parent).pipe(
125 Effect.map((items) =>
126 items.find((item) => item.description === description),
127 ),
128 );
129
130export const findTemplateByDescription = (
131 parent: string,
132 description: string,
133) =>
134 listTemplates(parent).pipe(
135 Effect.map((items) =>
136 items.find((item) => item.description === description),
137 ),
138 );