feat(spanner): add Client Context support to options (#1499) · googleapis/google-cloud-python@0da5f78
@@ -34,6 +34,8 @@
3434from google.cloud._helpers import _date_from_iso8601_date
3535from google.cloud.spanner_v1.types import ExecuteSqlRequest
3636from google.cloud.spanner_v1.types import TransactionOptions
37+from google.cloud.spanner_v1.types import ClientContext
38+from google.cloud.spanner_v1.types import RequestOptions
3739from google.cloud.spanner_v1.data_types import JsonObject, Interval
3840from google.cloud.spanner_v1.request_id_header import (
3941with_request_id,
@@ -172,15 +174,15 @@ def _merge_query_options(base, merge):
172174 If the resultant object only has empty fields, returns None.
173175 """
174176combined = base or ExecuteSqlRequest.QueryOptions()
175-if type(combined) is dict:
177+if isinstance(combined, dict):
176178combined = ExecuteSqlRequest.QueryOptions(
177179optimizer_version=combined.get("optimizer_version", ""),
178180optimizer_statistics_package=combined.get(
179181"optimizer_statistics_package", ""
180182 ),
181183 )
182184merge = merge or ExecuteSqlRequest.QueryOptions()
183-if type(merge) is dict:
185+if isinstance(merge, dict):
184186merge = ExecuteSqlRequest.QueryOptions(
185187optimizer_version=merge.get("optimizer_version", ""),
186188optimizer_statistics_package=merge.get("optimizer_statistics_package", ""),
@@ -191,6 +193,95 @@ def _merge_query_options(base, merge):
191193return combined
192194193195196+def _merge_client_context(base, merge):
197+"""Merge higher precedence ClientContext with current ClientContext.
198+199+ :type base: :class:`~google.cloud.spanner_v1.types.ClientContext`
200+ or :class:`dict` or None
201+ :param base: The current ClientContext that is intended for use.
202+203+ :type merge: :class:`~google.cloud.spanner_v1.types.ClientContext`
204+ or :class:`dict` or None
205+ :param merge:
206+ The ClientContext that has a higher priority than base. These options
207+ should overwrite the fields in base.
208+209+ :rtype: :class:`~google.cloud.spanner_v1.types.ClientContext`
210+ or None
211+ :returns:
212+ ClientContext object formed by merging the two given ClientContexts.
213+ """
214+if base is None and merge is None:
215+return None
216+217+# Avoid in-place modification of base
218+combined_pb = ClientContext()._pb
219+if base:
220+base_pb = ClientContext(base)._pb if isinstance(base, dict) else base._pb
221+combined_pb.MergeFrom(base_pb)
222+if merge:
223+merge_pb = ClientContext(merge)._pb if isinstance(merge, dict) else merge._pb
224+combined_pb.MergeFrom(merge_pb)
225+226+combined = ClientContext(combined_pb)
227+228+if not combined.secure_context:
229+return None
230+return combined
231+232+233+def _validate_client_context(client_context):
234+"""Validate and convert client_context.
235+236+ :type client_context: :class:`~google.cloud.spanner_v1.types.ClientContext`
237+ or :class:`dict`
238+ :param client_context: (Optional) Client context to use.
239+240+ :rtype: :class:`~google.cloud.spanner_v1.types.ClientContext`
241+ :returns: Validated ClientContext object or None.
242+ :raises TypeError: if client_context is not a ClientContext or a dict.
243+ """
244+if client_context is not None:
245+if isinstance(client_context, dict):
246+client_context = ClientContext(client_context)
247+elif not isinstance(client_context, ClientContext):
248+raise TypeError("client_context must be a ClientContext or a dict")
249+return client_context
250+251+252+def _merge_request_options(request_options, client_context):
253+"""Merge RequestOptions and ClientContext.
254+255+ :type request_options: :class:`~google.cloud.spanner_v1.types.RequestOptions`
256+ or :class:`dict` or None
257+ :param request_options: The current RequestOptions that is intended for use.
258+259+ :type client_context: :class:`~google.cloud.spanner_v1.types.ClientContext`
260+ or :class:`dict` or None
261+ :param client_context:
262+ The ClientContext to merge into request_options.
263+264+ :rtype: :class:`~google.cloud.spanner_v1.types.RequestOptions`
265+ or None
266+ :returns:
267+ RequestOptions object formed by merging the given ClientContext.
268+ """
269+if request_options is None and client_context is None:
270+return None
271+272+if request_options is None:
273+request_options = RequestOptions()
274+elif isinstance(request_options, dict):
275+request_options = RequestOptions(request_options)
276+277+if client_context:
278+request_options.client_context = _merge_client_context(
279+client_context, request_options.client_context
280+ )
281+282+return request_options
283+284+194285def _assert_numeric_precision_and_scale(value):
195286"""
196287 Asserts that input numeric field is within Spanner supported range.