You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

99 lines
3.3 KiB

package s3tables
import (
"fmt"
"path/filepath"
"regexp"
"time"
)
// ARN parsing functions
// parseBucketNameFromARN extracts bucket name from table bucket ARN
// ARN format: arn:aws:s3tables:{region}:{account}:bucket/{bucket-name}
func parseBucketNameFromARN(arn string) (string, error) {
pattern := regexp.MustCompile(`^arn:aws:s3tables:[^:]*:[^:]*:bucket/([a-z0-9_-]+)$`)
matches := pattern.FindStringSubmatch(arn)
if len(matches) != 2 {
return "", fmt.Errorf("invalid bucket ARN: %s", arn)
}
return matches[1], nil
}
// parseTableFromARN extracts bucket name, namespace, and table name from ARN
// ARN format: arn:aws:s3tables:{region}:{account}:bucket/{bucket-name}/table/{namespace}/{table-name}
func parseTableFromARN(arn string) (bucketName, namespace, tableName string, err error) {
pattern := regexp.MustCompile(`^arn:aws:s3tables:[^:]*:[^:]*:bucket/([a-z0-9_-]+)/table/([a-z0-9_]+)/([a-z0-9_]+)$`)
matches := pattern.FindStringSubmatch(arn)
if len(matches) != 4 {
return "", "", "", fmt.Errorf("invalid table ARN: %s", arn)
}
return matches[1], matches[2], matches[3], nil
}
// Path helpers
// getTableBucketPath returns the filer path for a table bucket
func getTableBucketPath(bucketName string) string {
return fmt.Sprintf("%s/%s", TablesPath, bucketName)
}
// getNamespacePath returns the filer path for a namespace
func getNamespacePath(bucketName, namespace string) string {
return fmt.Sprintf("%s/%s/namespaces/%s", TablesPath, bucketName, namespace)
}
// getTablePath returns the filer path for a table
func getTablePath(bucketName, namespace, tableName string) string {
return fmt.Sprintf("%s/%s/namespaces/%s/%s", TablesPath, bucketName, namespace, tableName)
}
// Metadata structures
// tableBucketMetadata stores metadata for a table bucket
type tableBucketMetadata struct {
Name string `json:"name"`
CreatedAt time.Time `json:"createdAt"`
OwnerID string `json:"ownerAccountId"`
}
// namespaceMetadata stores metadata for a namespace
type namespaceMetadata struct {
Namespace []string `json:"namespace"`
CreatedAt time.Time `json:"createdAt"`
OwnerID string `json:"ownerAccountId"`
}
// tableMetadataInternal stores metadata for a table
type tableMetadataInternal struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
Format string `json:"format"`
CreatedAt time.Time `json:"createdAt"`
ModifiedAt time.Time `json:"modifiedAt"`
OwnerID string `json:"ownerAccountId"`
VersionToken string `json:"versionToken"`
MetadataLocation string `json:"metadataLocation,omitempty"`
Schema *TableMetadata `json:"metadata,omitempty"`
}
// Utility functions
// isValidBucketName validates bucket name characters
// Bucket names must contain only lowercase letters, numbers, hyphens, and underscores
func isValidBucketName(name string) bool {
pattern := regexp.MustCompile(`^[a-z0-9_-]+$`)
return pattern.MatchString(name)
}
// generateVersionToken generates a unique version token
func generateVersionToken() string {
return fmt.Sprintf("%d", time.Now().UnixNano())
}
// splitPath splits a path into directory and name components using stdlib
func splitPath(path string) (dir, name string) {
dir = filepath.Dir(path)
name = filepath.Base(path)
return
}