Skip to content

Commit bba3670

Browse files
committed
WIP
1 parent e4d4d8e commit bba3670

14 files changed

Lines changed: 449 additions & 31 deletions

File tree

packages/deploy/src/clusterChanges/applyCouchbaseClusterChanges.ts

Lines changed: 81 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ import { Cluster, keyspacePath } from '@cbjsdev/cbjs';
22
import {
33
CouchbaseHttpApiConfig,
44
createQueryIndex,
5-
getUser,
5+
getBucket,
66
updateQueryIndex,
77
updateUserPassword,
88
waitForBucket,
99
waitForCollection,
1010
waitForQueryIndex,
1111
waitForScope,
12+
waitForSearchIndex,
1213
waitForUser,
1314
whoami,
1415
} from '@cbjsdev/http-client';
@@ -20,18 +21,21 @@ import {
2021
CouchbaseClusterChangeCreateCollection,
2122
CouchbaseClusterChangeCreateIndex,
2223
CouchbaseClusterChangeCreateScope,
24+
CouchbaseClusterChangeCreateSearchIndex,
2325
CouchbaseClusterChangeCreateUser,
2426
CouchbaseClusterChangeDropBucket,
2527
CouchbaseClusterChangeDropCollection,
2628
CouchbaseClusterChangeDropIndex,
2729
CouchbaseClusterChangeDropScope,
30+
CouchbaseClusterChangeDropSearchIndex,
2831
CouchbaseClusterChangeDropUser,
2932
CouchbaseClusterChangeRecreateBucket,
3033
CouchbaseClusterChangeRecreateIndex,
3134
CouchbaseClusterChangeRecreateUser,
3235
CouchbaseClusterChangeUpdateBucket,
3336
CouchbaseClusterChangeUpdateCollection,
3437
CouchbaseClusterChangeUpdateIndex,
38+
CouchbaseClusterChangeUpdateSearchIndex,
3539
CouchbaseClusterChangeUpdateUser,
3640
CouchbaseClusterChangeUpdateUserPassword,
3741
} from './types.js';
@@ -45,6 +49,11 @@ export type ChangeOptions = {
4549
timeout?: number;
4650
};
4751

52+
function getTimePrefix() {
53+
const d = new Date();
54+
return `[${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}]`;
55+
}
56+
4857
export async function applyCouchbaseClusterChanges(
4958
cluster: Cluster,
5059
apiConfig: CouchbaseHttpApiConfig,
@@ -81,6 +90,9 @@ export async function applyCouchbaseClusterChanges(
8190
dropUser: applyDropUser,
8291
recreateUser: applyRecreateUser,
8392
updateUserPassword: applyUpdateUserPassword,
93+
createSearchIndex: applyCreateSearchIndex,
94+
updateSearchIndex: applyCreateSearchIndex,
95+
dropSearchIndex: applyDropSearchIndex,
8496
};
8597

8698
for (const change of changes) {
@@ -612,7 +624,72 @@ async function applyDropUser(
612624
console.log(`${getTimePrefix()} User "${change.user.username}" dropped`);
613625
}
614626

615-
function getTimePrefix() {
616-
const d = new Date();
617-
return `[${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}]`;
627+
async function applyCreateSearchIndex(
628+
cluster: Cluster,
629+
apiConfig: CouchbaseHttpApiConfig,
630+
change:
631+
| CouchbaseClusterChangeCreateSearchIndex
632+
| CouchbaseClusterChangeUpdateSearchIndex,
633+
opts: ChangeOptions
634+
) {
635+
const bucket = await getBucket(apiConfig, change.bucket);
636+
const config = change.configFn({ sourceName: change.bucket, sourceUUID: bucket.uuid });
637+
638+
console.log(
639+
`${getTimePrefix()} Requesting creation of search index "${change.bucket} # ${change.name}"`
640+
);
641+
642+
await cluster.searchIndexes().upsertIndex(
643+
{
644+
...config,
645+
name: change.name,
646+
},
647+
opts
648+
);
649+
650+
console.log(
651+
`${getTimePrefix()} Waiting for search index "${change.bucket} # ${change.name}" to be created`
652+
);
653+
await waitForSearchIndex(
654+
apiConfig,
655+
change.name,
656+
{
657+
bucket: change.bucket,
658+
},
659+
opts
660+
);
661+
console.log(
662+
`${getTimePrefix()} Search index "${change.bucket} # ${change.name}" created`
663+
);
664+
}
665+
666+
async function applyDropSearchIndex(
667+
cluster: Cluster,
668+
apiConfig: CouchbaseHttpApiConfig,
669+
change: CouchbaseClusterChangeDropSearchIndex,
670+
opts: ChangeOptions
671+
) {
672+
console.log(
673+
`${getTimePrefix()} Requesting deletion of search index "${change.bucket} # ${change.name}"`
674+
);
675+
676+
await cluster.searchIndexes().dropIndex(change.name);
677+
678+
console.log(
679+
`${getTimePrefix()} Waiting for search index "${change.bucket} # ${change.name}" to be deleted`
680+
);
681+
await waitForSearchIndex(
682+
apiConfig,
683+
change.name,
684+
{
685+
bucket: change.bucket,
686+
},
687+
{
688+
...opts,
689+
expectMissing: true,
690+
}
691+
);
692+
console.log(
693+
`${getTimePrefix()} Search index "${change.bucket} # ${change.name}" deleted`
694+
);
618695
}

packages/deploy/src/clusterChanges/getCouchbaseClusterChanges.ts

Lines changed: 130 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,20 @@ import {
99
CouchbaseClusterChangeCreateCollection,
1010
CouchbaseClusterChangeCreateIndex,
1111
CouchbaseClusterChangeCreateScope,
12+
CouchbaseClusterChangeCreateSearchIndex,
1213
CouchbaseClusterChangeCreateUser,
1314
CouchbaseClusterChangeDropCollection,
1415
CouchbaseClusterChangeDropIndex,
1516
CouchbaseClusterChangeDropScope,
17+
CouchbaseClusterChangeDropSearchIndex,
1618
CouchbaseClusterChangeDropUser,
1719
CouchbaseClusterChangeRecreateBucket,
1820
CouchbaseClusterChangeRecreateIndex,
1921
CouchbaseClusterChangeRecreateUser,
2022
CouchbaseClusterChangeUpdateBucket,
2123
CouchbaseClusterChangeUpdateCollection,
2224
CouchbaseClusterChangeUpdateIndex,
25+
CouchbaseClusterChangeUpdateSearchIndex,
2326
CouchbaseClusterChangeUpdateUser,
2427
CouchbaseClusterChangeUpdateUserPassword,
2528
CouchbaseClusterConfig,
@@ -65,6 +68,24 @@ export function getCouchbaseClusterChanges(
6568

6669
changes.push(...obsoleteScopes, ...newScopes);
6770

71+
const obsoleteSearchIndexes = getObsoleteSearchIndexes(
72+
currentKeyspaceConfig,
73+
nextKeyspaceConfig,
74+
requestedBucketName
75+
);
76+
const newSearchIndexes = getNewSearchIndexes(
77+
currentKeyspaceConfig,
78+
nextKeyspaceConfig,
79+
requestedBucketName
80+
);
81+
const updatedSearchIndexes = getUpdatedSearchIndexes(
82+
currentKeyspaceConfig,
83+
nextKeyspaceConfig,
84+
requestedBucketName
85+
);
86+
87+
changes.push(...obsoleteSearchIndexes, ...newSearchIndexes, ...updatedSearchIndexes);
88+
6889
Object.entries(requestedBucket.scopes).forEach(
6990
([requestedScopeName, requestedScope]) => {
7091
const obsoleteCollections = getObsoleteCollections(
@@ -396,10 +417,10 @@ function getObsoleteIndexes(
396417
): CouchbaseClusterChangeDropIndex[] {
397418
const currentIndexes = Object.keys(
398419
currentConfig[bucketName]?.scopes[scopeName]?.collections[collectionName]?.indexes ??
399-
[]
420+
{}
400421
);
401422
const requestedIndexes = Object.keys(
402-
nextConfig[bucketName].scopes[scopeName].collections[collectionName]?.indexes ?? []
423+
nextConfig[bucketName].scopes[scopeName].collections[collectionName]?.indexes ?? {}
403424
);
404425

405426
return currentIndexes
@@ -422,10 +443,10 @@ function getNewIndexes(
422443
): CouchbaseClusterChangeCreateIndex[] {
423444
const currentIndexes = Object.keys(
424445
currentConfig[bucketName]?.scopes[scopeName]?.collections[collectionName]?.indexes ??
425-
[]
446+
{}
426447
);
427448
const requestedIndexes = Object.keys(
428-
nextConfig[bucketName].scopes[scopeName].collections[collectionName]?.indexes ?? []
449+
nextConfig[bucketName].scopes[scopeName].collections[collectionName]?.indexes ?? {}
429450
);
430451

431452
return requestedIndexes
@@ -457,7 +478,7 @@ function getUpdatedIndexes(
457478
collectionName: string
458479
): Array<CouchbaseClusterChangeRecreateIndex | CouchbaseClusterChangeUpdateIndex> {
459480
const requestedIndexes = Object.keys(
460-
nextConfig[bucketName].scopes[scopeName].collections[collectionName]?.indexes ?? []
481+
nextConfig[bucketName].scopes[scopeName].collections[collectionName]?.indexes ?? {}
461482
);
462483

463484
const changes = requestedIndexes
@@ -641,3 +662,107 @@ function getNewUsers(
641662

642663
return changes;
643664
}
665+
666+
function getObsoleteSearchIndexes(
667+
currentConfig: CouchbaseClusterConfig['keyspaces'],
668+
nextConfig: CouchbaseClusterConfig['keyspaces'],
669+
bucketName: string,
670+
scopeName: string,
671+
collectionName: string
672+
): CouchbaseClusterChangeDropSearchIndex[] {
673+
const currentIndexes = Object.keys(currentConfig[bucketName]?.searchIndexes ?? {});
674+
const requestedIndexes = Object.keys(nextConfig[bucketName].searchIndexes ?? {});
675+
676+
return currentIndexes
677+
.filter((b) => !requestedIndexes.includes(b))
678+
.map((b) => ({
679+
type: 'dropSearchIndex',
680+
name: b,
681+
bucket: bucketName,
682+
scope: scopeName,
683+
collection: collectionName,
684+
}));
685+
}
686+
687+
function getNewSearchIndexes(
688+
currentConfig: CouchbaseClusterConfig['keyspaces'],
689+
nextConfig: CouchbaseClusterConfig['keyspaces'],
690+
bucketName: string,
691+
scopeName: string,
692+
collectionName: string
693+
): CouchbaseClusterChangeCreateSearchIndex[] {
694+
const currentIndexes = Object.keys(currentConfig[bucketName]?.searchIndexes ?? {});
695+
const requestedIndexes = Object.keys(nextConfig[bucketName].searchIndexes ?? {});
696+
697+
return requestedIndexes
698+
.filter((indexConfigName) => !currentIndexes.includes(indexConfigName))
699+
.map((indexConfigName) => {
700+
const requestedIndexFn = nextConfig[bucketName]?.searchIndexes?.[indexConfigName];
701+
702+
invariant(requestedIndexFn, 'Search index definition not found.');
703+
704+
return {
705+
type: 'createSearchIndex',
706+
name: indexConfigName,
707+
bucket: bucketName,
708+
scope: scopeName,
709+
collection: collectionName,
710+
configFn: requestedIndexFn,
711+
};
712+
});
713+
}
714+
715+
function getUpdatedSearchIndexes(
716+
currentConfig: CouchbaseClusterConfig['keyspaces'],
717+
nextConfig: CouchbaseClusterConfig['keyspaces'],
718+
bucketName: string,
719+
scopeName: string,
720+
collectionName: string
721+
): CouchbaseClusterChangeUpdateSearchIndex[] {
722+
const requestedIndexes = Object.keys(
723+
nextConfig[bucketName].scopes[scopeName].collections[collectionName]?.searchIndexes ??
724+
{}
725+
);
726+
727+
const changes = requestedIndexes
728+
.map((b) => {
729+
const currentIndexFn = currentConfig[bucketName].searchIndexes?.[b];
730+
const requestedIndexFn = nextConfig[bucketName].searchIndexes?.[b];
731+
732+
if (!currentIndexFn) {
733+
return;
734+
}
735+
736+
invariant(requestedIndexFn, 'Requested search index definition not found.');
737+
738+
const currentIndexConfig = currentIndexFn({
739+
sourceName: bucketName,
740+
sourceUUID: '<sourceUUID>',
741+
});
742+
743+
const requestedIndexConfig = requestedIndexFn({
744+
sourceName: bucketName,
745+
sourceUUID: '<sourceUUID>',
746+
});
747+
748+
invariant(currentIndexFn, 'Current index definition not found.');
749+
invariant(requestedIndexFn, 'Requested index definition not found.');
750+
751+
const indexHaveChanged =
752+
JSON.stringify(currentIndexConfig) !== JSON.stringify(requestedIndexConfig);
753+
754+
if (indexHaveChanged) {
755+
return {
756+
type: 'updateSearchIndex',
757+
name: b,
758+
bucket: bucketName,
759+
scope: scopeName,
760+
collection: collectionName,
761+
configFn: requestedIndexFn,
762+
} satisfies CouchbaseClusterChangeUpdateSearchIndex;
763+
}
764+
})
765+
.filter((c) => c !== undefined);
766+
767+
return changes as CouchbaseClusterChangeUpdateSearchIndex[];
768+
}

0 commit comments

Comments
 (0)