diff --git a/Couchbase/Cluster.php b/Couchbase/Cluster.php index 3ab03d7e..b894d1a6 100644 --- a/Couchbase/Cluster.php +++ b/Couchbase/Cluster.php @@ -265,12 +265,11 @@ public function users(): UserManager * Creates a new manager object for managing analytics query indexes. * * @return AnalyticsIndexManager - * @throws UnsupportedOperationException * @since 4.0.0 */ public function analyticsIndexes(): AnalyticsIndexManager { - throw new UnsupportedOperationException(); + return new AnalyticsIndexManager($this->core); } /** diff --git a/Couchbase/Management/AnalyticsDataset.php b/Couchbase/Management/AnalyticsDataset.php new file mode 100644 index 00000000..76a5e919 --- /dev/null +++ b/Couchbase/Management/AnalyticsDataset.php @@ -0,0 +1,124 @@ +name = $name; + $this->dataverseName = $dataverseName; + $this->linkName = $linkName; + $this->bucketName = $bucketName; + } + + /** + * Static helper to keep code more readable. + * + * @param string $name + * @param string $dataverseName + * @param string $linkName + * @param string $bucketName + * + * @return AnalyticsDataset + * @since 4.2.4 + */ + public static function build( + string $name, + string $dataverseName, + string $linkName, + string $bucketName + ) + { + return new AnalyticsDataset($name, $dataverseName, $linkName, $bucketName); + } + + /** + * Gets the name of the analytics dataset (or collection) + * + * @return string + * @since 4.2.4 + */ + public function name(): string + { + return $this->name; + } + + /** + * Gets the name of the dataverse in which this dataset is stored. + * + * @return string + * @since 4.2.4 + */ + public function dataverseName(): string + { + return $this->dataverseName; + } + + /** + * Gets the name of the link that is associated with this dataset. + * + * @return string + * @since 4.2.4 + */ + public function linkName(): string + { + return $this->linkName; + } + + /** + * Gets the name of the bucket that this dataset includes. + * + * @return string + * @since 4.2.4 + */ + public function bucketName(): string + { + return $this->bucketName; + } + + /** + * @internal + */ + public static function import(array $data): AnalyticsDataset + { + return AnalyticsDataset::build( + $data["name"] ?? "", + $data["dataverseName"] ?? "", + $data["linkName"] ?? "", + $data["bucketName"] ?? "" + ); + } +} diff --git a/Couchbase/Management/AnalyticsIndex.php b/Couchbase/Management/AnalyticsIndex.php new file mode 100644 index 00000000..d3571316 --- /dev/null +++ b/Couchbase/Management/AnalyticsIndex.php @@ -0,0 +1,100 @@ +name = $name; + $this->datasetName = $datasetName; + $this->dataverseName = $dataverseName; + $this->isPrimary = $isPrimary; + } + + /** + * Static helper to keep code more readable + * + * @param string $name + * @param string $datasetName + * @param string $dataverseName + * @param bool $isPrimary + * + * @return AnalyticsIndex + * @since 4.2.4 + */ + public static function build(string $name, string $datasetName, string $dataverseName, bool $isPrimary) + { + return new AnalyticsIndex($name, $datasetName, $dataverseName, $isPrimary); + } + + /** + * Gets the name of this index + * + * @return string + * @since 4.2.4 + */ + public function name(): string + { + return $this->name; + } + + /** + * Gets the name of the analytics dataset in which this index exists + * + * @return string + * @since 4.2.4 + */ + public function datasetName(): string + { + return $this->datasetName; + } + + /** + * Gets the name of the dataverse in which this index exists. + * + * @return string + * @since 4.2.4 + */ + public function dataverseName(): string + { + return $this->dataverseName; + } + + /** + * Returns true if this index is a primary index. + * + * @return bool + * @since 4.2.4 + */ + public function isPrimary(): bool + { + return $this->isPrimary; + } + + /** + * @internal + */ + public static function import(array $data): AnalyticsIndex + { + return AnalyticsIndex::build( + $data["name"] ?? "", + $data["datasetName"] ?? "", + $data["dataverseName"] ?? "", + $data["isPrimary"] ?? false + ); + } +} diff --git a/Couchbase/Management/AnalyticsIndexManager.php b/Couchbase/Management/AnalyticsIndexManager.php index 06c0dc01..c44385c3 100644 --- a/Couchbase/Management/AnalyticsIndexManager.php +++ b/Couchbase/Management/AnalyticsIndexManager.php @@ -20,65 +20,249 @@ namespace Couchbase\Management; +use Couchbase\Exception\CouchbaseException; +use Couchbase\Exception\InvalidArgumentException; +use Couchbase\Extension; + class AnalyticsIndexManager { - public function createDataverse(string $dataverseName, CreateAnalyticsDataverseOptions $options = null) + /** + * @var resource + */ + private $core; + + /** + * @internal + */ + public function __construct($core) + { + $this->core = $core; + } + + /** + * Creates a new analytics dataverse. + * + * @param string $dataverseName the name of the dataverse to create + * @param CreateAnalyticsDataverseOptions|null $options The options to use when creating the dataverse + * + * @since 4.2.4 + */ + public function createDataverse(string $dataverseName, CreateAnalyticsDataverseOptions $options = null): void { + Extension\analyticsDataverseCreate($this->core, $dataverseName, CreateAnalyticsDataverseOptions::export($options)); } - public function dropDataverse(string $dataverseName, DropAnalyticsDataverseOptions $options = null) + /** + * Deletes an analytics dataverse. + * + * @param string $dataverseName the name of the dataverse to drop + * @param DropAnalyticsDataverseOptions|null $options The options to use when dropping the dataverse + * + * @since 4.2.4 + */ + public function dropDataverse(string $dataverseName, DropAnalyticsDataverseOptions $options = null): void { + Extension\analyticsDataverseDrop($this->core, $dataverseName, DropAnalyticsDataverseOptions::export($options)); } - public function createDataset(string $datasetName, string $bucketName, CreateAnalyticsDatasetOptions $options = null) + /** + * Creates a new analytics dataset + * + * @param string $datasetName The name of the dataset to create + * @param string $bucketName The name of the bucket where the dataset is stored inside + * @param CreateAnalyticsDatasetOptions|null $options The options to use when creating the dataset + * + * @since 4.2.4 + */ + public function createDataset(string $datasetName, string $bucketName, CreateAnalyticsDatasetOptions $options = null): void { + Extension\analyticsDatasetCreate($this->core, $datasetName, $bucketName, CreateAnalyticsDatasetOptions::export($options)); } - public function dropDataset(string $datasetName, DropAnalyticsDatasetOptions $options = null) + /** + * Deletes an analytics dataset + * + * @param string $datasetName The name of the dataset to drop + * @param DropAnalyticsDatasetOptions|null $options The options to use when dropping the dataset + * + * @since 4.2.4 + */ + public function dropDataset(string $datasetName, DropAnalyticsDatasetOptions $options = null): void { + Extension\analyticsDatasetDrop($this->core, $datasetName, DropAnalyticsDatasetOptions::export($options)); } - public function getAllDatasets() + /** + * Fetches all datasets from the analytics service + * + * @param GetAllAnalyticsDatasetsOptions|null $options The options to use when fetching the datasets + * + * @return array an array of {@link AnalyticsDataset} + * @since 4.2.4 + */ + public function getAllDatasets(GetAllAnalyticsDatasetsOptions $options = null): array { + $result = Extension\analyticsDatasetGetAll($this->core, GetAllAnalyticsDatasetsOptions::export($options)); + $datasets = []; + foreach ($result as $dataset) { + $datasets[] = AnalyticsDataset::import($dataset); + } + return $datasets; } - public function createIndex(string $datasetName, string $indexName, array $fields, CreateAnalyticsIndexOptions $options = null) + /** + * Creates a new analytics index. + * + * @param string $datasetName The name of the dataset in which the index should be created + * @param string $indexName The name of the index to create + * @param array $fields The fields that should be indexed. + * @param CreateAnalyticsIndexOptions|null $options The options to use when creating the index. + * + * @since 4.2.4 + */ + public function createIndex(string $datasetName, string $indexName, array $fields, CreateAnalyticsIndexOptions $options = null): void { + Extension\analyticsIndexCreate($this->core, $datasetName, $indexName, $fields, CreateAnalyticsIndexOptions::export($options)); } - public function dropIndex(string $datasetName, string $indexName, DropAnalyticsIndexOptions $options = null) + /** + * Deletes an analytics index + * + * @param string $datasetName The name of the dataset in which the index exists + * @param string $indexName The name of the index to drop + * @param DropAnalyticsIndexOptions|null $options The options to use when dropping the index + * + * @since 4.2.4 + */ + public function dropIndex(string $datasetName, string $indexName, DropAnalyticsIndexOptions $options = null): void { + Extension\analyticsIndexDrop($this->core, $datasetName, $indexName, DropAnalyticsIndexOptions::export($options)); } - public function getAllIndexes() + /** + * Fetches all indexes from the analytics service. + * + * @param GetAllAnalyticsIndexesOptions|null $options The options to use when fetching the indexes. + * + * @return array array of {@link AnalyticsIndex} + * @since 4.2.4 + */ + public function getAllIndexes(GetAllAnalyticsIndexesOptions $options = null): array { + $result = Extension\analyticsIndexGetAll($this->core, GetAllAnalyticsIndexesOptions::export($options)); + $indexes = []; + foreach ($result as $index) { + $indexes[] = AnalyticsIndex::import($index); + } + return $indexes; } - public function connectLink(ConnectAnalyticsLinkOptions $options = null) + /** + * Connects the analytics link (by default, `Default.Local`) + * + * @param ConnectAnalyticsLinkOptions|null $options The options to use when connecting the link + * + * @since 4.2.4 + */ + public function connectLink(ConnectAnalyticsLinkOptions $options = null): void { + Extension\analyticsLinkConnect($this->core, ConnectAnalyticsLinkOptions::export($options)); } - public function disconnectLink(DisconnectAnalyticsLinkOptions $options = null) + /** + * Disconnects the analytics link (by default, `Default.local`) + * + * @param DisconnectAnalyticsLinkOptions|null $options The options to use when disconnecting the link + * + * @since 4.2.4 + */ + public function disconnectLink(DisconnectAnalyticsLinkOptions $options = null): void { + Extension\analyticsLinkDisconnect($this->core, DisconnectAnalyticsLinkOptions::export($options)); } - public function getPendingMutations() + /** + * Fetches the pending mutations for different dataverses. + * + * @param GetAnalyticsPendingMutationsOptions|null $options The options to use when fetching the pending mutations + * + * @return array Associative array where top level keys are dataverse names, + * and values are an associative array of datasets to number of pending mutations. + * @since 4.2.4 + */ + public function getPendingMutations(GetAnalyticsPendingMutationsOptions $options = null): array { + $results = Extension\analyticsPendingMutationsGet($this->core, GetAnalyticsPendingMutationsOptions::export($options)); + + return GetAnalyticsPendingMutationsOptions::import($results); } - public function createLink(AnalyticsLink $link, CreateAnalyticsLinkOptions $options = null) + /** + * Creates a new analytics link. + * + * @param AnalyticsLink $link The link that should be created. Either a Couchbase, s3, or azureblob link. + * @param CreateAnalyticsLinkOptions|null $options The options to use when creating the link + * + * @see CouchbaseRemoteAnalyticsLink + * @see S3ExternalAnalyticsLink + * @see AzureBlobExternalAnalyticsLink + * + * @since 4.2.4 + */ + public function createLink(AnalyticsLink $link, CreateAnalyticsLinkOptions $options = null): void { + Extension\analyticsLinkCreate($this->core, $link->export(), CreateAnalyticsLinkOptions::export($options)); } - public function replaceLink(AnalyticsLink $link, ReplaceAnalyticsLinkOptions $options = null) + /** + * Replaces an existing analytics link. + * + * @param AnalyticsLink $link The link that should be replaced, Either a Couchbase, s3, or azureblob link. + * @param ReplaceAnalyticsLinkOptions|null $options The options to use when replacing the link + * + * @see CouchbaseRemoteAnalyticsLink + * @see S3ExternalAnalyticsLink + * @see AzureBlobExternalAnalyticsLink + * + * @since 4.2.4 + */ + public function replaceLink(AnalyticsLink $link, ReplaceAnalyticsLinkOptions $options = null): void { + Extension\analyticsLinkReplace($this->core, $link->export(), ReplaceAnalyticsLinkOptions::export($options)); } - public function dropLink(string $linkName, string $dataverseName, DropAnalyticsLinkOptions $options = null) + /** + * Deletes an analytics link. + * + * @param string $linkName The name of the link + * @param string $dataverseName The dataverse in which the link exists + * @param DropAnalyticsLinkOptions|null $options The options to use when replacing hte link. + * + * @since 4.2.4 + */ + public function dropLink(string $linkName, string $dataverseName, DropAnalyticsLinkOptions $options = null): void { + Extension\analyticsLinkDrop($this->core, $linkName, $dataverseName, DropAnalyticsLinkOptions::export($options)); } - public function getLinks(GetAnalyticsLinksOptions $options = null) + /** + * Returns a list of current analytics links. + * + * @param GetAnalyticsLinksOptions|null $options The options to use when fetching the links + * + * @throws InvalidArgumentException If the linkName is set, the dataverseName must also be set. + * @throws CouchbaseException + * + * @return array array of {@link CouchbaseRemoteAnalyticsLink}, {@link S3ExternalAnalyticsLink}, or {@link AzureBlobExternalAnalyticsLink} + * @since 4.2.4 + */ + public function getLinks(GetAnalyticsLinksOptions $options = null): array { + $result = Extension\analyticsLinkGetAll($this->core, GetAnalyticsLinksOptions::export($options)); + $links = []; + foreach ($result as $link) { + $links[] = AnalyticsLink::import($link); + } + return $links; } } diff --git a/Couchbase/Management/AnalyticsLink.php b/Couchbase/Management/AnalyticsLink.php index f118e5ea..30c475f2 100644 --- a/Couchbase/Management/AnalyticsLink.php +++ b/Couchbase/Management/AnalyticsLink.php @@ -20,6 +20,92 @@ namespace Couchbase\Management; -interface AnalyticsLink +use Couchbase\Exception\CouchbaseException; + +abstract class AnalyticsLink { + /** + * Gets the name of the link + * + * @return string + * @since 4.2.4 + */ + abstract protected function name(): string; + + /** + * Gets the name of the dataverse to which this link belongs to. + * + * @return string + * @since 4.2.4 + */ + abstract protected function dataverseName(): string; + + /** + * Gets the link type. One of "couchbase", "s3" or "azureblob" + * + * @see AnalyticsLinkType::COUCHBASE + * @see AnalyticsLinkType::S3 + * @see AnalyticsLinkType::AZURE_BLOB + * + * @return string + * @since 4.2.4 + */ + abstract protected function linkType(): string; + + /** + * @internal + */ + abstract protected function export(): array; + + /** + * @throws CouchbaseException + * @internal + */ + public static function import(array $data): AnalyticsLink + { + if ($data["type"] == "couchbase") { + $link = CouchbaseRemoteAnalyticsLink::build($data["name"] ?? "", $data["dataverseName"] ?? "", $data["hostname"] ?? ""); + if (array_key_exists("username", $data)) { + $link->setUsername($data["username"]); + } + if (array_key_exists("encryptionLevel", $data)) { + if ($data["encryptionLevel"] == "full") { + $encryption = CouchbaseAnalyticsEncryptionSettings::build(AnalyticsEncryptionLevel::FULL); + } elseif ($data["encryptionLevel"] == "half") { + $encryption = CouchbaseAnalyticsEncryptionSettings::build(AnalyticsEncryptionLevel::HALF); + } else { + $encryption = CouchbaseAnalyticsEncryptionSettings::build(AnalyticsEncryptionLevel::NONE); + } + if (array_key_exists("certificate", $data)) { + $encryption->setCertificate($data["certificate"]); + } + if (array_key_exists("clientCertificate", $data)) { + $encryption->setClientCertificate($data["clientCertificate"]); + } + + $link->setEncryption($encryption); + } + return $link; + } elseif ($data["type"] == "s3") { + $link = S3ExternalAnalyticsLink::build($data["name"] ?? "", $data["dataverseName"] ?? "", $data["accessKeyId"] ?? "", $data["region"] ?? "", ""); + if (array_key_exists("serviceEndpoint", $data)) { + $link->setServiceEndpoint($data["serviceEndpoint"]); + } + return $link; + } elseif ($data["type"] == "azureblob") { + $link = AzureBlobExternalAnalyticsLink::build($data["name"] ?? "", $data["dataverseName"] ?? ""); + if (array_key_exists("accountName", $data)) { + $link->setAccountName($data["accountName"]); + } + if (array_key_exists("blobEndpoint", $data)) { + $link->setBlobEndpoint($data["blobEndpoint"]); + } + if (array_key_exists("endpointSuffix", $data)) { + $link->setEndpointSuffix($data["endpointSuffix"]); + } + return $link; + } else { + throw new CouchbaseException("Unexpected analytics link type received importing"); + } + } } diff --git a/Couchbase/Management/AzureBlobExternalAnalyticsLink.php b/Couchbase/Management/AzureBlobExternalAnalyticsLink.php index e36bcbce..88f36937 100644 --- a/Couchbase/Management/AzureBlobExternalAnalyticsLink.php +++ b/Couchbase/Management/AzureBlobExternalAnalyticsLink.php @@ -20,28 +20,36 @@ namespace Couchbase\Management; -class AzureBlobExternalAnalyticsLink implements AnalyticsLink +class AzureBlobExternalAnalyticsLink extends AnalyticsLink { - /** - * Sets name of the link - * - * @param string $name - * - * @return AzureBlobExternalAnalyticsLink - */ - public function name(string $name): AzureBlobExternalAnalyticsLink + private string $dataverseName; + private string $name; + + private ?string $connectionString = null; + private ?string $accountName = null; + private ?string $accountKey = null; + private ?string $sharedAccessSignature = null; + private ?string $blobEndpoint = null; + private ?string $endpointSuffix = null; + + public function __construct(string $name, string $dataverseName) { + $this->name = $name; + $this->dataverseName = $dataverseName; } /** - * Sets dataverse this link belongs to + * Static helper to keep code more readable * - * @param string $dataverse + * @param string $name + * @param string $dataverseName * * @return AzureBlobExternalAnalyticsLink + * @since 4.2.4 */ - public function dataverse(string $dataverse): AzureBlobExternalAnalyticsLink + public static function build(string $name, string $dataverseName): AzureBlobExternalAnalyticsLink { + return new AzureBlobExternalAnalyticsLink($name, $dataverseName); } /** @@ -53,8 +61,10 @@ public function dataverse(string $dataverse): AzureBlobExternalAnalyticsLink * * @return AzureBlobExternalAnalyticsLink */ - public function connectionString(string $connectionString): AzureBlobExternalAnalyticsLink + public function setConnectionString(string $connectionString): AzureBlobExternalAnalyticsLink { + $this->connectionString = $connectionString; + return $this; } /** @@ -64,8 +74,10 @@ public function connectionString(string $connectionString): AzureBlobExternalAna * * @return AzureBlobExternalAnalyticsLink */ - public function accountName(string $accountName): AzureBlobExternalAnalyticsLink + public function setAccountName(string $accountName): AzureBlobExternalAnalyticsLink { + $this->accountName = $accountName; + return $this; } /** @@ -75,8 +87,10 @@ public function accountName(string $accountName): AzureBlobExternalAnalyticsLink * * @return AzureBlobExternalAnalyticsLink */ - public function accountKey(string $accountKey): AzureBlobExternalAnalyticsLink + public function setAccountKey(string $accountKey): AzureBlobExternalAnalyticsLink { + $this->accountKey = $accountKey; + return $this; } /** @@ -86,8 +100,10 @@ public function accountKey(string $accountKey): AzureBlobExternalAnalyticsLink * * @return AzureBlobExternalAnalyticsLink */ - public function sharedAccessSignature(string $signature): AzureBlobExternalAnalyticsLink + public function setSharedAccessSignature(string $signature): AzureBlobExternalAnalyticsLink { + $this->sharedAccessSignature = $signature; + return $this; } /** @@ -97,8 +113,10 @@ public function sharedAccessSignature(string $signature): AzureBlobExternalAnaly * * @return AzureBlobExternalAnalyticsLink */ - public function blobEndpoint(string $blobEndpoint): AzureBlobExternalAnalyticsLink + public function setBlobEndpoint(string $blobEndpoint): AzureBlobExternalAnalyticsLink { + $this->blobEndpoint = $blobEndpoint; + return $this; } /** @@ -108,7 +126,71 @@ public function blobEndpoint(string $blobEndpoint): AzureBlobExternalAnalyticsLi * * @return AzureBlobExternalAnalyticsLink */ - public function endpointSuffix(string $suffix): AzureBlobExternalAnalyticsLink + public function setEndpointSuffix(string $suffix): AzureBlobExternalAnalyticsLink + { + $this->endpointSuffix = $suffix; + return $this; + } + + /** + * @inheritdoc + */ + public function name(): string + { + return $this->name; + } + + /** + * @inheritdoc + */ + public function dataverseName(): string + { + return $this->dataverseName; + } + + /** + * @inheritdoc + */ + public function linkType(): string + { + return AnalyticsLinkType::AZURE_BLOB; + } + + /** + * @internal + */ + public function export(): array { + $json = [ + "type" => "azureblob", + "linkName" => $this->name, + "dataverse" => $this->dataverseName, + ]; + + if ($this->connectionString != null) { + $json["connectionString"] = $this->connectionString; + } + + if ($this->accountName != null) { + $json["accountName"] = $this->accountName; + } + + if ($this->accountKey != null) { + $json["accountKey"] = $this->accountKey; + } + + if ($this->sharedAccessSignature != null) { + $json["sharedAccessSignature"] = $this->sharedAccessSignature; + } + + if ($this->blobEndpoint != null) { + $json["blobEndpoint"] = $this->blobEndpoint; + } + + if ($this->endpointSuffix != null) { + $json["endpointSuffix"] = $this->endpointSuffix; + } + + return $json; } } diff --git a/Couchbase/Management/ConnectAnalyticsLinkOptions.php b/Couchbase/Management/ConnectAnalyticsLinkOptions.php index 4f6ad0cc..f514c177 100644 --- a/Couchbase/Management/ConnectAnalyticsLinkOptions.php +++ b/Couchbase/Management/ConnectAnalyticsLinkOptions.php @@ -22,11 +22,96 @@ class ConnectAnalyticsLinkOptions { - public function linkName(bstring $linkName): ConnectAnalyticsLinkOptions + private ?int $timeoutMilliseconds = null; + private ?string $dataverseName = null; + private ?string $linkName = null; + private ?bool $force = null; + + /** + * Static helper to keep code more readable + * + * @return ConnectAnalyticsLinkOptions + * @since 4.2.4 + */ + public static function build(): ConnectAnalyticsLinkOptions { + return new ConnectAnalyticsLinkOptions(); } + /** + * Customizes the dataverse to connect to + * + * @param string $dataverseName The name of the dataverse + * + * @return ConnectAnalyticsLinkOptions + * @since 4.2.4 + */ public function dataverseName(string $dataverseName): ConnectAnalyticsLinkOptions { + $this->dataverseName = $dataverseName; + return $this; + } + + /** + * Sets whether to force link creation even if the bucket UUID changed + * + * @param bool $force whether to force link creation + * + * @return ConnectAnalyticsLinkOptions + * @since 4.2.4 + */ + public function force(bool $force): ConnectAnalyticsLinkOptions + { + $this->force = $force; + return $this; + } + + /** + * Sets the name of the link + * + * @param string $linkName the link name + * + * @return ConnectAnalyticsLinkOptions + * @since 4.2.4 + */ + public function linkName(string $linkName): ConnectAnalyticsLinkOptions + { + $this->linkName = $linkName; + return $this; + } + + /** + * Sets the operation timeout in milliseconds. + * + * @param int $milliseconds the operation timeout to apply + * + * @return ConnectAnalyticsLinkOptions + * @since 4.2.4 + */ + public function timeout(int $milliseconds): ConnectAnalyticsLinkOptions + { + $this->timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @param ConnectAnalyticsLinkOptions|null $options + * + * @return array + * @internal + * @since 4.2.4 + */ + public static function export(?ConnectAnalyticsLinkOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + 'dataverseName' => $options->dataverseName, + 'linkName' => $options->linkName, + 'force' => $options->force, + ]; } } diff --git a/Couchbase/Management/CouchbaseAnalyticsEncryptionSettings.php b/Couchbase/Management/CouchbaseAnalyticsEncryptionSettings.php new file mode 100644 index 00000000..07ce4ff8 --- /dev/null +++ b/Couchbase/Management/CouchbaseAnalyticsEncryptionSettings.php @@ -0,0 +1,158 @@ +encryptionLevel = $level; + } + + /** + * Static helper to keep code more readable + * + * @param string $level Accepted values are 'none', 'half', 'full'. + * + * @throws InvalidArgumentException if $level is not an accepted value + * + * @see AnalyticsEncryptionLevel::FULL + * @see AnalyticsEncryptionLevel::NONE + * @see AnalyticsEncryptionLevel::HALF + * + * @since 4.2.4 + */ + public static function build(string $level): CouchbaseAnalyticsEncryptionSettings + { + return new CouchbaseAnalyticsEncryptionSettings($level); + } + + /** + * Provides a certificate to use for connecting when encryption level is set + * to full. Required when encryption level is set to @see AnalyticsEncryptionLevel::FULL + * + * @param string $certificate + * + * @return CouchbaseAnalyticsEncryptionSettings + * @since 4.2.4 + */ + public function setCertificate(string $certificate): CouchbaseAnalyticsEncryptionSettings + { + $this->certificate = $certificate; + return $this; + } + + /** + * Provides a client certificate to use for connecting when encryption level + * is set to full. Cannot be set if a username/password are used. + * + * @param string $clientCertificate + * + * @return CouchbaseAnalyticsEncryptionSettings + * @since 4.2.4 + */ + public function setClientCertificate(string $clientCertificate): CouchbaseAnalyticsEncryptionSettings + { + $this->clientCertificate = $clientCertificate; + return $this; + } + + /** + * Provides a client key to use for connecting when encryption level is set + * to full. Cannot be set if a username/password are used. + * + * @param string $key + * + * @return CouchbaseAnalyticsEncryptionSettings + * @since 4.2.4 + */ + public function setClientKey(string $key): CouchbaseAnalyticsEncryptionSettings + { + $this->clientKey = $key; + return $this; + } + + /** + * Gets the certificate to use for connecting when encryption level is set + * to full. + * + * @return string|null + * @since 4.2.4 + */ + public function certificate(): ?string + { + return $this->certificate; + } + + /** + * Gets the client certificate to use for connecting when encryption level is set + * to full. + * + * @return string|null + * @since 4.2.4 + */ + public function clientCertificate(): ?string + { + return $this->clientCertificate; + } + + /** + * Gets the client key to use for connecting when encryption level is set + * to full + * + * @return string|null + * @since 4.2.4 + */ + public function clientKey(): ?string + { + return $this->clientKey; + } + + /** + * Gets the encryption level + * + * @return string + * @since 4.2.4 + */ + public function encryptionLevel(): string + { + return $this->encryptionLevel; + } +} diff --git a/Couchbase/Management/CouchbaseRemoteAnalyticsLink.php b/Couchbase/Management/CouchbaseRemoteAnalyticsLink.php index 5ea1f9c0..cb15ab45 100644 --- a/Couchbase/Management/CouchbaseRemoteAnalyticsLink.php +++ b/Couchbase/Management/CouchbaseRemoteAnalyticsLink.php @@ -20,39 +20,35 @@ namespace Couchbase\Management; -class CouchbaseRemoteAnalyticsLink implements AnalyticsLink +class CouchbaseRemoteAnalyticsLink extends AnalyticsLink { - /** - * Sets name of the link - * - * @param string $name - * - * @return CouchbaseRemoteAnalyticsLink - */ - public function name(string $name): CouchbaseRemoteAnalyticsLink - { - } + private string $dataverseName; + private string $name; + private string $hostname; - /** - * Sets dataverse this link belongs to - * - * @param string $dataverse - * - * @return CouchbaseRemoteAnalyticsLink - */ - public function dataverse(string $dataverse): CouchbaseRemoteAnalyticsLink + private ?CouchbaseAnalyticsEncryptionSettings $encryption = null; + private ?string $username = null; + private ?string $password = null; + + public function __construct(string $name, string $dataverseName, string $hostname) { + $this->name = $name; + $this->dataverseName = $dataverseName; + $this->hostname = $hostname; } /** - * Sets the hostname of the target Couchbase cluster - * + * Static helper to keep code more readable + * @param string $name + * @param string $dataverseName * @param string $hostname * * @return CouchbaseRemoteAnalyticsLink + * @since 4.2.4 */ - public function hostname(string $hostname): CouchbaseRemoteAnalyticsLink + public static function build(string $name, string $dataverseName, string $hostname): CouchbaseRemoteAnalyticsLink { + return new CouchbaseRemoteAnalyticsLink($name, $dataverseName, $hostname); } /** @@ -63,9 +59,12 @@ public function hostname(string $hostname): CouchbaseRemoteAnalyticsLink * @param string $username * * @return CouchbaseRemoteAnalyticsLink + * @since 4.2.4 */ - public function username(string $username): CouchbaseRemoteAnalyticsLink + public function setUsername(string $username): CouchbaseRemoteAnalyticsLink { + $this->username = $username; + return $this; } /** @@ -76,19 +75,88 @@ public function username(string $username): CouchbaseRemoteAnalyticsLink * @param string $password * * @return CouchbaseRemoteAnalyticsLink + * @since 4.2.4 */ - public function password(string $password): CouchbaseRemoteAnalyticsLink + public function setPassword(string $password): CouchbaseRemoteAnalyticsLink { + $this->password = $password; + return $this; } /** * Sets settings for connection encryption * - * @param EncryptionSettings $settings + * @param CouchbaseAnalyticsEncryptionSettings $settings * * @return CouchbaseRemoteAnalyticsLink + * @since 4.2.4 + */ + public function setEncryption(CouchbaseAnalyticsEncryptionSettings $settings): CouchbaseRemoteAnalyticsLink + { + $this->encryption = $settings; + return $this; + } + + /** + * @inheritdoc */ - public function encryption(EncryptionSettings $settings): CouchbaseRemoteAnalyticsLink + public function name(): string { + return $this->name; + } + + /** + * @inheritdoc + */ + public function dataverseName(): string + { + return $this->dataverseName; + } + + /** + * @inheritdoc + */ + public function linkType(): string + { + return AnalyticsLinkType::COUCHBASE; + } + + /** + * @internal + */ + public function export(): array + { + $json = [ + "type" => "couchbase", + "linkName" => $this->name, + "dataverse" => $this->dataverseName, + "hostname" => $this->hostname, + ]; + + if ($this->username != null) { + $json["username"] = $this->username; + } + if ($this->password != null) { + $json["password"] = $this->password; + } + if ($this->encryption != null) { + $json["encryptionLevel"] = $this->encryption->encryptionLevel(); + + if ($this->encryption->certificate() != null) { + $json["certificate"] = $this->encryption->certificate(); + } + + if ($this->encryption->clientCertificate() != null) { + $json["clientCertificate"] = $this->encryption->clientCertificate(); + } + + if ($this->encryption->clientKey() != null) { + $json["clientKey"] = $this->encryption->clientKey(); + } + } else { + $json["encryptionLevel"] = AnalyticsEncryptionLevel::NONE; + } + + return $json; } } diff --git a/Couchbase/Management/CreateAnalyticsDatasetOptions.php b/Couchbase/Management/CreateAnalyticsDatasetOptions.php index 3fcc7e52..3ea8fca8 100644 --- a/Couchbase/Management/CreateAnalyticsDatasetOptions.php +++ b/Couchbase/Management/CreateAnalyticsDatasetOptions.php @@ -22,15 +22,90 @@ class CreateAnalyticsDatasetOptions { - public function ignoreIfExists(bool $shouldIgnore): CreateAnalyticsDatasetOptions + private ?int $timeoutMilliseconds = null; + private ?bool $ignoreIfExists = null; + private ?string $condition = null; + private ?string $dataverseName = null; + + /** + * Static helper to keep code more readable + * + * @return CreateAnalyticsDatasetOptions + * @since 4.2.4 + */ + public static function build(): CreateAnalyticsDatasetOptions { + return new CreateAnalyticsDatasetOptions(); } + /** + * Sets the where clause to use for creating the dataset + * + * @param string $condition + * + * @return CreateAnalyticsDatasetOptions + * @since 4.2.4 + */ public function condition(string $condition): CreateAnalyticsDatasetOptions { + $this->condition = $condition; + return $this; } + /** + * Customizes the dataverse from which this dataset should be created. + * + * @param string $dataverseName The name of the dataverse + * + * @return CreateAnalyticsDatasetOptions + * @since 4.2.4 + */ public function dataverseName(string $dataverseName): CreateAnalyticsDatasetOptions { + $this->dataverseName = $dataverseName; + return $this; + } + + /** + * @param bool $shouldIgnore + * + * @return CreateAnalyticsDatasetOptions + * @since 4.2.4 + */ + public function ignoreIfExists(bool $shouldIgnore): CreateAnalyticsDatasetOptions + { + $this->ignoreIfExists = $shouldIgnore; + return $this; + } + + /** + * Sets the operation timeout in milliseconds. + * + * @param int $milliseconds the operation timeout to apply + * + * @return CreateAnalyticsDatasetOptions + * @since 4.2.4 + */ + public function timeout(int $milliseconds): CreateAnalyticsDatasetOptions + { + $this->timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?CreateAnalyticsDatasetOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + 'ignoreIfExists' => $options->ignoreIfExists, + 'condition' => $options->condition, + 'dataverseName' => $options->dataverseName, + ]; } } diff --git a/Couchbase/Management/CreateAnalyticsDataverseOptions.php b/Couchbase/Management/CreateAnalyticsDataverseOptions.php index 8b4f1a24..f8fc4e27 100644 --- a/Couchbase/Management/CreateAnalyticsDataverseOptions.php +++ b/Couchbase/Management/CreateAnalyticsDataverseOptions.php @@ -22,7 +22,58 @@ class CreateAnalyticsDataverseOptions { + private ?int $timeoutMilliseconds = null; + private ?bool $ignoreIfExists = null; + + /** + * Static helper to keep code more readable + * + * @return CreateAnalyticsDataverseOptions + * @since 4.2.4 + */ + public static function build(): CreateAnalyticsDataverseOptions + { + return new CreateAnalyticsDataverseOptions(); + } + + /** + * @param bool $shouldIgnore + * + * @return CreateAnalyticsDataverseOptions + * @since 4.2.4 + */ public function ignoreIfExists(bool $shouldIgnore): CreateAnalyticsDataverseOptions { + $this->ignoreIfExists = $shouldIgnore; + return $this; + } + + /** + * Sets the operation timeout in milliseconds. + * + * @param int $milliseconds the operation timeout to apply + * + * @return CreateAnalyticsDataverseOptions + * @since 4.2.4 + */ + public function timeout(int $milliseconds): CreateAnalyticsDataverseOptions + { + $this->timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?CreateAnalyticsDataverseOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + 'ignoreIfExists' => $options->ignoreIfExists, + ]; } } diff --git a/Couchbase/Management/CreateAnalyticsIndexOptions.php b/Couchbase/Management/CreateAnalyticsIndexOptions.php index 241ad5a7..9f1e1bbf 100644 --- a/Couchbase/Management/CreateAnalyticsIndexOptions.php +++ b/Couchbase/Management/CreateAnalyticsIndexOptions.php @@ -22,11 +22,74 @@ class CreateAnalyticsIndexOptions { - public function ignoreIfExists(bool $shouldIgnore): CreateAnalyticsIndexOptions + private ?int $timeoutMilliseconds = null; + private ?bool $ignoreIfExists = null; + private ?string $dataverseName = null; + + /** + * Static helper to keep code more readable + * + * @return CreateAnalyticsIndexOptions + * @since 4.2.4 + */ + public static function build(): CreateAnalyticsIndexOptions { + return new CreateAnalyticsIndexOptions(); } + /** + * Customizes the dataverse from which this index should be created. + * + * @param string $dataverseName The name of the dataverse + * + * @return CreateAnalyticsIndexOptions + * @since 4.2.4 + */ public function dataverseName(string $dataverseName): CreateAnalyticsIndexOptions { + $this->dataverseName = $dataverseName; + return $this; + } + + /** + * @param bool $shouldIgnore + * + * @return CreateAnalyticsIndexOptions + * @since 4.2.4 + */ + public function ignoreIfExists(bool $shouldIgnore): CreateAnalyticsIndexOptions + { + $this->ignoreIfExists = $shouldIgnore; + return $this; + } + + /** + * Sets the operation timeout in milliseconds. + * + * @param int $milliseconds the operation timeout to apply + * + * @return CreateAnalyticsIndexOptions + * @since 4.2.4 + */ + public function timeout(int $milliseconds): CreateAnalyticsIndexOptions + { + $this->timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?CreateAnalyticsIndexOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + 'ignoreIfExists' => $options->ignoreIfExists, + 'dataverseName' => $options->dataverseName, + ]; } } diff --git a/Couchbase/Management/CreateAnalyticsLinkOptions.php b/Couchbase/Management/CreateAnalyticsLinkOptions.php index a62c6521..e968fd65 100644 --- a/Couchbase/Management/CreateAnalyticsLinkOptions.php +++ b/Couchbase/Management/CreateAnalyticsLinkOptions.php @@ -22,7 +22,44 @@ class CreateAnalyticsLinkOptions { - public function timeout(int $arg): CreateAnalyticsLinkOptions + private ?int $timeoutMilliseconds = null; + + /** + * Static helper to keep code more readable + * + * @return CreateAnalyticsLinkOptions + * @since 4.2.4 + */ + public static function build(): CreateAnalyticsLinkOptions + { + return new CreateAnalyticsLinkOptions(); + } + + /** + * Sets the operation timeout in milliseconds. + * + * @param int $milliseconds the operation timeout to apply + * + * @return CreateAnalyticsLinkOptions + * @since 4.2.4 + */ + public function timeout(int $milliseconds): CreateAnalyticsLinkOptions { + $this->timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?CreateAnalyticsLinkOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + ]; } } diff --git a/Couchbase/Management/DisconnectAnalyticsLinkOptions.php b/Couchbase/Management/DisconnectAnalyticsLinkOptions.php index a6d776c4..f2a00a6a 100644 --- a/Couchbase/Management/DisconnectAnalyticsLinkOptions.php +++ b/Couchbase/Management/DisconnectAnalyticsLinkOptions.php @@ -22,11 +22,76 @@ class DisconnectAnalyticsLinkOptions { - public function linkName(bstring $linkName): DisconnectAnalyticsLinkOptions + private ?int $timeoutMilliseconds = null; + private ?string $dataverseName = null; + private ?string $linkName = null; + + /** + * Static helper to keep code more readable + * + * @return DisconnectAnalyticsLinkOptions + * @since 4.2.4 + */ + public static function build(): DisconnectAnalyticsLinkOptions { + return new DisconnectAnalyticsLinkOptions(); } + /** + * Customizes the dataverse to disconnect from + * + * @param string $dataverseName The name of the dataverse + * + * @return DisconnectAnalyticsLinkOptions + * @since 4.2.4 + */ public function dataverseName(string $dataverseName): DisconnectAnalyticsLinkOptions { + $this->dataverseName = $dataverseName; + return $this; + } + + /** + * Sets the name of the link + * + * @param string $linkName the link name + * + * @return DisconnectAnalyticsLinkOptions + * @since 4.2.4 + */ + public function linkName(string $linkName): DisconnectAnalyticsLinkOptions + { + $this->linkName = $linkName; + return $this; + } + + /** + * Sets the operation timeout in milliseconds. + * + * @param int $milliseconds the operation timeout to apply + * + * @return DisconnectAnalyticsLinkOptions + * @since 4.2.4 + */ + public function timeout(int $milliseconds): DisconnectAnalyticsLinkOptions + { + $this->timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?DisconnectAnalyticsLinkOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + 'dataverseName' => $options->dataverseName, + 'linkName' => $options->linkName, + ]; } } diff --git a/Couchbase/Management/DropAnalyticsDatasetOptions.php b/Couchbase/Management/DropAnalyticsDatasetOptions.php index 5439590c..9bab8f95 100644 --- a/Couchbase/Management/DropAnalyticsDatasetOptions.php +++ b/Couchbase/Management/DropAnalyticsDatasetOptions.php @@ -22,11 +22,74 @@ class DropAnalyticsDatasetOptions { - public function ignoreIfNotExists(bool $shouldIgnore): DropAnalyticsDatasetOptions + private ?int $timeoutMilliseconds = null; + private ?bool $ignoreIfDoesNotExist = null; + private ?string $dataverseName = null; + + /** + * Static helper to keep code more readable + * + * @return DropAnalyticsDatasetOptions + * @since 4.2.4 + */ + public static function build(): DropAnalyticsDatasetOptions { + return new DropAnalyticsDatasetOptions(); } + /** + * Customizes the dataverse from which this dataset should be dropped. + * + * @param string $dataverseName The name of the dataverse + * + * @return DropAnalyticsDatasetOptions + * @since 4.2.4 + */ public function dataverseName(string $dataverseName): DropAnalyticsDatasetOptions { + $this->dataverseName = $dataverseName; + return $this; + } + + /** + * @param bool $shouldIgnore + * + * @return DropAnalyticsDatasetOptions + * @since 4.2.4 + */ + public function ignoreIfDoesNotExist(bool $shouldIgnore): DropAnalyticsDatasetOptions + { + $this->ignoreIfDoesNotExist = $shouldIgnore; + return $this; + } + + /** + * Sets the operation timeout in milliseconds. + * + * @param int $milliseconds the operation timeout to apply + * + * @return DropAnalyticsDatasetOptions + * @since 4.2.4 + */ + public function timeout(int $milliseconds): DropAnalyticsDatasetOptions + { + $this->timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?DropAnalyticsDatasetOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + 'ignoreIfDoesNotExist' => $options->ignoreIfDoesNotExist, + 'dataverseName' => $options->dataverseName, + ]; } } diff --git a/Couchbase/Management/DropAnalyticsDataverseOptions.php b/Couchbase/Management/DropAnalyticsDataverseOptions.php index 56ce90e5..394de40c 100644 --- a/Couchbase/Management/DropAnalyticsDataverseOptions.php +++ b/Couchbase/Management/DropAnalyticsDataverseOptions.php @@ -22,7 +22,58 @@ class DropAnalyticsDataverseOptions { - public function ignoreIfNotExists(bool $shouldIgnore): DropAnalyticsDataverseOptions + private ?int $timeoutMilliseconds = null; + private ?bool $ignoreIfDoesNotExist = null; + + /** + * Static helper to keep code more readable + * + * @return DropAnalyticsDataverseOptions + * @since 4.2.4 + */ + public static function build(): DropAnalyticsDataverseOptions + { + return new DropAnalyticsDataverseOptions(); + } + + /** + * @param bool $shouldIgnore + * + * @return DropAnalyticsDataverseOptions + * @since 4.2.4 + */ + public function ignoreIfDoesNotExist(bool $shouldIgnore): DropAnalyticsDataverseOptions { + $this->ignoreIfDoesNotExist = $shouldIgnore; + return $this; + } + + /** + * Sets the operation timeout in milliseconds. + * + * @param int $milliseconds the operation timeout to apply + * + * @return DropAnalyticsDataverseOptions + * @since 4.2.4 + */ + public function timeout(int $milliseconds): DropAnalyticsDataverseOptions + { + $this->timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?DropAnalyticsDataverseOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + 'ignoreIfDoesNotExist' => $options->ignoreIfDoesNotExist, + ]; } } diff --git a/Couchbase/Management/DropAnalyticsIndexOptions.php b/Couchbase/Management/DropAnalyticsIndexOptions.php index ff3b834e..f1676e0c 100644 --- a/Couchbase/Management/DropAnalyticsIndexOptions.php +++ b/Couchbase/Management/DropAnalyticsIndexOptions.php @@ -22,11 +22,74 @@ class DropAnalyticsIndexOptions { - public function ignoreIfNotExists(bool $shouldIgnore): DropAnalyticsIndexOptions + private ?int $timeoutMilliseconds = null; + private ?bool $ignoreIfDoesNotExist = null; + private ?string $dataverseName = null; + + /** + * Static helper to keep code more readable + * + * @return DropAnalyticsIndexOptions + * @since 4.2.4 + */ + public static function build(): DropAnalyticsIndexOptions { + return new DropAnalyticsIndexOptions(); } + /** + * Customizes the dataverse from which this index should be created. + * + * @param string $dataverseName The name of the dataverse + * + * @return DropAnalyticsIndexOptions + * @since 4.2.4 + */ public function dataverseName(string $dataverseName): DropAnalyticsIndexOptions { + $this->dataverseName = $dataverseName; + return $this; + } + + /** + * @param bool $shouldIgnore + * + * @return DropAnalyticsIndexOptions + * @since 4.2.4 + */ + public function ignoreIfDoesNotExist(bool $shouldIgnore): DropAnalyticsIndexOptions + { + $this->ignoreIfDoesNotExist = $shouldIgnore; + return $this; + } + + /** + * Sets the operation timeout in milliseconds. + * + * @param int $milliseconds the operation timeout to apply + * + * @return DropAnalyticsIndexOptions + * @since 4.2.4 + */ + public function timeout(int $milliseconds): DropAnalyticsIndexOptions + { + $this->timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?DropAnalyticsIndexOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + 'ignoreIfDoesNotExist' => $options->ignoreIfDoesNotExist, + 'dataverseName' => $options->dataverseName, + ]; } } diff --git a/Couchbase/Management/DropAnalyticsLinkOptions.php b/Couchbase/Management/DropAnalyticsLinkOptions.php index 333ff837..118fbebd 100644 --- a/Couchbase/Management/DropAnalyticsLinkOptions.php +++ b/Couchbase/Management/DropAnalyticsLinkOptions.php @@ -22,7 +22,44 @@ class DropAnalyticsLinkOptions { - public function timeout(int $arg): DropAnalyticsLinkOptions + private ?int $timeoutMilliseconds = null; + + /** + * Static helper to keep code more readable + * + * @return DropAnalyticsLinkOptions + * @since 4.2.4 + */ + public static function build(): DropAnalyticsLinkOptions + { + return new DropAnalyticsLinkOptions(); + } + + /** + * Sets the operation timeout in milliseconds. + * + * @param int $milliseconds the operation timeout to apply + * + * @return DropAnalyticsLinkOptions + * @since 4.2.4 + */ + public function timeout(int $milliseconds): DropAnalyticsLinkOptions { + $this->timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?DropAnalyticsLinkOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + ]; } } diff --git a/Couchbase/Management/EncryptionSettings.php b/Couchbase/Management/EncryptionSettings.php deleted file mode 100644 index 04a5cafc..00000000 --- a/Couchbase/Management/EncryptionSettings.php +++ /dev/null @@ -1,51 +0,0 @@ -timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?GetAllAnalyticsDatasetsOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + ]; + } +} diff --git a/Couchbase/Management/GetAllAnalyticsIndexesOptions.php b/Couchbase/Management/GetAllAnalyticsIndexesOptions.php new file mode 100644 index 00000000..b6df7fef --- /dev/null +++ b/Couchbase/Management/GetAllAnalyticsIndexesOptions.php @@ -0,0 +1,65 @@ +timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?GetAllAnalyticsIndexesOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + ]; + } +} diff --git a/Couchbase/Management/GetAnalyticsLinksOptions.php b/Couchbase/Management/GetAnalyticsLinksOptions.php index c46989fd..77fde629 100644 --- a/Couchbase/Management/GetAnalyticsLinksOptions.php +++ b/Couchbase/Management/GetAnalyticsLinksOptions.php @@ -20,36 +20,113 @@ namespace Couchbase\Management; +use Couchbase\Exception\InvalidArgumentException; + class GetAnalyticsLinksOptions { - public function timeout(int $arg): DropAnalyticsLinkOptions + private ?int $timeoutMilliseconds = null; + private ?string $dataverseName = null; + private ?string $name = null; + private ?string $linkType = null; + + /** + * Static helper to keep code more readable + * + * @return GetAnalyticsLinksOptions + * @since 4.2.4 + */ + public static function build(): GetAnalyticsLinksOptions { + return new GetAnalyticsLinksOptions(); } /** - * @param string $tupe restricts the results to the given link type. + * Sets the operation timeout in milliseconds. + * + * @param int $milliseconds the operation timeout to apply + * + * @return GetAnalyticsLinksOptions + * @since 4.2.4 + */ + public function timeout(int $milliseconds): GetAnalyticsLinksOptions + { + $this->timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * Customizes the dataverse to restrict links to + * + * @param string $dataverseName The name of the dataverse + * + * @return GetAnalyticsLinksOptions + * @since 4.2.4 + */ + public function dataverseName(string $dataverseName): GetAnalyticsLinksOptions + { + $this->dataverseName = $dataverseName; + return $this; + } + + /** + * The type of links to restrict returned links to. + * + * @param string $type the link type, must be value one of 'couchbase', 's3', or 'azureblob' * - * @see AnalyticsLinkType::COUCHBASE - * @see AnalyticsLinkType::S3 * @see AnalyticsLinkType::AZURE_BLOB + * @see AnalyticsLinkType::S3 + * @see AnalyticsLinkType::COUCHBASE + * + * @throws InvalidArgumentException + * + * @return GetAnalyticsLinksOptions + * @since 4.2.4 */ - public function linkType(string $type): DropAnalyticsLinkOptions + public function linkType(string $type): GetAnalyticsLinksOptions { + if ( + $type != AnalyticsLinkType::COUCHBASE && + $type != AnalyticsLinkType::AZURE_BLOB && + $type != AnalyticsLinkType::S3 + ) { + throw new InvalidArgumentException("linkType value must be one of 'couchbase', 's3', or 'azureblob'"); + } + $this->linkType = $type; + return $this; } /** - * @param string $dataverse restricts the results to a given dataverse, can be given in the form of "namepart" or - * "namepart1/namepart2". + * Sets the name of the link to fetch. If set, then dataverse must also be set. + * + * @param string $name The name of the link + * + * @return GetAnalyticsLinksOptions + * @since 4.2.4 */ - public function dataverse(string $dataverse): DropAnalyticsLinkOptions + public function name(string $name): GetAnalyticsLinksOptions { + $this->name = $name; + return $this; } /** - * @param string $name restricts the results to the link with the specified name. If set then dataverse must also - * be set. + * @internal */ - public function name(string $name): DropAnalyticsLinkOptions + public static function export(?GetAnalyticsLinksOptions $options): array { + if ($options == null) { + return []; + } + + if (isset($options->name) && !isset($options->dataverseName)) { + throw new InvalidArgumentException("If the link name is set, the dataverseName must also be set."); + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + 'dataverseName' => $options->dataverseName, + 'name' => $options->name, + 'linkType' => $options->linkType + ]; } } diff --git a/Couchbase/Management/GetAnalyticsPendingMutationsOptions.php b/Couchbase/Management/GetAnalyticsPendingMutationsOptions.php new file mode 100644 index 00000000..fcb4b051 --- /dev/null +++ b/Couchbase/Management/GetAnalyticsPendingMutationsOptions.php @@ -0,0 +1,79 @@ +timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?GetAnalyticsPendingMutationsOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + ]; + } + + /** + * @internal + */ + public static function import(array $pendingMutations): array + { + $finalArray = []; + foreach ($pendingMutations as $mutation) { + $splitKey = explode(".", $mutation["key"]); + $dataverseName = $splitKey[0]; + $finalArray[$dataverseName][$splitKey[1]] = $mutation["count"]; + } + return $finalArray; + } +} diff --git a/Couchbase/Management/ReplaceAnalyticsLinkOptions.php b/Couchbase/Management/ReplaceAnalyticsLinkOptions.php index 1a4bbb69..644e81d4 100644 --- a/Couchbase/Management/ReplaceAnalyticsLinkOptions.php +++ b/Couchbase/Management/ReplaceAnalyticsLinkOptions.php @@ -22,7 +22,44 @@ class ReplaceAnalyticsLinkOptions { - public function timeout(int $arg): ReplaceAnalyticsLinkOptions + private ?int $timeoutMilliseconds = null; + + /** + * Static helper to keep code more readable + * + * @return ReplaceAnalyticsLinkOptions + * @since 4.2.4 + */ + public static function build(): ReplaceAnalyticsLinkOptions + { + return new ReplaceAnalyticsLinkOptions(); + } + + /** + * Sets the operation timeout in milliseconds. + * + * @param int $milliseconds the operation timeout to apply + * + * @return ReplaceAnalyticsLinkOptions + * @since 4.2.4 + */ + public function timeout(int $milliseconds): ReplaceAnalyticsLinkOptions { + $this->timeoutMilliseconds = $milliseconds; + return $this; + } + + /** + * @internal + */ + public static function export(?ReplaceAnalyticsLinkOptions $options): array + { + if ($options == null) { + return []; + } + + return [ + 'timeoutMilliseconds' => $options->timeoutMilliseconds, + ]; } } diff --git a/Couchbase/Management/S3ExternalAnalyticsLink.php b/Couchbase/Management/S3ExternalAnalyticsLink.php index c3ae71a7..448d87f3 100644 --- a/Couchbase/Management/S3ExternalAnalyticsLink.php +++ b/Couchbase/Management/S3ExternalAnalyticsLink.php @@ -20,82 +20,135 @@ namespace Couchbase\Management; -class S3ExternalAnalyticsLink implements AnalyticsLink +class S3ExternalAnalyticsLink extends AnalyticsLink { + private string $dataverseName; + private string $name; + private string $accessKeyID; + private string $secretAccessKey; + private string $region; + + private ?string $sessionToken = null; + + private ?string $serviceEndpoint = null; + + public function __construct( + string $name, + string $dataverseName, + string $accessKeyID, + string $region, + string $secretAccessKey, + ) + { + $this->name = $name; + $this->dataverseName = $dataverseName; + $this->accessKeyID = $accessKeyID; + $this->region = $region; + $this->secretAccessKey = $secretAccessKey; + } + /** - * Sets name of the link - * + * Static helper to keep code more readable + * @param string $name + * @param string $dataverseName + * @param string $accessKeyID + * @param string $region + * @param string $secretAccessKey * * @return S3ExternalAnalyticsLink + * @since 4.2.4 */ - public function name(string $name): S3ExternalAnalyticsLink + public static function build( + string $name, + string $dataverseName, + string $accessKeyID, + string $region, + string $secretAccessKey, + ): S3ExternalAnalyticsLink { + return new S3ExternalAnalyticsLink( + $name, + $dataverseName, + $accessKeyID, + $region, + $secretAccessKey, + ); } /** - * Sets dataverse this link belongs to + * Sets AWS S3 service endpoint * - * @param string $dataverse + * @param string $serviceEndpoint * * @return S3ExternalAnalyticsLink + * @since 4.2.4 */ - public function dataverse(string $dataverse): S3ExternalAnalyticsLink + public function setServiceEndpoint(string $serviceEndpoint): S3ExternalAnalyticsLink { + $this->serviceEndpoint = $serviceEndpoint; + return $this; } /** - * Sets AWS S3 access key ID + * Sets the session token * - * @param string $accessKeyId + * @param string $sessionToken * * @return S3ExternalAnalyticsLink + * @since 4.2.4 */ - public function accessKeyId(string $accessKeyId): S3ExternalAnalyticsLink + public function setSessionToken(string $sessionToken): S3ExternalAnalyticsLink { + $this->sessionToken = $sessionToken; + return $this; } /** - * Sets AWS S3 secret key - * - * @param string $secretAccessKey - * - * @return S3ExternalAnalyticsLink + * @inheritdoc */ - public function secretAccessKey(string $secretAccessKey): S3ExternalAnalyticsLink + public function name(): string { + return $this->name; } /** - * Sets AWS S3 region - * - * @param string $region - * - * @return S3ExternalAnalyticsLink + * @inheritdoc */ - public function region(string $region): S3ExternalAnalyticsLink + public function dataverseName(): string { + return $this->dataverseName; } /** - * Sets AWS S3 token if temporary credentials are provided. Only available in 7.0+ - * - * @param string $sessionToken - * - * @return S3ExternalAnalyticsLink + * @inheritdoc */ - public function sessionToken(string $sessionToken): S3ExternalAnalyticsLink + public function linkType(): string { + return AnalyticsLinkType::S3; } /** - * Sets AWS S3 service endpoint - * - * @param string $serviceEndpoint - * - * @return S3ExternalAnalyticsLink + * @internal */ - public function serviceEndpoint(string $serviceEndpoint): S3ExternalAnalyticsLink + public function export(): array { + $json = [ + "type" => "s3", + "linkName" => $this->name, + "dataverse" => $this->dataverseName, + "accessKeyId" => $this->accessKeyID, + "secretAccessKey" => $this->secretAccessKey, + "region" => $this->region + ]; + + if ($this->sessionToken != null) { + $json["sessionToken"] = $this->sessionToken; + } + if ($this->serviceEndpoint != null) { + $json["serviceEndpoint"] = $this->serviceEndpoint; + } + + return $json; } } diff --git a/src/php_couchbase.cxx b/src/php_couchbase.cxx index d0f2a9ee..eebc3717 100644 --- a/src/php_couchbase.cxx +++ b/src/php_couchbase.cxx @@ -3331,6 +3331,384 @@ PHP_FUNCTION(collectionQueryIndexBuildDeferred) } } +PHP_FUNCTION(analyticsDataverseCreate) +{ + zval* connection = nullptr; + zend_string* dataverse_name = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_RESOURCE(connection) + Z_PARAM_STR(dataverse_name) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_create_dataverse(return_value, dataverse_name, options); e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsDataverseDrop) +{ + zval* connection = nullptr; + zend_string* dataverse_name = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_RESOURCE(connection) + Z_PARAM_STR(dataverse_name) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_drop_dataverse(return_value, dataverse_name, options); e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsDatasetCreate) +{ + zval* connection = nullptr; + zend_string* dataset_name = nullptr; + zend_string* bucket_name = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(3, 4) + Z_PARAM_RESOURCE(connection) + Z_PARAM_STR(dataset_name) + Z_PARAM_STR(bucket_name) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_create_dataset(return_value, dataset_name, bucket_name, options); + e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsDatasetDrop) +{ + zval* connection = nullptr; + zend_string* dataset_name = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_RESOURCE(connection) + Z_PARAM_STR(dataset_name) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_drop_dataset(return_value, dataset_name, options); e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsDatasetGetAll) +{ + zval* connection = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_RESOURCE(connection) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_get_all_datasets(return_value, options); e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsIndexCreate) +{ + zval* connection = nullptr; + zend_string* dataset_name = nullptr; + zend_string* index_name = nullptr; + zval* fields = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(4, 5) + Z_PARAM_RESOURCE(connection) + Z_PARAM_STR(dataset_name) + Z_PARAM_STR(index_name) + Z_PARAM_ARRAY(fields) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = + handle->analytics_create_index(return_value, dataset_name, index_name, fields, options); + e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsIndexDrop) +{ + zval* connection = nullptr; + zend_string* dataset_name = nullptr; + zend_string* index_name = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(3, 4) + Z_PARAM_RESOURCE(connection) + Z_PARAM_STR(dataset_name) + Z_PARAM_STR(index_name) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_drop_index(return_value, dataset_name, index_name, options); + e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsIndexGetAll) +{ + zval* connection = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_RESOURCE(connection) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_get_all_indexes(return_value, options); e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsLinkConnect) +{ + zval* connection = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_RESOURCE(connection) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_connect_link(return_value, options); e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsLinkDisconnect) +{ + zval* connection = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_RESOURCE(connection) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_disconnect_link(return_value, options); e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsPendingMutationsGet) +{ + zval* connection = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_RESOURCE(connection) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_get_pending_mutations(return_value, options); e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsLinkCreate) +{ + zval* connection = nullptr; + zval* analytics_link = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_RESOURCE(connection) + Z_PARAM_ARRAY(analytics_link) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_create_link(return_value, analytics_link, options); e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsLinkReplace) +{ + zval* connection = nullptr; + zval* analytics_link = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(2, 3) + Z_PARAM_RESOURCE(connection) + Z_PARAM_ARRAY(analytics_link) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_replace_link(return_value, analytics_link, options); e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsLinkDrop) +{ + zval* connection = nullptr; + zend_string* link_name = nullptr; + zend_string* dataverse_name = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(3, 4) + Z_PARAM_RESOURCE(connection) + Z_PARAM_STR(link_name) + Z_PARAM_STR(dataverse_name) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_drop_link(return_value, link_name, dataverse_name, options); + e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + +PHP_FUNCTION(analyticsLinkGetAll) +{ + zval* connection = nullptr; + zval* options = nullptr; + + ZEND_PARSE_PARAMETERS_START(1, 2) + Z_PARAM_RESOURCE(connection) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY_OR_NULL(options) + ZEND_PARSE_PARAMETERS_END(); + + logger_flusher guard; + + auto* handle = fetch_couchbase_connection_from_resource(connection); + if (handle == nullptr) { + RETURN_THROWS(); + } + if (auto e = handle->analytics_get_all_links(return_value, options); e.ec) { + couchbase_throw_exception(e); + RETURN_THROWS(); + } +} + static PHP_MINFO_FUNCTION(couchbase) { php_info_print_table_start(); @@ -4131,6 +4509,95 @@ ZEND_ARG_TYPE_INFO(0, collectionName, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsDataverseCreate, 0, 0, 2) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, dataverseName, IS_STRING, 0) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsDataverseDrop, 0, 0, 2) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, dataverseName, IS_STRING, 0) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsDatasetCreate, 0, 0, 3) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, datasetName, IS_STRING, 0) +ZEND_ARG_TYPE_INFO(0, bucketName, IS_STRING, 0) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsDatasetDrop, 0, 0, 2) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, datasetName, IS_STRING, 0) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsDatasetGetAll, 0, 0, 1) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsIndexCreate, 0, 0, 4) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, datasetName, IS_STRING, 0) +ZEND_ARG_TYPE_INFO(0, indexName, IS_STRING, 0) +ZEND_ARG_TYPE_INFO(0, fields, IS_ARRAY, 0) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsIndexDrop, 0, 0, 3) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, datasetName, IS_STRING, 0) +ZEND_ARG_TYPE_INFO(0, indexName, IS_STRING, 0) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsIndexGetAll, 0, 0, 1) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsLinkConnect, 0, 0, 1) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsLinkDisconnect, 0, 0, 1) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsPendingMutationsGet, 0, 0, 1) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsLinkCreate, 0, 0, 2) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, analyticsLink, IS_ARRAY, 0) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsLinkReplace, 0, 0, 2) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, analyticsLink, IS_ARRAY, 0) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsLinkDrop, 0, 0, 3) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, linkName, IS_STRING, 0) +ZEND_ARG_TYPE_INFO(0, dataverseName, IS_STRING, 0) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(ai_CouchbaseExtension_analyticsLinkGetAll, 0, 0, 1) +ZEND_ARG_INFO(0, connection) +ZEND_ARG_TYPE_INFO(0, options, IS_ARRAY, 1) +ZEND_END_ARG_INFO() + // clang-format off static zend_function_entry couchbase_functions[] = { ZEND_NS_FE("Couchbase\\Extension", notifyFork, ai_CouchbaseExtension_notifyFork) @@ -4244,6 +4711,22 @@ static zend_function_entry couchbase_functions[] = { ZEND_NS_FE("Couchbase\\Extension", collectionQueryIndexDrop, ai_CouchbaseExtension_collectionQueryIndexDrop) ZEND_NS_FE("Couchbase\\Extension", collectionQueryIndexDropPrimary, ai_CouchbaseExtension_collectionQueryIndexDropPrimary) ZEND_NS_FE("Couchbase\\Extension", collectionQueryIndexBuildDeferred, ai_CouchbaseExtension_collectionQueryIndexBuildDeferred) + + ZEND_NS_FE("Couchbase\\Extension", analyticsDataverseCreate, ai_CouchbaseExtension_analyticsDataverseCreate) + ZEND_NS_FE("Couchbase\\Extension", analyticsDataverseDrop, ai_CouchbaseExtension_analyticsDataverseDrop) + ZEND_NS_FE("Couchbase\\Extension", analyticsDatasetCreate, ai_CouchbaseExtension_analyticsDatasetCreate) + ZEND_NS_FE("Couchbase\\Extension", analyticsDatasetDrop, ai_CouchbaseExtension_analyticsDatasetDrop) + ZEND_NS_FE("Couchbase\\Extension", analyticsDatasetGetAll, ai_CouchbaseExtension_analyticsDatasetGetAll) + ZEND_NS_FE("Couchbase\\Extension", analyticsIndexCreate, ai_CouchbaseExtension_analyticsIndexCreate) + ZEND_NS_FE("Couchbase\\Extension", analyticsIndexDrop, ai_CouchbaseExtension_analyticsIndexDrop) + ZEND_NS_FE("Couchbase\\Extension", analyticsIndexGetAll, ai_CouchbaseExtension_analyticsIndexGetAll) + ZEND_NS_FE("Couchbase\\Extension", analyticsLinkConnect, ai_CouchbaseExtension_analyticsLinkConnect) + ZEND_NS_FE("Couchbase\\Extension", analyticsLinkDisconnect, ai_CouchbaseExtension_analyticsLinkDisconnect) + ZEND_NS_FE("Couchbase\\Extension", analyticsPendingMutationsGet, ai_CouchbaseExtension_analyticsPendingMutationsGet) + ZEND_NS_FE("Couchbase\\Extension", analyticsLinkCreate, ai_CouchbaseExtension_analyticsLinkCreate) + ZEND_NS_FE("Couchbase\\Extension", analyticsLinkReplace, ai_CouchbaseExtension_analyticsLinkReplace) + ZEND_NS_FE("Couchbase\\Extension", analyticsLinkDrop, ai_CouchbaseExtension_analyticsLinkDrop) + ZEND_NS_FE("Couchbase\\Extension", analyticsLinkGetAll, ai_CouchbaseExtension_analyticsLinkGetAll) PHP_FE_END }; diff --git a/src/wrapper/connection_handle.cxx b/src/wrapper/connection_handle.cxx index dfc0929d..40943054 100644 --- a/src/wrapper/connection_handle.cxx +++ b/src/wrapper/connection_handle.cxx @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -5001,6 +5002,804 @@ connection_handle::collection_query_index_build_deferred(zval* return_value, return {}; } +COUCHBASE_API +core_error_info +connection_handle::analytics_create_dataverse(zval* return_value, + const zend_string* dataverse_name, + const zval* options) +{ + + couchbase::core::operations::management::analytics_dataverse_create_request request{}; + + request.dataverse_name = cb_string_new(dataverse_name); + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_assign_boolean(request.ignore_if_exists, options, "ignoreIfExists"); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to create dataverse" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format( + "Unable to create dataverse ({}: {})", first_error.code, first_error.message) }; + } + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_drop_dataverse(zval* return_value, + const zend_string* dataverse_name, + const zval* options) +{ + couchbase::core::operations::management::analytics_dataverse_drop_request request{}; + + request.dataverse_name = cb_string_new(dataverse_name); + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_assign_boolean(request.ignore_if_does_not_exist, options, "ignoreIfDoesNotExist"); + e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to drop dataverse" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format( + "Unable to drop dataverse ({}: {})", first_error.code, first_error.message) }; + } + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_create_dataset(zval* return_value, + const zend_string* dataset_name, + const zend_string* bucket_name, + const zval* options) +{ + couchbase::core::operations::management::analytics_dataset_create_request request{}; + + request.dataset_name = cb_string_new(dataset_name); + request.bucket_name = cb_string_new(bucket_name); + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_assign_boolean(request.ignore_if_exists, options, "ignoreIfExists"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(request.condition, options, "condition"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(request.dataverse_name, options, "dataverseName"); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to create dataset" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format( + "Unable to create dataset ({}: {})", first_error.code, first_error.message) }; + } + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_drop_dataset(zval* return_value, + const zend_string* dataset_name, + const zval* options) +{ + couchbase::core::operations::management::analytics_dataset_drop_request request{}; + + request.dataset_name = cb_string_new(dataset_name); + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_assign_boolean(request.ignore_if_does_not_exist, options, "ignoreIfDoesNotExist"); + e.ec) { + return e; + } + + if (auto e = cb_assign_string(request.dataverse_name, options, "dataverseName"); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to drop dataset" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format( + "Unable to drop dataset ({}: {})", first_error.code, first_error.message) }; + } + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_get_all_datasets(zval* return_value, const zval* options) +{ + couchbase::core::operations::management::analytics_dataset_get_all_request request{}; + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to fetch all datasets" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format( + "Unable to fetch all datasets ({}: {})", first_error.code, first_error.message) }; + } + } + + array_init(return_value); + for (const auto& dataset : resp.datasets) { + zval data; + array_init(&data); + add_assoc_string(&data, "name", dataset.name.c_str()); + add_assoc_string(&data, "dataverseName", dataset.dataverse_name.c_str()); + add_assoc_string(&data, "linkName", dataset.link_name.c_str()); + add_assoc_string(&data, "bucketName", dataset.bucket_name.c_str()); + add_next_index_zval(return_value, &data); + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_create_index(zval* return_value, + const zend_string* dataset_name, + const zend_string* index_name, + const zval* fields, + const zval* options) +{ + couchbase::core::operations::management::analytics_index_create_request request{}; + + request.dataset_name = cb_string_new(dataset_name); + request.index_name = cb_string_new(index_name); + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_assign_string(request.dataverse_name, options, "dataverseName"); e.ec) { + return e; + } + + if (auto e = cb_assign_boolean(request.ignore_if_exists, options, "ignoreIfExists"); e.ec) { + return e; + } + + if (fields != nullptr && Z_TYPE_P(fields) == IS_ARRAY) { + std::map req_fields{}; + const zend_string* key = nullptr; + const zval* item = nullptr; + + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(fields), key, item) + { + req_fields[cb_string_new(key)] = std::string({ Z_STRVAL_P(item), Z_STRLEN_P(item) }); + } + ZEND_HASH_FOREACH_END(); + + request.fields = req_fields; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to create analytics index" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to create analytics index ({}: {})", + first_error.code, + first_error.message) }; + } + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_drop_index(zval* return_value, + const zend_string* dataset_name, + const zend_string* index_name, + const zval* options) +{ + couchbase::core::operations::management::analytics_index_drop_request request{}; + + request.dataset_name = cb_string_new(dataset_name); + request.index_name = cb_string_new(index_name); + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_assign_boolean(request.ignore_if_does_not_exist, options, "ignoreIfDoesNotExist"); + e.ec) { + return e; + } + + if (auto e = cb_assign_string(request.dataverse_name, options, "dataverseName"); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to drop analytics index" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to drop analytics index ({}: {})", + first_error.code, + first_error.message) }; + } + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_get_all_indexes(zval* return_value, const zval* options) +{ + couchbase::core::operations::management::analytics_index_get_all_request request{}; + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to fetch all analytics indexes" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("Unable to fetch all analytics indexes ({}: {})", + first_error.code, + first_error.message) }; + } + } + + array_init(return_value); + for (const auto& idx : resp.indexes) { + zval index; + array_init(&index); + add_assoc_string(&index, "name", idx.name.c_str()); + add_assoc_string(&index, "dataverseName", idx.dataverse_name.c_str()); + add_assoc_string(&index, "datasetName", idx.dataset_name.c_str()); + add_assoc_bool(&index, "isPrimary", idx.is_primary); + add_next_index_zval(return_value, &index); + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_connect_link(zval* return_value, const zval* options) +{ + couchbase::core::operations::management::analytics_link_connect_request request{}; + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_assign_string(request.dataverse_name, options, "dataverseName"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(request.link_name, options, "linkName"); e.ec) { + return e; + } + + if (auto e = cb_assign_boolean(request.force, options, "force"); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to connect analytics link" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to connect analytics link ({}: {})", + first_error.code, + first_error.message) }; + } + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_disconnect_link(zval* return_value, const zval* options) +{ + couchbase::core::operations::management::analytics_link_disconnect_request request{}; + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_assign_string(request.dataverse_name, options, "dataverseName"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(request.link_name, options, "linkName"); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to disconnect analytics link" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to disconnect analytics link({}: {})", + first_error.code, + first_error.message) }; + } + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_get_pending_mutations(zval* return_value, const zval* options) +{ + couchbase::core::operations::management::analytics_get_pending_mutations_request request{}; + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, + ERROR_LOCATION, + "unable to get pending mutations for the analytics service" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to get pending mutations for the analytics service ({}: {})", + first_error.code, + first_error.message) }; + } + } + + array_init(return_value); + for (const auto& [key, mutation_count] : resp.stats) { + zval mut; + array_init(&mut); + add_assoc_string(&mut, "key", key.c_str()); + add_assoc_long(&mut, "count", mutation_count); + add_next_index_zval(return_value, &mut); + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_create_link(zval* return_value, + const zval* analytics_link, + const zval* options) +{ + auto [err, type] = cb_get_string(analytics_link, "type"); + + if (err.ec) { + return err; + } + if (!type.has_value()) { + return { errc::common::invalid_argument, + ERROR_LOCATION, + "Did not receive an analytics link type" }; + } + + if (type.value() == "couchbase") { + couchbase::core::operations::management::analytics_link_create_request< + couchbase::core::management::analytics::couchbase_remote_link> + request{}; + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_fill_analytics_link(request.link, analytics_link); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to create couchbase_remote link" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to create couchbase_remote link ({}: {})", + first_error.code, + first_error.message) }; + } + } + } else if (type.value() == "azureblob") { + couchbase::core::operations::management::analytics_link_create_request< + couchbase::core::management::analytics::azure_blob_external_link> + request{}; + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_fill_analytics_link(request.link, analytics_link); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to create azure_blob_external link" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to create azure_blob_external link ({}: {})", + first_error.code, + first_error.message) }; + } + } + } else if (type.value() == "s3") { + couchbase::core::operations::management::analytics_link_create_request< + couchbase::core::management::analytics::s3_external_link> + request{}; + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_fill_analytics_link(request.link, analytics_link); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to create s3_external link" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to create s3_external link ({}: {})", + first_error.code, + first_error.message) }; + } + } + } else { + return { errc::common::invalid_argument, + ERROR_LOCATION, + fmt::format("unexpected analytics link type {}", type.value()) }; + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_replace_link(zval* return_value, + const zval* analytics_link, + const zval* options) +{ + auto [err, type] = cb_get_string(analytics_link, "type"); + + if (err.ec) { + return err; + } + if (!type.has_value()) { + return { errc::common::invalid_argument, + ERROR_LOCATION, + "Did not receive an analytics link type" }; + } + + if (type.value() == "couchbase") { + couchbase::core::operations::management::analytics_link_replace_request< + couchbase::core::management::analytics::couchbase_remote_link> + request{}; + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_fill_analytics_link(request.link, analytics_link); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to replace couchbase_remote link" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to replace couchbase_remote link ({}: {})", + first_error.code, + first_error.message) }; + } + } + } else if (type.value() == "azureblob") { + couchbase::core::operations::management::analytics_link_replace_request< + couchbase::core::management::analytics::azure_blob_external_link> + request{}; + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_fill_analytics_link(request.link, analytics_link); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to replace azure_blob_external link" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to replace azure_blob_external link ({}: {})", + first_error.code, + first_error.message) }; + } + } + } else if (type.value() == "s3") { + couchbase::core::operations::management::analytics_link_replace_request< + couchbase::core::management::analytics::s3_external_link> + request{}; + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + if (auto e = cb_fill_analytics_link(request.link, analytics_link); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to replace s3_external link" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to replace s3_external link ({}: {})", + first_error.code, + first_error.message) }; + } + } + } else { + return { errc::common::invalid_argument, + ERROR_LOCATION, + fmt::format("unexpected analytics link type {}", type.value()) }; + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_drop_link(zval* return_value, + const zend_string* link_name, + const zend_string* dataverse_name, + const zval* options) +{ + couchbase::core::operations::management::analytics_link_drop_request request{}; + + request.link_name = cb_string_new(link_name); + request.dataverse_name = cb_string_new(dataverse_name); + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to drop link" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to drop link ({}: {})", first_error.code, first_error.message) }; + } + } + + return {}; +} + +COUCHBASE_API +core_error_info +connection_handle::analytics_get_all_links(zval* return_value, const zval* options) +{ + couchbase::core::operations::management::analytics_link_get_all_request request{}; + + if (auto e = cb_assign_string(request.link_type, options, "linkType"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(request.link_name, options, "name"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(request.dataverse_name, options, "dataverseName"); e.ec) { + return e; + } + + if (auto e = cb_assign_timeout(request, options); e.ec) { + return e; + } + + auto [resp, err] = impl_->http_execute(__func__, std::move(request)); + + if (err.ec) { + if (resp.errors.empty()) { + return { resp.ctx.ec, ERROR_LOCATION, "unable to retrieve analytics links" }; + } else { + const auto& first_error = resp.errors.front(); + return { resp.ctx.ec, + ERROR_LOCATION, + fmt::format("unable to retrieve analytics links ({}: {})", + first_error.code, + first_error.message) }; + } + } + + array_init(return_value); + for (const auto& link : resp.couchbase) { + zval row; + array_init(&row); + add_assoc_string(&row, "type", "couchbase"); + add_assoc_string(&row, "name", link.link_name.c_str()); + add_assoc_string(&row, "dataverseName", link.dataverse.c_str()); + add_assoc_string(&row, "hostname", link.hostname.c_str()); + if (link.username.has_value()) { + add_assoc_string(&row, "username", link.username.value().c_str()); + } + switch (link.encryption.level) { + case core::management::analytics::couchbase_link_encryption_level::none: + add_assoc_string(&row, "encryptionLevel", "none"); + break; + case core::management::analytics::couchbase_link_encryption_level::half: + add_assoc_string(&row, "encryptionLevel", "half"); + break; + case core::management::analytics::couchbase_link_encryption_level::full: + add_assoc_string(&row, "encryptionLevel", "full"); + break; + } + if (link.encryption.certificate.has_value()) { + add_assoc_string(&row, "certificate", link.encryption.certificate.value().c_str()); + } + if (link.encryption.client_certificate.has_value()) { + add_assoc_string( + &row, "clientCertificate", link.encryption.client_certificate.value().c_str()); + } + add_next_index_zval(return_value, &row); + } + for (const auto& link : resp.s3) { + zval row; + array_init(&row); + add_assoc_string(&row, "type", "s3"); + add_assoc_string(&row, "name", link.link_name.c_str()); + add_assoc_string(&row, "dataverseName", link.dataverse.c_str()); + add_assoc_string(&row, "accessKeyId", link.access_key_id.c_str()); + add_assoc_string(&row, "region", link.region.c_str()); + if (link.service_endpoint.has_value()) { + add_assoc_string(&row, "serviceEndpoint", link.service_endpoint.value().c_str()); + } + add_next_index_zval(return_value, &row); + } + + for (const auto& link : resp.azure_blob) { + zval row; + array_init(&row); + add_assoc_string(&row, "type", "azureblob"); + add_assoc_string(&row, "name", link.link_name.c_str()); + add_assoc_string(&row, "dataverseName", link.dataverse.c_str()); + if (link.account_name.has_value()) { + add_assoc_string(&row, "accountName", link.account_name.value().c_str()); + } + if (link.blob_endpoint.has_value()) { + add_assoc_string(&row, "blobEndpoint", link.blob_endpoint.value().c_str()); + } + if (link.endpoint_suffix.has_value()) { + add_assoc_string(&row, "endpointSuffix", link.endpoint_suffix.value().c_str()); + } + add_next_index_zval(return_value, &row); + } + + return {}; +} + bool connection_handle::is_expired(std::chrono::system_clock::time_point now) const { diff --git a/src/wrapper/connection_handle.hxx b/src/wrapper/connection_handle.hxx index acfe2f2b..aa884e46 100644 --- a/src/wrapper/connection_handle.hxx +++ b/src/wrapper/connection_handle.hxx @@ -617,6 +617,74 @@ public: const zend_string* collection_name, const zval* options); + COUCHBASE_API + core_error_info analytics_create_dataverse(zval* return_value, + const zend_string* dataverse_name, + const zval* options); + + COUCHBASE_API + core_error_info analytics_drop_dataverse(zval* return_value, + const zend_string* dataverse_name, + const zval* options); + + COUCHBASE_API + core_error_info analytics_create_dataset(zval* return_value, + const zend_string* dataset_name, + const zend_string* bucket_name, + const zval* options); + + COUCHBASE_API + core_error_info analytics_drop_dataset(zval* return_value, + const zend_string* dataset_name, + const zval* options); + + COUCHBASE_API + core_error_info analytics_get_all_datasets(zval* return_value, const zval* options); + + COUCHBASE_API + core_error_info analytics_create_index(zval* return_value, + const zend_string* dataset_name, + const zend_string* index_name, + const zval* fields, + const zval* options); + + COUCHBASE_API + core_error_info analytics_drop_index(zval* return_value, + const zend_string* dataset_name, + const zend_string* index_name, + const zval* options); + + COUCHBASE_API + core_error_info analytics_get_all_indexes(zval* return_value, const zval* options); + + COUCHBASE_API + core_error_info analytics_connect_link(zval* return_value, const zval* options); + + COUCHBASE_API + core_error_info analytics_disconnect_link(zval* return_value, const zval* options); + + COUCHBASE_API + core_error_info analytics_get_pending_mutations(zval* return_value, const zval* options); + + COUCHBASE_API + core_error_info analytics_create_link(zval* return_value, + const zval* analytics_link, + const zval* options); + + COUCHBASE_API + core_error_info analytics_replace_link(zval* return_value, + const zval* analytics_link, + const zval* options); + + COUCHBASE_API + core_error_info analytics_drop_link(zval* return_value, + const zend_string* link_name, + const zend_string* dataverse_name, + const zval* options); + + COUCHBASE_API + core_error_info analytics_get_all_links(zval* return_value, const zval* options); + private: class impl; diff --git a/src/wrapper/conversion_utilities.cxx b/src/wrapper/conversion_utilities.cxx index 919b736a..3881d284 100644 --- a/src/wrapper/conversion_utilities.cxx +++ b/src/wrapper/conversion_utilities.cxx @@ -586,7 +586,7 @@ search_query_response_to_zval(zval* return_value, const core::operations::search zval fragments; array_init(&fragments); - for (auto const& [field, fragment] : row.fragments) { + for (const auto& [field, fragment] : row.fragments) { zval z_fragment_values; array_init(&z_fragment_values); @@ -816,6 +816,134 @@ zval_to_common_search_request(const zend_string* index_name, return { request, {} }; } +core_error_info +cb_fill_analytics_link(core::management::analytics::couchbase_remote_link& dst, const zval* src) +{ + if (auto e = cb_assign_string(dst.link_name, src, "linkName"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.dataverse, src, "dataverse"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.hostname, src, "hostname"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.username, src, "username"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.password, src, "password"); e.ec) { + return e; + } + + auto [err, encryption_level] = cb_get_string(src, "encryptionLevel"); + if (err.ec) { + return err; + } + + if (!encryption_level.has_value()) { + dst.encryption.level = core::management::analytics::couchbase_link_encryption_level::none; + } else if (encryption_level.value() == "none") { + dst.encryption.level = core::management::analytics::couchbase_link_encryption_level::none; + } else if (encryption_level.value() == "half") { + dst.encryption.level = core::management::analytics::couchbase_link_encryption_level::half; + } else if (encryption_level.value() == "full") { + dst.encryption.level = core::management::analytics::couchbase_link_encryption_level::full; + } else { + return { errc::common::invalid_argument, + ERROR_LOCATION, + fmt::format("invalid value used for encryptionLevel: {}", *encryption_level) }; + } + + if (auto e = cb_assign_string(dst.encryption.certificate, src, "certificate"); e.ec) { + return e; + } + if (auto e = cb_assign_string(dst.encryption.client_certificate, src, "clientCertificate"); + e.ec) { + return e; + } + if (auto e = cb_assign_string(dst.encryption.client_key, src, "clientKey"); e.ec) { + return e; + } + + return {}; +} + +core_error_info +cb_fill_analytics_link(core::management::analytics::azure_blob_external_link& dst, const zval* src) +{ + if (auto e = cb_assign_string(dst.link_name, src, "linkName"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.dataverse, src, "dataverse"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.connection_string, src, "connectionString"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.account_name, src, "accountName"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.account_key, src, "accountKey"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.shared_access_signature, src, "sharedAccessSignature"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.blob_endpoint, src, "blobEndpoint"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.endpoint_suffix, src, "endpointSuffix"); e.ec) { + return e; + } + + return {}; +} + +core_error_info +cb_fill_analytics_link(core::management::analytics::s3_external_link& dst, const zval* src) +{ + if (auto e = cb_assign_string(dst.link_name, src, "linkName"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.dataverse, src, "dataverse"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.access_key_id, src, "accessKeyId"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.secret_access_key, src, "secretAccessKey"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.session_token, src, "sessionToken"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.region, src, "region"); e.ec) { + return e; + } + + if (auto e = cb_assign_string(dst.service_endpoint, src, "serviceEndpoint"); e.ec) { + return e; + } + + return {}; +} + core_error_info cb_string_to_cas(const std::string& cas_string, couchbase::cas& cas) { diff --git a/src/wrapper/conversion_utilities.hxx b/src/wrapper/conversion_utilities.hxx index 92796b4e..5f18a027 100644 --- a/src/wrapper/conversion_utilities.hxx +++ b/src/wrapper/conversion_utilities.hxx @@ -22,6 +22,10 @@ #include #include +#include +#include +#include + #include #include #include @@ -64,6 +68,15 @@ zval_to_common_search_request(const zend_string* index_name, const zend_string* query, const zval* options); +core_error_info +cb_fill_analytics_link(core::management::analytics::couchbase_remote_link& dst, const zval* src); + +core_error_info +cb_fill_analytics_link(core::management::analytics::azure_blob_external_link& dst, const zval* src); + +core_error_info +cb_fill_analytics_link(core::management::analytics::s3_external_link& dst, const zval* src); + void query_response_to_zval(zval* return_value, const core::operations::query_response& resp); diff --git a/src/wrapper/persistent_connections_cache.cxx b/src/wrapper/persistent_connections_cache.cxx index 9630b6fb..d70ac2e8 100644 --- a/src/wrapper/persistent_connections_cache.cxx +++ b/src/wrapper/persistent_connections_cache.cxx @@ -53,7 +53,7 @@ check_persistent_connection(zval* zv) auto now = std::chrono::system_clock::now(); if (res->type == persistent_connection_destructor_id_) { - auto const* connection = static_cast(res->ptr); + const auto* connection = static_cast(res->ptr); if (COUCHBASE_G(persistent_timeout) != -1 && connection->is_expired(now)) { /* connection has timed out */ return ZEND_HASH_APPLY_REMOVE; @@ -201,7 +201,7 @@ notify_transaction(zval* zv, void* event_ptr) const fork_event event = *(static_cast(event_ptr)); if (res->type == get_transactions_destructor_id()) { - auto const* transaction = static_cast(res->ptr); + const auto* transaction = static_cast(res->ptr); transaction->notify_fork(event); } return ZEND_HASH_APPLY_KEEP; diff --git a/tests/AnalyticsManagerTest.php b/tests/AnalyticsManagerTest.php new file mode 100644 index 00000000..54cd738a --- /dev/null +++ b/tests/AnalyticsManagerTest.php @@ -0,0 +1,209 @@ +manager = $this->connectCluster()->analyticsIndexes(); + $this->indexName = $this->uniqueId("idx"); + $this->datasetName = $this->uniqueId("ds"); + $this->dataverseName = $this->uniqueId("dv"); + $this->linkName = $this->uniqueId("ln"); + } + + public function testAnalyticsIndexCreationWorkflow() + { + $this->skipIfProtostellar(); + $this->skipIfCaves(); + + $this->retryFor( + 5, + 1000, + function () { + $this->manager->createDataverse($this->dataverseName); + } + ); + + $this->manager->createDataset($this->datasetName, self::env()->bucketName(), CreateAnalyticsDatasetOptions::build()->dataverseName($this->dataverseName)); + + $datasets = $this->manager->getAllDatasets(); + + $exists = false; + foreach ($datasets as $dataset) { + if ($dataset->name() == $this->datasetName && $dataset->dataverseName() == $this->dataverseName) { + $exists = true; + } + } + $this->assertTrue($exists); + + $this->manager->createIndex($this->datasetName, $this->indexName, [ "name" => "string" ], CreateAnalyticsIndexOptions::build()->dataverseName($this->dataverseName)); + + $indexes = $this->manager->getAllIndexes(); + + $exists = false; + foreach ($indexes as $index) { + if ($index->name() == $this->indexName && $index->datasetName() == $this->datasetName && $index->dataverseName() == $this->dataverseName) { + $exists = true; + } + } + + $this->assertTrue($exists); + + $this->manager->createIndex($this->datasetName, $this->indexName, [ "name" => "string"], CreateAnalyticsIndexOptions::build()->dataverseName($this->dataverseName)->ignoreIfExists(true)); + + $this->manager->dropIndex($this->datasetName, $this->indexName, \Couchbase\Management\DropAnalyticsIndexOptions::build()->dataverseName($this->dataverseName)); + + $indexes = $this->manager->getAllIndexes(); + + $exists = false; + foreach ($indexes as $index) { + if ($index->name() == $this->indexName && $index->datasetName() == $this->datasetName && $index->dataverseName() == $this->dataverseName) { + $exists = true; + } + } + + $this->assertFalse($exists); + + $this->manager->dropDataset($this->datasetName, DropAnalyticsDatasetOptions::build()->dataverseName($this->dataverseName)); + + $datasets = $this->manager->getAllDatasets(); + + $exists = false; + foreach ($datasets as $dataset) { + if ($dataset->name() == $this->datasetName && $dataset->dataverseName() == $this->dataverseName) { + $exists = true; + } + } + + $this->assertFalse($exists); + + $this->manager->dropDataverse($this->dataverseName); + } + + public function testLinkCreationWorkflow() + { + $this->skipIfProtostellar(); + $this->skipIfCaves(); + + $this->retryFor( + 5, + 1000, + function () { + $this->manager->createDataverse($this->dataverseName, CreateAnalyticsDataverseOptions::build()->ignoreIfExists(true)); + } + ); + + $s3Link = S3ExternalAnalyticsLink::build($this->linkName, $this->dataverseName, "accessKeyId", "us-east-1", "secretAccessKey"); + + $this->manager->createLink($s3Link); + + $links = $this->manager->getLinks(); + + $found = false; + + foreach ($links as $link) { + if ($link->dataverseName() == $this->dataverseName && $link->name() == $this->linkName && $link->linkType() == "s3") { + $found = true; + } + } + $this->assertTrue($found); + + $this->manager->dropLink($this->linkName, $this->dataverseName); + + $links = $this->manager->getLinks(); + + $found = false; + + foreach ($links as $link) { + if ($link->dataverseName() == $this->dataverseName && $link->name() == $this->linkName && $link->linkType() == "s3") { + $found = true; + } + } + $this->assertFalse($found); + + $this->expectException(LinkNotFoundException::class); + $this->manager->replaceLink($s3Link); + } + + public function testGetPendingMutations() + { + $this->skipIfProtostellar(); + $this->skipIfCaves(); + + $this->retryFor( + 5, + 1000, + function () { + $this->manager->createDataverse($this->dataverseName, CreateAnalyticsDataverseOptions::build()->ignoreIfExists(true)); + } + ); + + $this->manager->createDataset("dataset1", self::env()->bucketName(), CreateAnalyticsDatasetOptions::build()->ignoreIfExists(true)); + $this->manager->createDataset("dataset2", self::env()->bucketName(), CreateAnalyticsDatasetOptions::build()->dataverseName($this->dataverseName)->ignoreIfExists(true)); + $this->manager->createDataset("dataset3", self::env()->bucketName(), CreateAnalyticsDatasetOptions::build()->dataverseName($this->dataverseName)->ignoreIfExists(true)); + + $this->manager->connectLink(); + + $res = $this->manager->getPendingMutations(); + + $this->assertArrayHasKey("Default", $res); + $this->assertArrayHasKey($this->dataverseName, $res); + $this->assertIsArray($res[$this->dataverseName]); + $this->assertGreaterThanOrEqual(2, count($res[$this->dataverseName])); + $this->assertArrayHasKey("dataset2", $res[$this->dataverseName]); + + $this->manager->disconnectLink(); + } + + + public function testFailDropMissingIndex() + { + $this->skipIfProtostellar(); + $this->skipIfCaves(); + + $this->manager->createDataset($this->datasetName, self::env()->bucketName(), CreateAnalyticsDatasetOptions::build()->ignoreIfExists(true)); + + $this->expectException(IndexNotFoundException::class); + $this->manager->dropIndex($this->datasetName, "does-not-exist"); + } + + public function testFailDropMissingDataset() + { + $this->skipIfProtostellar(); + $this->skipIfCaves(); + + $this->expectException(DatasetNotFoundException::class); + $this->manager->dropDataset("does-not-exist"); + } + + public function testFailDropMissingDataverse() + { + $this->skipIfProtostellar(); + $this->skipIfCaves(); + + $this->expectException(DataverseNotFoundException::class); + $this->manager->dropDataverse("does-not-exist"); + } +}