1717import json
1818import logging
1919from dataclasses import dataclass
20+ from dataclasses import field
2021from typing import Any
2122from typing import Callable
2223from typing import Dict
3738_LOGGER = logging .getLogger (__name__ )
3839
3940
41+ @dataclass
42+ class AlloyDBLanguageConnectorConfig :
43+ """Configuration options for AlloyDB Java language connector.
44+
45+ Contains all parameters needed to configure a connection using the AlloyDB
46+ Java connector via JDBC. For details see
47+ https://github.com/GoogleCloudPlatform/alloydb-java-connector/blob/main/docs/jdbc.md
48+
49+ Attributes:
50+ database_name: Name of the database to connect to.
51+ instance_name: Fullly qualified instance. Format:
52+ 'projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances
53+ /<INSTANCE>'
54+ ip_type: IP type to use for connection. Either 'PRIVATE' (default),
55+ 'PUBLIC' 'PSC.
56+ enable_iam_auth: Whether to enable IAM authentication. Default is False
57+ target_principal: Optional service account to impersonate for
58+ connection.
59+ delegates: Optional comma-separated list of service accounts for
60+ delegated impersonation.
61+ admin_service_endpoint: Optional custom API service endpoint.
62+ quota_project: Optional project ID for quota and billing.
63+ """
64+ database_name : str
65+ instance_name : str
66+ ip_type : str = "PRIVATE"
67+ enable_iam_auth : bool = False
68+ target_principal : Optional [str ] = None
69+ delegates : Optional [List [str ]] = None
70+ admin_service_endpoint : Optional [str ] = None
71+ quota_project : Optional [str ] = None
72+
73+ def to_jdbc_url (self ) -> str :
74+ """Convert options to a properly formatted JDBC URL.
75+
76+ Returns:
77+ JDBC URL string configured with all options.
78+ """
79+ # Base URL with database name
80+ url = f"jdbc:postgresql:///{ self .database_name } ?"
81+
82+ # Add required properties
83+ properties = {
84+ "socketFactory" : "com.google.cloud.alloydb.SocketFactory" ,
85+ "alloydbInstanceName" : self .instance_name ,
86+ "alloydbIpType" : self .ip_type
87+ }
88+
89+ if self .enable_iam_auth :
90+ properties ["alloydbEnableIAMAuth" ] = "true"
91+
92+ if self .target_principal :
93+ properties ["alloydbTargetPrincipal" ] = self .target_principal
94+
95+ if self .delegates :
96+ properties ["alloydbDelegates" ] = "," .join (self .delegates )
97+
98+ if self .admin_service_endpoint :
99+ properties ["alloydbAdminServiceEndpoint" ] = self .admin_service_endpoint
100+
101+ if self .quota_project :
102+ properties ["alloydbQuotaProject" ] = self .quota_project
103+
104+ property_string = "&" .join (f"{ k } ={ v } " for k , v in properties .items ())
105+ return url + property_string
106+
107+
40108@dataclass
41109class AlloyDBConnectionConfig :
42110 """Configuration for AlloyDB database connection.
@@ -58,6 +126,10 @@ class AlloyDBConnectionConfig:
58126 max_connections: Optional number of connections in the pool.
59127 Use negative for no limit.
60128 write_batch_size: Optional write batch size for bulk operations.
129+ additional_jdbc_args: Additional arguments that will be passed to
130+ WriteToJdbc. These may include 'driver_jars', 'expansion_service',
131+ 'classpath', etc. See full set of args at
132+ :class:`~apache_beam.io.jdbc.WriteToJdbc`
61133
62134 Example:
63135 >>> config = AlloyDBConnectionConfig(
@@ -76,6 +148,60 @@ class AlloyDBConnectionConfig:
76148 autosharding : Optional [bool ] = None
77149 max_connections : Optional [int ] = None
78150 write_batch_size : Optional [int ] = None
151+ additional_jdbc_args : Dict [str , Any ] = field (default_factory = dict )
152+
153+ @classmethod
154+ def with_language_connector (
155+ cls ,
156+ connector_options : AlloyDBLanguageConnectorConfig ,
157+ username : str ,
158+ password : str ,
159+ connection_properties : Optional [Dict [str , str ]] = None ,
160+ connection_init_sqls : Optional [List [str ]] = None ,
161+ autosharding : Optional [bool ] = None ,
162+ max_connections : Optional [int ] = None ,
163+ write_batch_size : Optional [int ] = None ) -> 'AlloyDBConnectionConfig' :
164+ """Create AlloyDBConnectionConfig using the AlloyDB language connector.
165+
166+ Args:
167+ connector_options: AlloyDB language connector configuration options.
168+ username: Database username. For IAM auth, this should be the IAM
169+ user email.
170+ password: Database password. Can be empty string when using IAM
171+ auth.
172+ connection_properties: Additional JDBC connection properties.
173+ connection_init_sqls: SQL statements to execute on connection.
174+ autosharding: Enable autosharding.
175+ max_connections: Max connections in pool.
176+ write_batch_size: Write batch size.
177+
178+ Returns:
179+ Configured AlloyDBConnectionConfig instance.
180+
181+ Example:
182+ >>> options = AlloyDBLanguageConnectorConfig(
183+ ... database_name="mydb",
184+ ... instance_name="projects/my-project/locations/us-central1\
185+ .... /clusters/my-cluster/instances/my-instance",
186+ ... ip_type="PUBLIC",
187+ ... enable_iam_auth=True
188+ ... )
189+ """
190+ return cls (
191+ jdbc_url = connector_options .to_jdbc_url (),
192+ username = username ,
193+ password = password ,
194+ connection_properties = connection_properties ,
195+ connection_init_sqls = connection_init_sqls ,
196+ autosharding = autosharding ,
197+ max_connections = max_connections ,
198+ write_batch_size = write_batch_size ,
199+ additional_jdbc_args = {
200+ 'classpath' : [
201+ "org.postgresql:postgresql:42.2.16" ,
202+ "com.google.cloud:alloydb-jdbc-connector:1.2.0"
203+ ]
204+ })
79205
80206
81207@dataclass
@@ -713,4 +839,5 @@ def expand(self, pcoll: beam.PCollection[Chunk]):
713839 connection_init_sqls ,
714840 autosharding = self .config .connection_config .autosharding ,
715841 max_connections = self .config .connection_config .max_connections ,
716- write_batch_size = self .config .connection_config .write_batch_size ))
842+ write_batch_size = self .config .connection_config .write_batch_size ,
843+ ** self .config .connection_config .additional_jdbc_args ))
0 commit comments