|
15 | 15 | """Schemas for BigQuery tables / queries.""" |
16 | 16 |
|
17 | 17 | from __future__ import annotations |
18 | | -import collections |
19 | 18 | import enum |
20 | 19 | import typing |
21 | 20 | from typing import Any, cast, Dict, Iterable, Optional, Union |
@@ -503,40 +502,78 @@ def _build_schema_resource(fields): |
503 | 502 | Returns: |
504 | 503 | Sequence[Dict]: Mappings describing the schema of the supplied fields. |
505 | 504 | """ |
506 | | - return [field.to_api_repr() for field in fields] |
| 505 | + if isinstance(fields, (list, tuple)): |
| 506 | + # Input is list-like: Process and return a list of SchemaFields |
| 507 | + return [field.to_api_repr() for field in fields] |
| 508 | + |
| 509 | + elif isinstance(fields, dict): |
| 510 | + # Input is a dict: Update "fields" in place, if present |
| 511 | + |
| 512 | + if "fields" not in fields: |
| 513 | + return fields # No fields to process, so nothing to convert |
| 514 | + |
| 515 | + fields["fields"] = [field.to_api_repr() for field in fields["fields"]] |
| 516 | + return fields # Return the modified dictionary |
| 517 | + |
| 518 | + else: |
| 519 | + raise TypeError("Schema must be a Sequence (list) or a Mapping (dict).") |
507 | 520 |
|
508 | 521 |
|
509 | 522 | def _to_schema_fields(schema): |
510 | | - """Coerce `schema` to a list of schema field instances. |
| 523 | + """Coerces schema to a list of SchemaField instances while |
| 524 | + preserving the original structure as much as possible. |
511 | 525 |
|
512 | 526 | Args: |
513 | | - schema(Sequence[Union[ \ |
514 | | - :class:`~google.cloud.bigquery.schema.SchemaField`, \ |
515 | | - Mapping[str, Any] \ |
516 | | - ]]): |
517 | | - Table schema to convert. If some items are passed as mappings, |
518 | | - their content must be compatible with |
519 | | - :meth:`~google.cloud.bigquery.schema.SchemaField.from_api_repr`. |
| 527 | + schema (Union[ \ |
| 528 | + dict, \ |
| 529 | + Sequence[Union[ \ |
| 530 | + :class:`~google.cloud.bigquery.schema.SchemaField`, \ |
| 531 | + Mapping[str, Any] \ |
| 532 | + ] |
| 533 | + ] |
| 534 | + ] |
| 535 | + ):: |
| 536 | + Table schema to convert. Can be a list of SchemaField |
| 537 | + objects or mappings, OR a dictionary with a "fields" key |
| 538 | + containing such a list and optionally a "foreign_type_info" key. |
520 | 539 |
|
521 | 540 | Returns: |
522 | | - Sequence[:class:`~google.cloud.bigquery.schema.SchemaField`] |
| 541 | + A list of SchemaField objects if the input was a list. |
| 542 | + A dictionary with a list of Schemafield objects assigned to the 'fields' |
| 543 | + key, if the input was a dictionary. If a "foreign_type_info" key was present |
| 544 | + in the dictionary, it will be preserved. |
523 | 545 |
|
524 | 546 | Raises: |
525 | | - Exception: If ``schema`` is not a sequence, or if any item in the |
526 | | - sequence is not a :class:`~google.cloud.bigquery.schema.SchemaField` |
527 | | - instance or a compatible mapping representation of the field. |
| 547 | + TypeError: If schema is not a list or dictionary. |
| 548 | + ValueError: If schema is a dictionary without a "fields" key, or |
| 549 | + if any element within the "fields" is invalid. |
528 | 550 | """ |
529 | | - for field in schema: |
530 | | - if not isinstance(field, (SchemaField, collections.abc.Mapping)): |
531 | | - raise ValueError( |
532 | | - "Schema items must either be fields or compatible " |
533 | | - "mapping representations." |
534 | | - ) |
535 | 551 |
|
536 | | - return [ |
537 | | - field if isinstance(field, SchemaField) else SchemaField.from_api_repr(field) |
538 | | - for field in schema |
539 | | - ] |
| 552 | + if isinstance(schema, (list, tuple)): |
| 553 | + # Input is a list: Process and return a new list of SchemaFields |
| 554 | + return [ |
| 555 | + field |
| 556 | + if isinstance(field, SchemaField) |
| 557 | + else SchemaField.from_api_repr(field) |
| 558 | + for field in schema |
| 559 | + ] |
| 560 | + |
| 561 | + elif isinstance(schema, dict): |
| 562 | + # Input is a dict: Update "fields" in place if present |
| 563 | + |
| 564 | + if "fields" not in schema: |
| 565 | + return schema # No fields to process, so nothing to convert |
| 566 | + |
| 567 | + schema["fields"] = [ |
| 568 | + field |
| 569 | + if isinstance(field, SchemaField) |
| 570 | + else SchemaField.from_api_repr(field) |
| 571 | + for field in schema["fields"] |
| 572 | + ] |
| 573 | + return schema # Return the modified dictionary |
| 574 | + |
| 575 | + else: |
| 576 | + raise TypeError("Schema must be a Sequence (list) or a Mapping (dict).") |
540 | 577 |
|
541 | 578 |
|
542 | 579 | class PolicyTagList(object): |
|
0 commit comments