From a35f10b3f33c5faa91e769ac478aabad79dfbb37 Mon Sep 17 00:00:00 2001 From: Martin Weise <martin.weise@tuwien.ac.at> Date: Sat, 12 Oct 2024 13:31:42 +0000 Subject: [PATCH] Version/keycloak --- .docker/docker-compose.yml | 1 - .docs/.swagger/api.base.yaml | 4 +- .docs/.swagger/api.yaml | 207 +- .docs/.swagger/swagger-generate.sh | 2 + .docs/api/gateway-service.md | 34 + .docs/changelog.md | 56 + .docs/help.md | 8 - .docs/images/architecture.drawio | 177 +- .docs/kubernetes.md | 34 +- dbrepo-analyse-service/.gitignore | 6 + dbrepo-analyse-service/Pipfile.lock | 214 +- .../lib/dbrepo-1.4.7.tar.gz | Bin 39380 -> 39357 bytes .../dashboards/system.json | 362 + .../at/tuwien/endpoints/TableEndpoint.java | 2 +- .../at/tuwien/endpoints/ViewEndpoint.java | 69 +- .../tuwien/validation/EndpointValidator.java | 2 - .../service/SchemaServiceIntegrationTest.java | 2 +- .../src/test/resources/init/weather.sql | 2 +- .../java/at/tuwien/mapper/DataMapper.java | 5 +- .../java/at/tuwien/mapper/MariaDbMapper.java | 27 +- .../java/at/tuwien/service/QueueService.java | 1 + .../java/at/tuwien/service/TableService.java | 48 + .../java/at/tuwien/service/ViewService.java | 40 +- .../service/impl/ViewServiceMariaDbImpl.java | 15 +- dbrepo-gateway-service/dbrepo.conf | 6 +- dbrepo-metadata-db/1_setup-schema.sql | 127 +- .../api/container/image/DataTypeDto.java | 22 +- .../at/tuwien/api/database/ViewColumnDto.java | 3 - .../api/database/table/columns/ColumnDto.java | 5 - .../database/table/columns/ColumnTypeDto.java | 3 + .../entities/container/image/DataType.java | 8 +- .../at/tuwien/entities/database/Database.java | 5 +- .../at/tuwien/entities/database/View.java | 2 +- .../tuwien/entities/database/ViewColumn.java | 12 +- .../tuwien/entities/database/table/Table.java | 12 +- .../database/table/columns/TableColumn.java | 8 +- .../table/columns/TableColumnType.java | 1 + .../java/at/tuwien/mapper/MetadataMapper.java | 1 - .../tuwien/validation/EndpointValidator.java | 30 + .../endpoints/TableEndpointUnitTest.java | 82 + .../tuwien/mapper/MetadataMapperUnitTest.java | 10 +- .../tuwien/service/TableServiceUnitTest.java | 1 - .../service/ViewServicePersistenceTest.java | 3 +- .../tuwien/service/impl/TableServiceImpl.java | 4 +- .../tuwien/service/impl/ViewServiceImpl.java | 4 +- .../java/at/tuwien/test/AbstractUnitTest.java | 13 +- .../main/java/at/tuwien/test/BaseTest.java | 360 +- dbrepo-metric-db/prometheus.yml | 4 + dbrepo-search-service/.gitignore | 6 + dbrepo-search-service/Pipfile.lock | 194 +- dbrepo-search-service/init/.gitignore | 5 + dbrepo-search-service/init/Pipfile.lock | 192 +- .../init/lib/dbrepo-1.4.7.tar.gz | Bin 39380 -> 39357 bytes dbrepo-search-service/init/test/test_app.py | 2 - dbrepo-search-service/lib/dbrepo-1.4.7.tar.gz | Bin 39380 -> 39357 bytes .../test/test_opensearch_client.py | 7 +- dbrepo-ui/bun.lockb | Bin 380657 -> 381014 bytes dbrepo-ui/components/dialogs/EditTuple.vue | 204 +- dbrepo-ui/components/subset/Builder.vue | 26 +- dbrepo-ui/components/table/TableHistory.vue | 35 +- dbrepo-ui/components/table/TableList.vue | 1 - dbrepo-ui/components/table/TableSchema.vue | 29 +- dbrepo-ui/components/table/TableToolbar.vue | 2 +- dbrepo-ui/composables/view-service.ts | 25 +- dbrepo-ui/dto/index.ts | 1 - dbrepo-ui/locales/en-US.json | 8 +- dbrepo-ui/package.json | 1 + .../[database_id]/table/[table_id]/data.vue | 3 +- .../[database_id]/table/[table_id]/schema.vue | 4 - .../[database_id]/view/[view_id]/data.vue | 52 +- dbrepo-ui/plugins/vuetify.ts | 1 + docker-compose.yml | 1 - lib/python/dbrepo/api/dto.py | 3 +- mkdocs.yml | 1 + yq.1 | 17196 ++++++++++++++++ 75 files changed, 19106 insertions(+), 937 deletions(-) create mode 100644 .docs/changelog.md create mode 100644 dbrepo-search-service/init/.gitignore create mode 100644 yq.1 diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml index 2d16bb1b50..1b826fedfd 100644 --- a/.docker/docker-compose.yml +++ b/.docker/docker-compose.yml @@ -85,7 +85,6 @@ services: - ./config/master-realm.json:/opt/keycloak/data/import/master-realm.json - ./config/dbrepo-realm.json:/opt/keycloak/data/import/dbrepo-realm.json environment: - BITNAMI_DEBUG: "true" KEYCLOAK_ENABLE_HTTPS: "false" KEYCLOAK_ENABLE_STATISTICS: "true" KEYCLOAK_ENABLE_HEALTH_ENDPOINTS: "true" diff --git a/.docs/.swagger/api.base.yaml b/.docs/.swagger/api.base.yaml index c7b01fab0e..b7bd0570ee 100644 --- a/.docs/.swagger/api.base.yaml +++ b/.docs/.swagger/api.base.yaml @@ -11,7 +11,7 @@ components: type: http externalDocs: description: Project Website - url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/ + url: https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.7/ info: contact: email: andreas.rauber@tuwien.ac.at @@ -24,7 +24,7 @@ info: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0 title: DBRepo REST API - version: 1.4.4 + version: 1.4.7 openapi: 3.1.0 servers: - description: Test Instance diff --git a/.docs/.swagger/api.yaml b/.docs/.swagger/api.yaml index 1495e398e3..a3f7eea7f2 100644 --- a/.docs/.swagger/api.yaml +++ b/.docs/.swagger/api.yaml @@ -16,7 +16,7 @@ info: name: Apache 2.0 url: 'https://www.apache.org/licenses/LICENSE-2.0' title: DBRepo REST API - version: 1.4.4 + version: 1.4.7 servers: - description: Test Instance url: 'https://test.dbrepo.tuwien.ac.at' @@ -929,7 +929,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ImportCsvDto' + $ref: '#/components/schemas/ImportDto' required: true responses: '202': @@ -5605,7 +5605,7 @@ components: type: object additionalProperties: type: object - ImportCsvDto: + ImportDto: required: - location - separator @@ -5624,13 +5624,6 @@ components: minimum: 0 type: integer format: int64 - false_element: - type: string - true_element: - type: string - null_element: - type: string - example: NA line_termination: type: string example: \r\n @@ -5760,6 +5753,7 @@ components: - longblob - enum - set + - serial - bit - tinyint - bool @@ -5777,7 +5771,6 @@ components: - year ColumnDto: required: - - auto_generated - column_type - database_id - id @@ -5845,11 +5838,6 @@ components: minLength: 0 type: string example: mdb_date - date_format: - $ref: '#/components/schemas/ImageDateDto' - auto_generated: - type: boolean - example: false index_length: type: integer format: int64 @@ -5874,6 +5862,7 @@ components: - longblob - enum - set + - serial - bit - tinyint - bool @@ -6014,6 +6003,64 @@ components: ui_port: type: integer format: int32 + DataTypeDto: + required: + - display_name + - documentation + - is_buildable + - is_quoted + - value + type: object + properties: + value: + type: string + example: time + documentation: + type: string + example: 'https://mariadb.com/kb/en/time/' + display_name: + type: string + example: TIME(fsp) + size_min: + type: integer + format: int32 + example: 0 + size_max: + type: integer + format: int32 + example: 6 + size_default: + type: integer + format: int32 + example: 0 + size_required: + type: boolean + example: false + d_min: + type: integer + format: int32 + d_max: + type: integer + format: int32 + d_default: + type: integer + format: int32 + d_required: + type: boolean + data_hint: + type: string + example: 'e.g. HH:MM:SS, HH:MM, HHMMSS, H:M:S' + type_hint: + type: string + example: 'fsp=microsecond precision, min. 0, max. 6' + is_quoted: + type: boolean + description: frontend needs to quote this data type + example: false + is_buildable: + type: boolean + description: frontend can build this data type + example: true DatabaseAccessDto: required: - created @@ -6164,33 +6211,9 @@ components: $ref: '#/components/schemas/ForeignKeyBriefDto' referenced_column: $ref: '#/components/schemas/ColumnBriefDto' - ImageDateDto: - required: - - created_at - - database_format - - has_time - - id - - unix_format - type: object - properties: - id: - type: integer - format: int64 - database_format: - type: string - example: '%d.%c.%Y' - unix_format: - type: string - example: dd.MM.YYYY - has_time: - type: boolean - example: false - created_at: - type: string - format: date-time - example: '2021-03-12T15:26:21.000Z' ImageDto: required: + - data_types - default - default_port - dialect @@ -6220,10 +6243,6 @@ components: driver_class: type: string example: org.mariadb.jdbc.Driver - date_formats: - type: array - items: - $ref: '#/components/schemas/ImageDateDto' jdbc_method: type: string example: mariadb @@ -6234,6 +6253,10 @@ components: type: integer format: int32 example: 3306 + data_types: + type: array + items: + $ref: '#/components/schemas/DataTypeDto' PrimaryKeyDto: required: - column @@ -6494,8 +6517,6 @@ components: minLength: 0 type: string example: mdb_date - date_format: - $ref: '#/components/schemas/ImageDateDto' auto_generated: type: boolean example: false @@ -6523,6 +6544,7 @@ components: - longblob - enum - set + - serial - bit - tinyint - bool @@ -8169,6 +8191,7 @@ components: - longblob - enum - set + - serial - bit - tinyint - bool @@ -8197,10 +8220,6 @@ components: minLength: 0 type: string example: Formatted as YYYY-MM-dd - dfid: - type: integer - description: date format id - format: int64 enums: type: array description: 'enum values, only considered when type = ENUM' @@ -8409,14 +8428,14 @@ components: type: string resumptionToken: type: string + parametersString: + type: string fromDate: type: string format: date-time untilDate: type: string format: date-time - parametersString: - type: string BannerMessageDto: required: - id @@ -8692,10 +8711,6 @@ components: format: int32 isDefault: type: boolean - dateFormats: - type: array - items: - $ref: '#/components/schemas/ContainerImageDate' containers: type: array items: @@ -8706,28 +8721,10 @@ components: lastModified: type: string format: date-time - ContainerImageDate: - type: object - properties: - id: - type: integer - format: int64 - iid: - type: integer - format: int64 - image: - $ref: '#/components/schemas/ContainerImage' - example: - type: string - hasTime: - type: boolean - databaseFormat: - type: string - unixFormat: - type: string - createdAt: - type: string - format: date-time + dataTypes: + type: array + items: + $ref: '#/components/schemas/DataType' Creator: type: object properties: @@ -8776,6 +8773,50 @@ components: type: string ieeeName: type: string + DataType: + type: object + properties: + id: + type: integer + format: int64 + displayName: + type: string + value: + type: string + sizeMin: + type: integer + format: int32 + sizeMax: + type: integer + format: int32 + sizeDefault: + type: integer + format: int32 + sizeRequired: + type: boolean + documentation: + type: string + typeHint: + type: string + dataHint: + type: string + quoted: + type: boolean + buildable: + type: boolean + image: + $ref: '#/components/schemas/ContainerImage' + dmin: + type: integer + format: int32 + dmax: + type: integer + format: int32 + ddefault: + type: integer + format: int32 + drequired: + type: boolean Database: type: object properties: @@ -9775,14 +9816,10 @@ components: id: type: integer format: int64 - dateFormat: - $ref: '#/components/schemas/ContainerImageDate' table: $ref: '#/components/schemas/Table' name: type: string - autoGenerated: - type: boolean internalName: type: string description: @@ -9809,6 +9846,7 @@ components: - TableColumnType.LONGBLOB - TableColumnType.ENUM - TableColumnType.SET + - TableColumnType.SERIAL - TableColumnType.BIT - TableColumnType.TINYINT - TableColumnType.BOOL @@ -9994,8 +10032,6 @@ components: id: type: integer format: int64 - dateFormat: - $ref: '#/components/schemas/ContainerImageDate' view: $ref: '#/components/schemas/View' name: @@ -10021,6 +10057,7 @@ components: - TableColumnType.LONGBLOB - TableColumnType.ENUM - TableColumnType.SET + - TableColumnType.SERIAL - TableColumnType.BIT - TableColumnType.TINYINT - TableColumnType.BOOL diff --git a/.docs/.swagger/swagger-generate.sh b/.docs/.swagger/swagger-generate.sh index c293e6c5cf..8ea2981243 100644 --- a/.docs/.swagger/swagger-generate.sh +++ b/.docs/.swagger/swagger-generate.sh @@ -6,6 +6,8 @@ services[9093]=data services[9099]=metadata services[3305]=sidecar +# requires https://github.com/mikefarah/yq/ -> v4.44.3 + function retrieve () { if [[ "$2" == analyse ]] || [[ "$2" == search ]] || [[ "$2" == sidecar ]]; then echo "... retrieve json api from localhost:$1" diff --git a/.docs/api/gateway-service.md b/.docs/api/gateway-service.md index 26ad76f092..9a44f9635b 100644 --- a/.docs/api/gateway-service.md +++ b/.docs/api/gateway-service.md @@ -60,6 +60,40 @@ services: ... ``` +## Monitoring (Optional) + +By default the Gateway Service is not monitored. You need to add the following to the `docker-compose.yml` file. + +```yaml title="docker-compose.yml" +services: + ... + dbrepo-gateway-service-sidecar: + restart: "no" + container_name: dbrepo-gateway-service-sidecar + hostname: dbrepo-gateway-service-sidecar + image: docker.io/nginx/nginx-prometheus-exporter:1.3.0 + command: + - "-nginx.scrape-uri=http://gateway-service/basic_status" + ports: + - "9113:9113" + depends_on: + dbrepo-gateway-service: + condition: service_started + logging: + driver: json-file +``` + +Then, uncomment the scrape config from the `prometheus.yml` file. + +```yaml title="prometheus.yml" +scrape_configs: + ... + - job_name: 'gateway scrape' + metrics_path: '/metrics' + static_configs: + - targets: ['dbrepo-gateway-service-sidecar:9113'] +``` + ## Limitations (none relevant to DBRepo) diff --git a/.docs/changelog.md b/.docs/changelog.md new file mode 100644 index 0000000000..256e245d5d --- /dev/null +++ b/.docs/changelog.md @@ -0,0 +1,56 @@ +--- +author: Martin Weise +--- + +## v1.4.7 (???) + +[:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.4.7) + +!!! warning "Contains Breaking Changes" + + This release updates the Metadata Database schema which is incompatible to v1.4.6! + +### What's Changed + +#### Features + +* Added `SERIAL` data type to create incrementing key + in [#454](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/454) + +#### Changes + +* Change the Docker image of the Auth Service to Bitnami-maintained similar to Kubernetes deployment with accompanying + Auth Database change to PostgreSQL + in [#455](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/455) + +#### Fixes + +* No hardcoded data type metadata in UI but instead added it hardcoded (associated with `image_id`) Metadata Database. + +## v1.4.6 (2024-10-11) + +[:simple-gitlab: GitLab Release](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/tags/v1.4.6) + +!!! warning "Contains Breaking Changes" + + This release updates the Metadata Database schema which is incompatible to v1.4.5! + +### What's Changed + +#### Features + +* Added [Dashboard Service](../api/dashboard-service/) and monitoring in default setup. + +#### Changes + +* Show the progress of dataset uploads in the UI + in [#448](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/448) +* Anonymous users are allowed to create (non-persistent) subsets + in [#449](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/449) +* Removed logic that maps `True`, `False` and `null` + +#### Fixes + +* Import of datasets stabilized in the UI + in [#442](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/442) +* Install script in [#444](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/issues/444) \ No newline at end of file diff --git a/.docs/help.md b/.docs/help.md index bde92d1b13..63ede84f97 100644 --- a/.docs/help.md +++ b/.docs/help.md @@ -10,14 +10,6 @@ The [concepts documentation](../concepts/) is the most complete guide on how to The [API documentation](../api/) present reference docs for all APIs. -## Troubleshooting - -**The Dashboard Service reloads recurrently** - -: *Origin*: Your Ad-Blocker blocks client-side requests of Grafana to its endpoints, resulting in authorization - errors, causing full page reloads. -: *Solution*: Disable uBlock Origin, AdBlock Plus, etc. for `/dashboard/*`. - !!! info "Additional Help" [Contact us](../contact) via e-mail. \ No newline at end of file diff --git a/.docs/images/architecture.drawio b/.docs/images/architecture.drawio index a6512707b1..8e44f6c84b 100644 --- a/.docs/images/architecture.drawio +++ b/.docs/images/architecture.drawio @@ -1,13 +1,13 @@ -<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.8 Chrome/128.0.6613.36 Electron/32.0.1 Safari/537.36" version="24.7.8" pages="8"> +<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.17 Chrome/128.0.6613.36 Electron/32.0.1 Safari/537.36" version="24.7.17" pages="8"> <diagram id="mvBsv1rP8O80Qe3yGnn_" name="docker-compose"> - <mxGraphModel dx="2390" dy="1370" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0"> + <mxGraphModel dx="683" dy="391" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1169" pageHeight="827" math="0" shadow="0"> <root> <mxCell id="0" /> <mxCell id="1" parent="0" /> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-76" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;arcSize=2;" vertex="1" parent="1"> - <mxGeometry x="320" y="160" width="530" height="397" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-76" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;arcSize=2;" parent="1" vertex="1"> + <mxGeometry x="320" y="160" width="640" height="397" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-77" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;endArrow=classic;endFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-108"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-77" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;endArrow=classic;endFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-108" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="668" y="206" /> @@ -16,55 +16,55 @@ </Array> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-78" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-77"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-78" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-77" vertex="1" connectable="0"> <mxGeometry x="-0.2051" y="1" relative="1" as="geometry"> <mxPoint x="61" y="40" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-79" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-77"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-79" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-77" vertex="1" connectable="0"> <mxGeometry x="-0.3724" relative="1" as="geometry"> <mxPoint x="-2" y="11" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-80" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;arcSize=6;" vertex="1" parent="1"> - <mxGeometry x="540" y="557" width="310" height="123" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-80" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;arcSize=6;" parent="1" vertex="1"> + <mxGeometry x="540" y="557" width="420" height="123" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-81" value="LDAP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-96" target="FWEJ_FGA9GBXbfwohBE8-104"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-81" value="LDAP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-96" target="FWEJ_FGA9GBXbfwohBE8-104" edge="1"> <mxGeometry x="-0.2381" relative="1" as="geometry"> <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-82" value="data-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-82" value="data-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> <mxGeometry x="352.5" y="658" width="85" height="20" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-83" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=0;exitDx=0;exitDy=0;startArrow=classic;startFill=1;endArrow=none;endFill=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-85" target="FWEJ_FGA9GBXbfwohBE8-92"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-83" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=0;exitDx=0;exitDy=0;startArrow=classic;startFill=1;endArrow=none;endFill=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-85" target="FWEJ_FGA9GBXbfwohBE8-92" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-84" value="AMQP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-83"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-84" value="AMQP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-83" vertex="1" connectable="0"> <mxGeometry x="-0.0476" y="-1" relative="1" as="geometry"> <mxPoint x="-1" y="-4" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-85" value="Data Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-85" value="Data Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> <mxGeometry x="330" y="504" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-86" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-85" target="FWEJ_FGA9GBXbfwohBE8-137"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-86" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-85" target="FWEJ_FGA9GBXbfwohBE8-137" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-87" value="JDBC" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-86"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-87" value="JDBC" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-86" vertex="1" connectable="0"> <mxGeometry x="0.3566" relative="1" as="geometry"> <mxPoint y="-11" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-88" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-92" target="FWEJ_FGA9GBXbfwohBE8-96"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-88" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-92" target="FWEJ_FGA9GBXbfwohBE8-96" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-89" value="LDAP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-88"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-89" value="LDAP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-88" vertex="1" connectable="0"> <mxGeometry x="-0.1051" y="-1" relative="1" as="geometry"> <mxPoint x="3" y="-1" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-90" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-92" target="FWEJ_FGA9GBXbfwohBE8-119"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-90" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-92" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="395" y="400" /> @@ -73,31 +73,31 @@ </Array> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-91" value="HTTP,<div>AMQP</div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-90"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-91" value="HTTP,<div>AMQP</div>" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-90" vertex="1" connectable="0"> <mxGeometry x="-0.1797" y="2" relative="1" as="geometry"> <mxPoint x="2" y="-77" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-92" value="<b>Broker Service</b><div><i>rabbitmq</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-92" value="<b>Broker Service</b><div><i>rabbitmq</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="330" y="422" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-93" value="LDAP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-96" target="FWEJ_FGA9GBXbfwohBE8-108"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-93" value="LDAP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-96" target="FWEJ_FGA9GBXbfwohBE8-108" edge="1"> <mxGeometry relative="1" as="geometry"> <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-94" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-96" target="FWEJ_FGA9GBXbfwohBE8-119"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-94" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-96" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-95" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-94"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-95" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-94" vertex="1" connectable="0"> <mxGeometry x="0.125" relative="1" as="geometry"> <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-96" value="<b>Identity Service *</b><div><i>openldap</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-96" value="<b>Identity Service *</b><div><i>openldap</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="520" y="422" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-97" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-119"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-97" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="775" y="480" /> @@ -107,12 +107,12 @@ </Array> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-98" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-97"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-98" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-97" vertex="1" connectable="0"> <mxGeometry x="0.7012" y="1" relative="1" as="geometry"> <mxPoint x="1" y="2" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-99" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;jumpStyle=arc;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-85"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-99" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=0;exitDx=0;exitDy=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;jumpStyle=arc;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-85" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="743" y="490" /> @@ -120,63 +120,63 @@ </Array> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-100" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-99"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-100" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-99" vertex="1" connectable="0"> <mxGeometry x="0.3494" relative="1" as="geometry"> <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-101" value="Metadata Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-101" value="Metadata Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> <mxGeometry x="710" y="504" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-102" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-104" target="FWEJ_FGA9GBXbfwohBE8-101"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-102" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-104" target="FWEJ_FGA9GBXbfwohBE8-101" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-103" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-102"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-103" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-102" vertex="1" connectable="0"> <mxGeometry x="-0.1111" relative="1" as="geometry"> <mxPoint x="3" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-104" value="<b>Auth Service</b><br><i>keycloak</i>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-104" value="<b>Auth Service</b><br><i>keycloak</i>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="520" y="504" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-105" value="Search Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-105" value="Search Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> <mxGeometry x="710" y="176" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-106" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-106" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="750" y="256" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-107" value="search-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-107" value="search-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> <mxGeometry x="732.5" y="320.5" width="85" height="17" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-108" value="<b>Dashboard Service</b><div><i>grafana</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-108" value="<b>Dashboard Service</b><div><i>grafana</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="710" y="422" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-109" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-124" target="FWEJ_FGA9GBXbfwohBE8-120"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-109" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-124" target="FWEJ_FGA9GBXbfwohBE8-120" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-110" value="S3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-109"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-110" value="S3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-109" vertex="1" connectable="0"> <mxGeometry x="0.2961" y="-3" relative="1" as="geometry"> <mxPoint x="3" y="-9" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-111" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-111" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="560" y="584" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-112" value="auth-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-112" value="auth-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> <mxGeometry x="542.5" y="648" width="85" height="20" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-113" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-113" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="750" y="584" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-114" value="metadata-db" style="text;html=1;strokeColor=none;fillColor=default;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-114" value="metadata-db" style="text;html=1;strokeColor=none;fillColor=default;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" parent="1" vertex="1"> <mxGeometry x="732.5" y="649" width="85" height="17" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-115" value="HTTP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-105"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-115" value="HTTP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-105" edge="1"> <mxGeometry relative="1" as="geometry"> <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-116" value="HTTP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-124"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-116" value="HTTP" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-124" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="490" y="186" /> @@ -185,7 +185,7 @@ <mxPoint as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-117" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-123"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-117" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-123" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="480" y="196" /> @@ -193,102 +193,102 @@ </Array> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-118" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-117"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-118" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-117" vertex="1" connectable="0"> <mxGeometry x="0.5551" y="-1" relative="1" as="geometry"> <mxPoint x="1" y="-64" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-119" value="<b>Gateway Service</b><div><i>nginx</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-119" value="<b>Gateway Service</b><div><i>nginx</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="520" y="176" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-120" value="<b>Storage Service</b><div><i>seaweedfs</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-120" value="<b>Storage Service</b><div><i>seaweedfs</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="329.5" y="258" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-121" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-123" target="FWEJ_FGA9GBXbfwohBE8-120"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-121" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-123" target="FWEJ_FGA9GBXbfwohBE8-120" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-122" value="S3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-121"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-122" value="S3" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-121" vertex="1" connectable="0"> <mxGeometry x="0.0536" relative="1" as="geometry"> <mxPoint y="1" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-123" value="Analyse Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-123" value="Analyse Service" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> <mxGeometry x="330" y="340" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-124" value="<b>Upload Service</b><div><i>tusd</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-124" value="<b>Upload Service</b><div><i>tusd</i></div>" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#E6E6E6;fontColor=#000000;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="330" y="176" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-125" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-105" target="FWEJ_FGA9GBXbfwohBE8-106"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-125" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-105" target="FWEJ_FGA9GBXbfwohBE8-106" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-126" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-125"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-126" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-125" vertex="1" connectable="0"> <mxGeometry x="-0.0782" y="-1" relative="1" as="geometry"> <mxPoint x="2" y="1" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-127" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-128" target="FWEJ_FGA9GBXbfwohBE8-119"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-127" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-128" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="585" y="110" /> </Array> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-128" value="Researcher" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-128" value="Researcher" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> <mxGeometry x="520" y="69" width="30" height="60" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-129" value="Database<div>Engineer</div>" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-129" value="Database<div>Engineer</div>" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> <mxGeometry x="490" y="586" width="30" height="60" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-130" value="" style="rounded=0;whiteSpace=wrap;html=1;strokeColor=none;" vertex="1" parent="1"> - <mxGeometry x="540" y="550" width="310" height="14" as="geometry" /> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-130" value="" style="rounded=0;whiteSpace=wrap;html=1;strokeColor=none;" parent="1" vertex="1"> + <mxGeometry x="540" y="550" width="420" height="14" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-131" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-113"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-131" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-101" target="FWEJ_FGA9GBXbfwohBE8-113" edge="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="840" y="524" as="sourcePoint" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-132" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-131"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-132" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-131" vertex="1" connectable="0"> <mxGeometry x="-0.0169" y="-1" relative="1" as="geometry"> <mxPoint x="1" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-133" value="JDBC" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-104" target="FWEJ_FGA9GBXbfwohBE8-111"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-133" value="JDBC" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-104" target="FWEJ_FGA9GBXbfwohBE8-111" edge="1"> <mxGeometry relative="1" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-134" value="System<div>Engineer</div>" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-134" value="System<div>Engineer</div>" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> <mxGeometry x="662" y="571" width="30" height="60" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-135" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-135" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="339.5" y="584" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-136" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-136" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="399.5" y="584" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-137" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-137" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" parent="1" vertex="1"> <mxGeometry x="369.5" y="594" width="50" height="64" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-138" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;arcSize=6;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-138" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;arcSize=6;" parent="1" vertex="1"> <mxGeometry x="320" y="575" width="150" height="105" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-139" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;entryX=1.004;entryY=0.397;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-129" target="FWEJ_FGA9GBXbfwohBE8-138"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-139" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;dashed=1;entryX=1.004;entryY=0.397;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-129" target="FWEJ_FGA9GBXbfwohBE8-138" edge="1"> <mxGeometry relative="1" as="geometry"> <mxPoint x="460" y="616" as="targetPoint" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-140" value="User Interface" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-140" value="User Interface" style="rounded=1;whiteSpace=wrap;html=1;fontStyle=1" parent="1" vertex="1"> <mxGeometry x="710" y="340" width="130" height="40" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-141" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-142" target="FWEJ_FGA9GBXbfwohBE8-119"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-141" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-142" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="585" y="110" /> </Array> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-142" value="Machine" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" vertex="1" parent="1"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-142" value="Machine" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1"> <mxGeometry x="620" y="69" width="30" height="60" as="geometry" /> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-143" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-85" target="FWEJ_FGA9GBXbfwohBE8-119"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-143" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-85" target="FWEJ_FGA9GBXbfwohBE8-119" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="395" y="480" /> @@ -298,24 +298,24 @@ </Array> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-144" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-143"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-144" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-143" vertex="1" connectable="0"> <mxGeometry x="0.6707" relative="1" as="geometry"> <mxPoint x="-1" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-145" value="" style="endArrow=none;dashed=1;html=1;rounded=0;entryX=1;entryY=0.976;entryDx=0;entryDy=0;entryPerimeter=0;exitX=1;exitY=0.076;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-80" target="FWEJ_FGA9GBXbfwohBE8-76"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-145" value="" style="endArrow=none;dashed=1;html=1;rounded=0;entryX=1;entryY=0.976;entryDx=0;entryDy=0;entryPerimeter=0;exitX=1;exitY=0.076;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-80" target="FWEJ_FGA9GBXbfwohBE8-76" edge="1"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="810" y="570" as="sourcePoint" /> <mxPoint x="860" y="520" as="targetPoint" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-146" value="" style="endArrow=none;dashed=1;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=0;exitY=0.121;exitDx=0;exitDy=0;exitPerimeter=0;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-80" target="FWEJ_FGA9GBXbfwohBE8-130"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-146" value="" style="endArrow=none;dashed=1;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;exitX=0;exitY=0.121;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-80" target="FWEJ_FGA9GBXbfwohBE8-130" edge="1"> <mxGeometry width="50" height="50" relative="1" as="geometry"> <mxPoint x="540" y="590" as="sourcePoint" /> <mxPoint x="590" y="540" as="targetPoint" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-147" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-140"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-147" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-119" target="FWEJ_FGA9GBXbfwohBE8-140" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="683" y="196" /> @@ -323,12 +323,12 @@ </Array> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-148" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-147"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-148" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-147" vertex="1" connectable="0"> <mxGeometry x="0.0179" relative="1" as="geometry"> <mxPoint y="8" as="offset" /> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-149" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;endArrow=none;endFill=0;" edge="1" parent="1" source="FWEJ_FGA9GBXbfwohBE8-105" target="FWEJ_FGA9GBXbfwohBE8-101"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-149" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;jumpStyle=arc;startArrow=classic;startFill=1;endArrow=none;endFill=0;" parent="1" source="FWEJ_FGA9GBXbfwohBE8-105" target="FWEJ_FGA9GBXbfwohBE8-101" edge="1"> <mxGeometry relative="1" as="geometry"> <Array as="points"> <mxPoint x="697" y="206" /> @@ -336,11 +336,28 @@ </Array> </mxGeometry> </mxCell> - <mxCell id="FWEJ_FGA9GBXbfwohBE8-150" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FWEJ_FGA9GBXbfwohBE8-149"> + <mxCell id="FWEJ_FGA9GBXbfwohBE8-150" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="FWEJ_FGA9GBXbfwohBE8-149" vertex="1" connectable="0"> <mxGeometry x="-0.5289" y="-1" relative="1" as="geometry"> <mxPoint x="4" y="34" as="offset" /> </mxGeometry> </mxCell> + <mxCell id="a_cl7nsyDpLQFaXOHeFD-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="a_cl7nsyDpLQFaXOHeFD-3" target="FWEJ_FGA9GBXbfwohBE8-108"> + <mxGeometry relative="1" as="geometry" /> + </mxCell> + <mxCell id="a_cl7nsyDpLQFaXOHeFD-6" value="HTTP" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="a_cl7nsyDpLQFaXOHeFD-5"> + <mxGeometry x="-0.1222" relative="1" as="geometry"> + <mxPoint as="offset" /> + </mxGeometry> + </mxCell> + <mxCell id="a_cl7nsyDpLQFaXOHeFD-3" value="" style="shape=cylinder3;whiteSpace=wrap;html=1;boundedLbl=1;backgroundOutline=1;size=8.600000000000023;fillColor=#E6E6E6;strokeColor=#000000;" vertex="1" parent="1"> + <mxGeometry x="900" y="410" width="50" height="64" as="geometry" /> + </mxCell> + <mxCell id="a_cl7nsyDpLQFaXOHeFD-4" value="metric-db" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;spacing=-1;" vertex="1" parent="1"> + <mxGeometry x="882.5" y="474" width="85" height="17" as="geometry" /> + </mxCell> + <mxCell id="a_cl7nsyDpLQFaXOHeFD-7" value="* omitted edges for all services to metric-db" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1"> + <mxGeometry x="727" y="683" width="233" height="11" as="geometry" /> + </mxCell> </root> </mxGraphModel> </diagram> diff --git a/.docs/kubernetes.md b/.docs/kubernetes.md index 0539dc542e..2384f61d04 100644 --- a/.docs/kubernetes.md +++ b/.docs/kubernetes.md @@ -20,36 +20,6 @@ helm upgrade --install dbrepo \ --cleanup-on-fail ``` -This chart is also on [Artifact Hub](https://artifacthub.io/packages/helm/dbrepo/dbrepo) with a full documentation -about values, etc. Before installing, you need to change credentials, e.g. the Broker Service administrator user -password: - -```yaml title="values.yaml" -brokerservice: - ... - auth: - ... - username: broker - password: broker - passwordHash: 1gwjNNTBPKLgyzbsUykfR0JIFC6nNqbNJaxzZ14uPT8JGcTZ -``` - -The `brokerservice.auth.passwordHash` field is the RabbitMQ SHA512-hash of the `brokerservice.auth.password` field and -can be obtained with -the [`generate-rabbitmq-pw.sh`](https://gitlab.phaidra.org/fair-data-austria-db-repository/fda-services/-/blob/release-1.4.7/helm/dbrepo/hack/generate-rabbitmq-pw.sh) -script: - -```console -$ ./generate-rabbitmq-pw.sh my_password -klPdmv4dgnRH64czHolIHAfXvc0G9hc24FQmPlI6eeI1NOf9 -``` - -The script needs the package `xxd` for generation of the random salt. If you don't have `xxd` installed, install it: - -* Debian/Ubuntu: `apt install xxd` -* Windows: `choco install xxd` -* MacOS: `brew install coreutils` - ## Prerequisites * Kubernetes 1.24+ @@ -58,9 +28,7 @@ The script needs the package `xxd` for generation of the random salt. If you don ## Limitations -1. MariaDB Galera does not (yet) support XA-transactions required by the authentication service (=Keycloak). Therefore - only a single MariaDB pod can be deployed at once for the Auth database. -2. The entire Helm deployment is rootless (=`runAsNonRoot=true`) except for +1. The entire Helm deployment is rootless (=`runAsNonRoot=true`) except for the [Storage Service](../api/storage-service) which still requires a root user. !!! question "Do you miss functionality? Do these limitations affect you?" diff --git a/dbrepo-analyse-service/.gitignore b/dbrepo-analyse-service/.gitignore index 4ae9f6930d..d339f8575c 100644 --- a/dbrepo-analyse-service/.gitignore +++ b/dbrepo-analyse-service/.gitignore @@ -17,6 +17,12 @@ venv/ .venv/ env* +# Libraries +./lib/dbrepo-1.4.4* +./lib/dbrepo-1.4.5* +./lib/dbrepo-1.4.6* +./lib/dbrepo-1.4.7rc* + # LLM *.bin diff --git a/dbrepo-analyse-service/Pipfile.lock b/dbrepo-analyse-service/Pipfile.lock index 681bdc8a9b..91f5b55d64 100644 --- a/dbrepo-analyse-service/Pipfile.lock +++ b/dbrepo-analyse-service/Pipfile.lock @@ -190,20 +190,20 @@ }, "boto3": { "hashes": [ - "sha256:234a475fe56b65e99b4f5cfff50adaac6b23d39558d6b55137bbf1e50dd0ef08", - "sha256:90c8cddc4a08c8040057ad44c7468ff82fea9fe8b6517db5ff01a9b2900299cc" + "sha256:5970b62c1ec8177501e02520f0d41839ca5fc549b30bac4e8c0c0882ae776217", + "sha256:670f811c65e3c5fe4ed8c8d69be0b44b1d649e992c0fc16de43816d1188f88f1" ], "index": "pypi", "markers": "python_version >= '3.8'", - "version": "==1.35.38" + "version": "==1.35.39" }, "botocore": { "hashes": [ - "sha256:2eb17d32fa2d3bb5d475132a83564d28e3acc2161534f24b75a54418a1d51359", - "sha256:55d9305c44e5ba29476df456120fa4fb919f03f066afa82f2ae400485e7465f4" + "sha256:781c547eb6a79c0e4b0bedd87b81fbfed957816b4841d33e20c8f1989c7c19ce", + "sha256:cb7f851933b5ccc2fba4f0a8b846252410aa0efac5bfbe93b82d10801f5f8e90" ], "markers": "python_version >= '3.8'", - "version": "==1.35.38" + "version": "==1.35.39" }, "certifi": { "hashes": [ @@ -440,7 +440,7 @@ }, "dbrepo": { "hashes": [ - "sha256:5aa92850231c25a57ffa58395e0f6bbda2818b1f0d4edd83f51fd8143d909451" + "sha256:654d487f1c0fd99b4978f5756aec4046f3e6019aeb225ecdd449768795f6e7e0" ], "markers": "python_version >= '3.11'", "path": "./lib/dbrepo-1.4.7.tar.gz" @@ -1613,7 +1613,7 @@ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version < '3.13'", + "markers": "python_version >= '3.8'", "version": "==4.12.2" }, "tzdata": { @@ -1629,7 +1629,7 @@ "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], - "markers": "python_version >= '3.10'", + "markers": "python_version >= '3.8'", "version": "==2.2.3" }, "werkzeug": { @@ -1642,101 +1642,107 @@ }, "yarl": { "hashes": [ - "sha256:047b258e00b99091b6f90355521f026238c63bd76dcf996d93527bb13320eefd", - "sha256:06ff23462398333c78b6f4f8d3d70410d657a471c2c5bbe6086133be43fc8f1a", - "sha256:07f9eaf57719d6721ab15805d85f4b01a5b509a0868d7320134371bcb652152d", - "sha256:0aa92e3e30a04f9462a25077db689c4ac5ea9ab6cc68a2e563881b987d42f16d", - "sha256:0cf21f46a15d445417de8fc89f2568852cf57fe8ca1ab3d19ddb24d45c0383ae", - "sha256:0fd7b941dd1b00b5f0acb97455fea2c4b7aac2dd31ea43fb9d155e9bc7b78664", - "sha256:147e36331f6f63e08a14640acf12369e041e0751bb70d9362df68c2d9dcf0c87", - "sha256:16a682a127930f3fc4e42583becca6049e1d7214bcad23520c590edd741d2114", - "sha256:176110bff341b6730f64a1eb3a7070e12b373cf1c910a9337e7c3240497db76f", - "sha256:19268b4fec1d7760134f2de46ef2608c2920134fb1fa61e451f679e41356dc55", - "sha256:1b16f6c75cffc2dc0616ea295abb0e1967601bd1fb1e0af6a1de1c6c887f3439", - "sha256:1bfc25aa6a7c99cf86564210f79a0b7d4484159c67e01232b116e445b3036547", - "sha256:1ca3894e9e9f72da93544f64988d9c052254a338a9f855165f37f51edb6591de", - "sha256:1dda53508df0de87b6e6b0a52d6718ff6c62a5aca8f5552748404963df639269", - "sha256:217a782020b875538eebf3948fac3a7f9bbbd0fd9bf8538f7c2ad7489e80f4e8", - "sha256:2192f718db4a8509f63dd6d950f143279211fa7e6a2c612edc17d85bf043d36e", - "sha256:29a84a46ec3ebae7a1c024c055612b11e9363a8a23238b3e905552d77a2bc51b", - "sha256:3007a5b75cb50140708420fe688c393e71139324df599434633019314ceb8b59", - "sha256:30600ba5db60f7c0820ef38a2568bb7379e1418ecc947a0f76fd8b2ff4257a97", - "sha256:337912bcdcf193ade64b9aae5a4017a0a1950caf8ca140362e361543c6773f21", - "sha256:37001e5d4621cef710c8dc1429ca04e189e572f128ab12312eab4e04cf007132", - "sha256:3d569f877ed9a708e4c71a2d13d2940cb0791da309f70bd970ac1a5c088a0a92", - "sha256:4009def9be3a7e5175db20aa2d7307ecd00bbf50f7f0f989300710eee1d0b0b9", - "sha256:46a9772a1efa93f9cd170ad33101c1817c77e0e9914d4fe33e2da299d7cf0f9b", - "sha256:47eede5d11d669ab3759b63afb70d28d5328c14744b8edba3323e27dc52d298d", - "sha256:498b3c55087b9d762636bca9b45f60d37e51d24341786dc01b81253f9552a607", - "sha256:4e0d45ebf975634468682c8bec021618b3ad52c37619e5c938f8f831fa1ac5c0", - "sha256:4f24f08b6c9b9818fd80612c97857d28f9779f0d1211653ece9844fc7b414df2", - "sha256:55c144d363ad4626ca744556c049c94e2b95096041ac87098bb363dcc8635e8d", - "sha256:582cedde49603f139be572252a318b30dc41039bc0b8165f070f279e5d12187f", - "sha256:587c3cc59bc148a9b1c07a019346eda2549bc9f468acd2f9824d185749acf0a6", - "sha256:5cd5dad8366e0168e0fd23d10705a603790484a6dbb9eb272b33673b8f2cce72", - "sha256:5d02d700705d67e09e1f57681f758f0b9d4412eeb70b2eb8d96ca6200b486db3", - "sha256:625f207b1799e95e7c823f42f473c1e9dbfb6192bd56bba8695656d92be4535f", - "sha256:659603d26d40dd4463200df9bfbc339fbfaed3fe32e5c432fe1dc2b5d4aa94b4", - "sha256:689a99a42ee4583fcb0d3a67a0204664aa1539684aed72bdafcbd505197a91c4", - "sha256:68ac1a09392ed6e3fd14be880d39b951d7b981fd135416db7d18a6208c536561", - "sha256:6a615cad11ec3428020fb3c5a88d85ce1b5c69fd66e9fcb91a7daa5e855325dd", - "sha256:73bedd2be05f48af19f0f2e9e1353921ce0c83f4a1c9e8556ecdcf1f1eae4892", - "sha256:742aef0a99844faaac200564ea6f5e08facb285d37ea18bd1a5acf2771f3255a", - "sha256:75ff4c819757f9bdb35de049a509814d6ce851fe26f06eb95a392a5640052482", - "sha256:781e2495e408a81e4eaeedeb41ba32b63b1980dddf8b60dbbeff6036bcd35049", - "sha256:7a9f917966d27f7ce30039fe8d900f913c5304134096554fd9bea0774bcda6d1", - "sha256:7e2637d75e92763d1322cb5041573279ec43a80c0f7fbbd2d64f5aee98447b17", - "sha256:8089d4634d8fa2b1806ce44fefa4979b1ab2c12c0bc7ef3dfa45c8a374811348", - "sha256:816d24f584edefcc5ca63428f0b38fee00b39fe64e3c5e558f895a18983efe96", - "sha256:8385ab36bf812e9d37cf7613999a87715f27ef67a53f0687d28c44b819df7cb0", - "sha256:85cb3e40eaa98489f1e2e8b29f5ad02ee1ee40d6ce6b88d50cf0f205de1d9d2c", - "sha256:8648180b34faaea4aa5b5ca7e871d9eb1277033fa439693855cf0ea9195f85f1", - "sha256:8892fa575ac9b1b25fae7b221bc4792a273877b9b56a99ee2d8d03eeb3dbb1d2", - "sha256:88c7d9d58aab0724b979ab5617330acb1c7030b79379c8138c1c8c94e121d1b3", - "sha256:8a2f8fb7f944bcdfecd4e8d855f84c703804a594da5123dd206f75036e536d4d", - "sha256:8f4e475f29a9122f908d0f1f706e1f2fc3656536ffd21014ff8a6f2e1b14d1d8", - "sha256:8f50eb3837012a937a2b649ec872b66ba9541ad9d6f103ddcafb8231cfcafd22", - "sha256:91d875f75fabf76b3018c5f196bf3d308ed2b49ddcb46c1576d6b075754a1393", - "sha256:94b2bb9bcfd5be9d27004ea4398fb640373dd0c1a9e219084f42c08f77a720ab", - "sha256:9557c9322aaa33174d285b0c1961fb32499d65ad1866155b7845edc876c3c835", - "sha256:95e16e9eaa2d7f5d87421b8fe694dd71606aa61d74b824c8d17fc85cc51983d1", - "sha256:96952f642ac69075e44c7d0284528938fdff39422a1d90d3e45ce40b72e5e2d9", - "sha256:985623575e5c4ea763056ffe0e2d63836f771a8c294b3de06d09480538316b13", - "sha256:99ff3744f5fe48288be6bc402533b38e89749623a43208e1d57091fc96b783b9", - "sha256:9abe80ae2c9d37c17599557b712e6515f4100a80efb2cda15f5f070306477cd2", - "sha256:a152751af7ef7b5d5fa6d215756e508dd05eb07d0cf2ba51f3e740076aa74373", - "sha256:a2e4725a08cb2b4794db09e350c86dee18202bb8286527210e13a1514dc9a59a", - "sha256:a56fbe3d7f3bce1d060ea18d2413a2ca9ca814eea7cedc4d247b5f338d54844e", - "sha256:ab3abc0b78a5dfaa4795a6afbe7b282b6aa88d81cf8c1bb5e394993d7cae3457", - "sha256:b03384eed107dbeb5f625a99dc3a7de8be04fc8480c9ad42fccbc73434170b20", - "sha256:b0547ab1e9345dc468cac8368d88ea4c5bd473ebc1d8d755347d7401982b5dd8", - "sha256:b4c1ecba93e7826dc71ddba75fb7740cdb52e7bd0be9f03136b83f54e6a1f511", - "sha256:b693c63e7e64b524f54aa4888403c680342d1ad0d97be1707c531584d6aeeb4f", - "sha256:b6d0147574ce2e7b812c989e50fa72bbc5338045411a836bd066ce5fc8ac0bce", - "sha256:b9cfef3f14f75bf6aba73a76caf61f9d00865912a04a4393c468a7ce0981b519", - "sha256:b9f805e37ed16cc212fdc538a608422d7517e7faf539bedea4fe69425bc55d76", - "sha256:bab03192091681d54e8225c53f270b0517637915d9297028409a2a5114ff4634", - "sha256:bc24f968b82455f336b79bf37dbb243b7d76cd40897489888d663d4e028f5069", - "sha256:c14b504a74e58e2deb0378b3eca10f3d076635c100f45b113c18c770b4a47a50", - "sha256:c2089a9afef887664115f7fa6d3c0edd6454adaca5488dba836ca91f60401075", - "sha256:c8ed4034f0765f8861620c1f2f2364d2e58520ea288497084dae880424fc0d9f", - "sha256:cd2660c01367eb3ef081b8fa0a5da7fe767f9427aa82023a961a5f28f0d4af6c", - "sha256:d8361c7d04e6a264481f0b802e395f647cd3f8bbe27acfa7c12049efea675bd1", - "sha256:d9baec588f015d0ee564057aa7574313c53a530662ffad930b7886becc85abdf", - "sha256:dbd9ff43a04f8ffe8a959a944c2dca10d22f5f99fc6a459f49c3ebfb409309d9", - "sha256:e3f8bfc1db82589ef965ed234b87de30d140db8b6dc50ada9e33951ccd8ec07a", - "sha256:e6a2c5c5bb2556dfbfffffc2bcfb9c235fd2b566d5006dfb2a37afc7e3278a07", - "sha256:e749af6c912a7bb441d105c50c1a3da720474e8acb91c89350080dd600228f0e", - "sha256:e85d86527baebb41a214cc3b45c17177177d900a2ad5783dbe6f291642d4906f", - "sha256:ee2c68e4f2dd1b1c15b849ba1c96fac105fca6ffdb7c1e8be51da6fabbdeafb9", - "sha256:f3ab950f8814f3b7b5e3eebc117986f817ec933676f68f0a6c5b2137dd7c9c69", - "sha256:f4f4547944d4f5cfcdc03f3f097d6f05bbbc915eaaf80a2ee120d0e756de377d", - "sha256:f72a0d746d38cb299b79ce3d4d60ba0892c84bbc905d0d49c13df5bace1b65f8", - "sha256:fc2c80bc87fba076e6cbb926216c27fba274dae7100a7b9a0983b53132dd99f2", - "sha256:fe4d2536c827f508348d7b40c08767e8c7071614250927233bf0c92170451c0a" + "sha256:0127bc2ea72c1eaae6808ace661f0edf222f32ffa987d37f2dbb4798288f2656", + "sha256:0358b697abdf1f2d68038bd02ef8ddcc4813835744f79c755f8743aa485585e7", + "sha256:06306c74f0775621a70fa5acd292119bbb6961d1f9a5f3d657a4c8c15b86f7b9", + "sha256:06b5b462cadf59c1df28ffbb0a3971fa16b60cf0c9d59a38bf5679a986d18685", + "sha256:097094a979af7b31520517c59179f6817b8426724343cecbec0eb3af1f8fb6cf", + "sha256:0c791a2d42da20ac568e5c0cc9b8af313188becd203a936ad959b578dafbcebb", + "sha256:1656a8b531a96427f26f498b7d0f19931166ff30e4344eca99bdb27faca14fc5", + "sha256:18614630533ac37ec373bd8035aec8fa4dd9aedac641209c06de7e082622ff77", + "sha256:1e5fa4c4e55cdacef1844f609bc9a02c8cd29c324a71ca1d3ee454701d4bb496", + "sha256:1edaf4171fc1582352ac5d9b2783966fa0f4ff86187279ef2a491613d23b894a", + "sha256:2124c642b8cc9b68e5981e429842dadc32bb850b010cccec9d24236253a19f60", + "sha256:229f222bb47cd7ab225648efd1ae47fe6943f18e4c91bce66471faf09fe33128", + "sha256:2429a651a2191c3fb8c9de21546c6046da539034d51dcb8df52302748004593d", + "sha256:25a4e29ee758596b2a0daffa4814714e9b464077ca862baf78ed0e8698e46b61", + "sha256:27c323b28723faed046f906c70466144c4dd12046a0128a301b29a65cfeff758", + "sha256:2add8ed2acf42398dfaa7dffd32e4d18ffbae341d62c8d4765bd9929336379b5", + "sha256:2bece7fdc13e23db005879b67190db0d397f6ba89c81dc7e3c77e9f5819aff7f", + "sha256:2eafb4e92f72a3b6c27f1d5e921d046e2728850af8887f86857c3fe868a5b5c0", + "sha256:32840ff92c713053591ff0e66845d4e9f4bea8fd5fba3da00f8d92e77722f24e", + "sha256:33896afca6fb4e1988c099534c52823870dfc8730bc6f96a3831f24c1e0ab814", + "sha256:350b468a217d433cbb4482e9414a14dfd360a3d5ab92013175925abb234364cc", + "sha256:38cab8f91b1085f1fd0765d40c46c8f43282f109018d5fcd017c46ac3eaba0cf", + "sha256:3e24a778470f3a9e9c11250d09daf5dea93369bc51aefca6605dbc963737a117", + "sha256:4224bbbc8a2e9b9a3828d36c1bab7458441d7fb9fb3af321eb735732ba8ee89d", + "sha256:4424082edff76fe46ff08851e91865097c0ad780fa79b87063dc5d5b80efc9d6", + "sha256:454707fb16f180984da6338d1f51897f0b8d8c4c2e0592d9d1e9fa02a5bb8218", + "sha256:4b1ab96a1ac91bd1233706d638ade35f663684deaa4e5e5f190858cba044afb9", + "sha256:4c5ff3e7609c214667c7d7e00d5f4f3576fefde47ebcb7e492c015117dafebbf", + "sha256:5107d89c9edec6ee077970a95fb9eeb4776ea8c2337b6a39c0ade9a58f50f3e4", + "sha256:5156c12a97405339ec93facbc7860566db381af2de1bec338195563fb64f37ef", + "sha256:553a1e3537aeeb29c0eb29ef28b80e0e801697fa71d96ac60675b284ff8e582a", + "sha256:5e1cc7823f43781390965c4762b54262cfcf76b6f152e489d00a5a1ac63063e4", + "sha256:5eef9804e65eb292e9c5587e88fe6a27a11f121d358312ac47211e8f42876751", + "sha256:6237637b496bc04819190e724a4e61ff2f251abf432f70cf491b3bc4a3f2f253", + "sha256:627bb5bc4ed3d3ebceb9fb55717cec6cd58bb47fdb5669169ebbc248e9bf156c", + "sha256:676d7356bb30825b7dbdad4fdd7a9feac379d074e5d4a36299767d72857ded42", + "sha256:6960b0d2e713e726cb2914e3051e080b12412f70dcb8731cf7a8fb52c37931bb", + "sha256:6b93a666cd8cfd43f605d1b81a32b9e290bf45c74c2bfd51ba705449c78448c7", + "sha256:6ca160b4c649f0d56daef04751eef4571de46ed4b80f9051a87d090fef32f08e", + "sha256:70ac7893e67a81ed1346ee3e71203ca4b0c3550c005b1d1cf87bc1e61eecd04b", + "sha256:73c4af08e9bb9a9aa7df6c789b05b924b9a0c6a368bb0e418d0b85181b64b631", + "sha256:748dcacc19c69957f7063ea4fb359fa2180735b1a638c81a4a96b86a382a6f29", + "sha256:75d9762f65205a86381298eb9079f27c60b84de0c262e402dcf45c6cbc385234", + "sha256:7711d83dafe52cda16ff2dd205cd83c05e4c06d5aaac596ae2cf7d50d094a530", + "sha256:7aa9f9af452c3e8486a0b88fddd58352e6cea17b691b18861d26e46cf65ffff0", + "sha256:7f713d8f3c4e2eac0d91b741e8ef2e1082022de244685601ec83e899b445d86a", + "sha256:81edbd9bf9f25cd995e6d51c307e1d279587d40b7473e258fef6d5e548560cd2", + "sha256:83363a5789f128618041b9a737c7b146f1965abddf4294b0444591406b437c1e", + "sha256:85e273e59b8b1a5f60a89df82cddeaf918181abd7ae7a2f2f899b68b0c774ff1", + "sha256:8ad2e487824ba4cda87851a371139e255410e45d3bf2e334194789278d709cec", + "sha256:8b7f902f13a230686f01bcff17cd9ba045653069811c8fd5027f0f414b417e2f", + "sha256:8f074a24aa9a6a3d406474ec889ebb5d661f329349068e05e8dfcb3c4be67752", + "sha256:9084d99933824ed8d665f10f4ce62d08fed714e7678d5ff11a8c2c98b2dc18f9", + "sha256:928f7a61c4311f3dd003af19bb779f99683f97a0559b765c80fdb8846dab0452", + "sha256:97fcaf530318369da3cfd6ff52f5ab38daf8cb10ecee9a76efebf8031de09eef", + "sha256:994d27b24b61b1870f3571395c840433faabec5dcd239bd11ff6af7e34234bb6", + "sha256:9ae454916aa3abe28d0ef1c21ca1e8e36a14ccf52183d465dfaccffaa7ed462c", + "sha256:9fac5416c44e8e1d8ea9440096f88e1a7273257f3157184c5c715060e0c448a1", + "sha256:a2fe45c1143eefb680a4589c55e671fabd482a7f8c7791f311ea3bcc20139246", + "sha256:a3f8be3e785009ffa148e66474fea5c787ccb203b3d0bd1f22e1e22f7da0f3b3", + "sha256:a616c2e4b60cb8cdd9eb3b0c6fda4ab5f3e26244b427aaade560dcf63c5754fb", + "sha256:a94c9058c5703c172904103d7b479f7e23dd4e5f8e67b49f6cd256d35ff169cb", + "sha256:b1208f2e081d34832f509cbe311237a0543effe23d60b2fa14c0d3f86e6d1d07", + "sha256:b4b25de7e85ba90b2ff230153123b6b000a7f69c41d84a3a0dc3f878334c8509", + "sha256:bbe72c41cdd55c88b238a8925849fde4069c0cdcdef83f8d967f8f3982659326", + "sha256:c0a86dd3e85c6aa3fc73236eb5cf7ce69dd8ad7abcd23f8ae1126831c8e40c2f", + "sha256:c3b08d9e98d1a15338fcfbd52c02003704322c2d460c9b9be7df08f2952bdce6", + "sha256:c4d9c221cc8e32b14196498679bf2b324bec1d1127c4ba934d98e19298faa661", + "sha256:c4f882e42c6cea89488b9a16919edde8c0b1a98f307c05abdd3dd3bc4368af40", + "sha256:c5cc25cbd9ae01d49ac7b504ef5f3cbdcc8d139f9750dcfa0b80d405b4645cc2", + "sha256:c7f2deac59dc3e0528bdded248e637e789e5111ba1723a8d7a262eb93e133e15", + "sha256:c8b034b60e74fb29064f765851e77e5910055e1c4a3cb75c32eccf2b470fc00f", + "sha256:c9b9159eeeb7cd1c7131dc7f5878454f97a4dc20cd157e6474174ccac448b844", + "sha256:c9c405ca78c70c3599d8956e53be0c9def9c51ad949964a49ad96c79729a5b1a", + "sha256:ceb200918c9bd163bd390cc169b254b23b4be121026b003be93a4f2f5b554b4b", + "sha256:d06040266b5e6512a37b4703684d1798124764b43328254799e9678c588882a6", + "sha256:d3f5e201bd170fb97c643e84df58e221372cd053fbb291ebbd878b165ea5057e", + "sha256:d4aa7cca009817789fd5b8e52e8122f9e85dc580c88b816a93321c00a8acbced", + "sha256:d772ae3c12d3b8629db656050c86ee66924eaa98f7125a889175a59cfaafdb19", + "sha256:d816969b55a970b3accc7f9e4ea8f60043e3f7de96f21c06063d747ffc2f18ba", + "sha256:d885dcdca7bae42bc9a2f6cbf766abcb2a6cc043b1905fc3782c6ea1f74a2b95", + "sha256:db903458a457a53ee0f764ed11c5b5368398e216b442c42dca9d90fbd2bbf31c", + "sha256:dc63bb79e896d6ce6aaf672ac304b54969280e949c45727867fc154a17ec7ab2", + "sha256:dd042e6c3bf36448e3e3ed302b12ce79762480f4aff8e7a167cdf8c35dc93297", + "sha256:ddea4abc4606c10dddb70651b210b7ab5b663148d6d7bc85d76963c923629891", + "sha256:df57f3c3ef760489f2e82192e6c93286c2bc80d6d854ef940e5345ae7153cd4b", + "sha256:e1ddf05eeb422810b1aa919095db0691493442eebbf9cfb0f1e478a7b2fbdf3d", + "sha256:e2e3cb74684ff357e6b3c82dd71031d3c1fd7ee9f9b0a5205e5568c963e074f9", + "sha256:e4f64c8c52dde564bf3251b41d7a6746564b0fc0516cebe9c9e6695224440d22", + "sha256:e4f7efb38331e8327c1cc7fb2a2905a7db03d1a7fdb04706bf6465d0e44d41d4", + "sha256:e61b2019ebb5345510b833c4dd1f4afb1f0c07753f86f184c63836ffc3fb08ba", + "sha256:e7e38bf6e52797084c5c396db5bb519615727e491e9003e2449631457bf77738", + "sha256:eae041f535fe2e57681954f7cccb81854d777ce4c2a87749428ebe6c71c02ec0", + "sha256:eb964d18c01b7a1263a6f07b88d63711fcd564fc429d934279cf12f4b467bf53", + "sha256:ef780f9d480ffb423380abeb4cfcad66ecb8f93526dfa367d322fdad9ec7c25f", + "sha256:efc0430b80ed834c80c99c32946cfc6ee29dfcd7c62ad3c8f15657322ade7942", + "sha256:f2508ee2bad8381b5254eadc35d32fe800d12eb2c63b744183341f3a66e435a7", + "sha256:fee9acd5e39c8611957074dfba06552e430020eea831caf5eb2cea30f10e06bd" ], "markers": "python_version >= '3.8'", - "version": "==1.14.0" + "version": "==1.15.0" }, "zope.event": { "hashes": [ @@ -2268,7 +2274,7 @@ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], - "markers": "python_version < '3.13'", + "markers": "python_version >= '3.8'", "version": "==4.12.2" }, "urllib3": { @@ -2276,7 +2282,7 @@ "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9" ], - "markers": "python_version >= '3.10'", + "markers": "python_version >= '3.8'", "version": "==2.2.3" }, "wrapt": { diff --git a/dbrepo-analyse-service/lib/dbrepo-1.4.7.tar.gz b/dbrepo-analyse-service/lib/dbrepo-1.4.7.tar.gz index 5774a413a678f3179e5e215737c5e39f5a773ef8..936ec4dac16fe8f065ac7d37a09aedca421086a6 100644 GIT binary patch delta 31394 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 delta 31325 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 diff --git a/dbrepo-dashboard-service/dashboards/system.json b/dbrepo-dashboard-service/dashboards/system.json index 52bf6d0671..d0234fe477 100644 --- a/dbrepo-dashboard-service/dashboards/system.json +++ b/dbrepo-dashboard-service/dashboards/system.json @@ -1797,6 +1797,368 @@ ], "title": "Successful API Requests", "type": "timeseries" + }, + { + "collapsed": true, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 31, + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "blue", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 0, + "y": 41 + }, + "id": 29, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "nginx_connections_active", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Connections (Active)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "orange", + "value": 3 + }, + { + "color": "red", + "value": 5 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 4, + "y": 41 + }, + "id": 30, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "nginx_connections_waiting", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Connections (Waiting)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "description": "", + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "yellow", + "value": 0.0001 + }, + { + "color": "orange", + "value": 0.001 + }, + { + "color": "red", + "value": 0.01 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 3, + "w": 4, + "x": 8, + "y": 41 + }, + "id": 33, + "options": { + "colorMode": "background", + "graphMode": "none", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "code", + "expr": "max(rate(promhttp_metric_handler_requests_total{job=\"gateway scrape\", code!=\"200\"}[24h]))", + "fullMetaSearch": false, + "includeNullMetadata": true, + "instant": false, + "legendFormat": "__auto", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Failed Requests (24h)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 0.0001 + }, + { + "color": "orange", + "value": 0.001 + }, + { + "color": "red", + "value": 0.01 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 7, + "w": 12, + "x": 12, + "y": 41 + }, + "id": 32, + "options": { + "displayMode": "basic", + "maxVizHeight": 300, + "minVizHeight": 16, + "minVizWidth": 8, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "10.4.9", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "disableTextWrap": false, + "editorMode": "builder", + "expr": "rate(promhttp_metric_handler_requests_total{job=\"gateway scrape\", code!=\"200\"}[24h])", + "fullMetaSearch": false, + "includeNullMetadata": false, + "instant": false, + "legendFormat": "Code {{code}}", + "range": true, + "refId": "A", + "useBackend": false + } + ], + "title": "Failed Requests (24h)", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "P18F45E9DC7E75912" + }, + "gridPos": { + "h": 3, + "w": 12, + "x": 0, + "y": 44 + }, + "id": 34, + "links": [ + { + "targetBlank": true, + "title": "Documentation", + "url": "https://www.ifs.tuwien.ac.at/infrastructures/dbrepo/1.4.6/api/gateway-service/#monitoring-optional" + } + ], + "options": { + "code": { + "language": "plaintext", + "showLineNumbers": false, + "showMiniMap": false + }, + "content": "## Optional Panel\n\nActivate this panel by setting-up the Gateway Service Monitoring by clicking the link above.", + "mode": "markdown" + }, + "pluginVersion": "10.4.9", + "transparent": true, + "type": "text" + } + ], + "title": "Gateway", + "type": "row" } ], "refresh": "1m", diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java index 548558cafd..06afef015d 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java @@ -555,7 +555,7 @@ public class TableEndpoint { throws DatabaseUnavailableException, RemoteUnavailableException, TableNotFoundException, NotAllowedException, StorageUnavailableException, QueryMalformedException, SidecarExportException, StorageNotFoundException, MetadataServiceException { - log.debug("endpoint find table history, databaseId={}, tableId={}, timestamp={}", databaseId, tableId, timestamp); + log.debug("endpoint export table data, databaseId={}, tableId={}, timestamp={}", databaseId, tableId, timestamp); /* parameters */ if (timestamp == null) { timestamp = Instant.now(); diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java index a4c07c3f55..9d0bd3b6ad 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/endpoints/ViewEndpoint.java @@ -1,9 +1,12 @@ package at.tuwien.endpoints; -import at.tuwien.api.database.*; +import at.tuwien.ExportResourceDto; +import at.tuwien.api.database.ViewCreateDto; +import at.tuwien.api.database.ViewDto; import at.tuwien.api.database.internal.PrivilegedDatabaseDto; import at.tuwien.api.database.internal.PrivilegedViewDto; import at.tuwien.api.database.query.QueryResultDto; +import at.tuwien.api.database.table.internal.PrivilegedTableDto; import at.tuwien.api.error.ApiErrorDto; import at.tuwien.exception.*; import at.tuwien.gateway.MetadataServiceGateway; @@ -24,6 +27,7 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -282,4 +286,67 @@ public class ViewEndpoint { } } + @GetMapping("/{viewId}/export") + @Observed(name = "dbrepo_view_data_export") + @Operation(summary = "Get view data", + description = "Gets data from view with id as downloadable file. For tables in private databases, the user needs to have at least *READ* access to the associated database.", + security = {@SecurityRequirement(name = "basicAuth"), @SecurityRequirement(name = "bearerAuth")}) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", + description = "Exported view data", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = InputStreamResource.class))}), + @ApiResponse(responseCode = "400", + description = "Request pagination or view data select query is malformed", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "403", + description = "Export view data not allowed", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "404", + description = "Failed to find view in metadata database or export dataset", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + @ApiResponse(responseCode = "503", + description = "Failed to establish connection with the metadata service", + content = {@Content( + mediaType = "application/json", + schema = @Schema(implementation = ApiErrorDto.class))}), + }) + public ResponseEntity<InputStreamResource> exportDataset(@NotBlank @PathVariable("databaseId") Long databaseId, + @NotBlank @PathVariable("viewId") Long viewId, + Principal principal) + throws DatabaseUnavailableException, RemoteUnavailableException, ViewNotFoundException, + NotAllowedException, MetadataServiceException, StorageUnavailableException, QueryMalformedException, + SidecarExportException, StorageNotFoundException { + log.debug("endpoint export view data, databaseId={}, viewId={}", databaseId, viewId); + /* parameters */ + final PrivilegedViewDto view = metadataServiceGateway.getViewById(databaseId, viewId); + if (!view.getIsPublic()) { + if (principal == null) { + log.error("Failed to export private view: principal is null"); + throw new NotAllowedException("Failed to export private view: principal is null"); + } + metadataServiceGateway.getAccess(databaseId, UserUtil.getId(principal)); + } + try { + final HttpHeaders headers = new HttpHeaders(); + final ExportResourceDto resource = viewService.exportDataset(view); + headers.add("Content-Disposition", "attachment; filename=\"" + resource.getFilename() + "\""); + log.trace("export table resulted in resource {}", resource); + return ResponseEntity.ok() + .headers(headers) + .body(resource.getResource()); + + } catch (SQLException e) { + log.error("Failed to establish connection to database: {}", e.getMessage()); + throw new DatabaseUnavailableException("Failed to establish connection to database", e); + } + } + } diff --git a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java index 3cbb865293..1c6adfd6a5 100644 --- a/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java +++ b/dbrepo-data-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java @@ -1,8 +1,6 @@ package at.tuwien.validation; import at.tuwien.api.database.AccessTypeDto; -import at.tuwien.api.database.DatabaseAccessDto; -import at.tuwien.api.database.DatabaseDto; import at.tuwien.config.QueryConfig; import at.tuwien.exception.NotAllowedException; import at.tuwien.exception.PaginationException; diff --git a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java index 85e2b80711..23503384b6 100644 --- a/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java +++ b/dbrepo-data-service/rest-service/src/test/java/at/tuwien/service/SchemaServiceIntegrationTest.java @@ -167,7 +167,7 @@ public class SchemaServiceIntegrationTest extends AbstractUnitTest { final List<ColumnDto> columns = response.getColumns(); assertNotNull(columns); assertEquals(5, columns.size()); - assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 19L, 0L, false, null); + assertColumn(columns.get(0), null, null, DATABASE_1_ID, "id", "id", ColumnTypeDto.BIGINT, 20L, 0L, false, null); assertColumn(columns.get(1), null, null, DATABASE_1_ID, "date", "date", ColumnTypeDto.DATE, null, null, false, null); assertColumn(columns.get(2), null, null, DATABASE_1_ID, "location", "location", ColumnTypeDto.VARCHAR, 255L, null, true, "Closest city"); assertColumn(columns.get(3), null, null, DATABASE_1_ID, "mintemp", "mintemp", ColumnTypeDto.DOUBLE, 22L, null, true, null); diff --git a/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql b/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql index 10cbf85565..322e67cc07 100644 --- a/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql +++ b/dbrepo-data-service/rest-service/src/test/resources/init/weather.sql @@ -11,7 +11,7 @@ CREATE TABLE weather_location CREATE TABLE weather_aus ( - id BIGINT NOT NULL PRIMARY KEY, + id SERIAL PRIMARY KEY, `date` DATE NOT NULL, location VARCHAR(255) NULL COMMENT 'Closest city', mintemp DOUBLE PRECISION NULL, diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java index 01854e0cb7..62b529976d 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/DataMapper.java @@ -140,7 +140,6 @@ public interface DataMapper { default TableDto resultSetToTable(ResultSet resultSet, TableDto table, QueryConfig queryConfig) throws SQLException { final ColumnDto column = ColumnDto.builder() .ordinalPosition(resultSet.getInt(1) - 1) /* start at zero */ - .autoGenerated(resultSet.getString(2) != null && resultSet.getString(2).startsWith("nextval")) .isNullAllowed(resultSet.getString(3).equals("YES")) .columnType(ColumnTypeDto.valueOf(resultSet.getString(4).toUpperCase())) .d(resultSet.getString(7) != null ? resultSet.getLong(7) : null) @@ -551,7 +550,7 @@ public interface DataMapper { case TEXT, CHAR, VARCHAR, TINYTEXT, MEDIUMTEXT, LONGTEXT, ENUM, SET -> { return String.valueOf(data); } - case BIGINT -> { + case BIGINT, SERIAL -> { return new BigInteger(String.valueOf(data)); } case INT, SMALLINT, MEDIUMINT, TINYINT -> { @@ -643,7 +642,7 @@ public interface DataMapper { } ps.setString(idx, String.valueOf(value)); break; - case BIGINT: + case BIGINT, SERIAL: if (value == null) { ps.setNull(idx, Types.BIGINT); break; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java index bf0483496d..bfca2d923f 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/mapper/MariaDbMapper.java @@ -664,9 +664,6 @@ public interface MariaDbMapper { log.error("Failed to find table column {}", key); throw new IllegalArgumentException("Failed to find table column"); } - if (optional.get().getAutoGenerated()) { - return; - } statement.append(idx[0]++ == 0 ? "" : ", ") .append("`") .append(key) @@ -683,9 +680,6 @@ public interface MariaDbMapper { log.error("Failed to find table column {}", key); throw new IllegalArgumentException("Failed to find table column"); } - if (optional.get().getAutoGenerated()) { - return; - } statement.append(jdx[0]++ == 0 ? "" : ", ") .append("?"); }); @@ -717,9 +711,9 @@ public interface MariaDbMapper { statement.setNull(idx, Types.DATE); break; } - statement.setDate(idx, Date.valueOf(String.valueOf(value))); + statement.setString(idx, String.valueOf(value)); break; - case BIGINT: + case BIGINT, SERIAL: if (value == null) { statement.setNull(idx, Types.BIGINT); break; @@ -731,21 +725,21 @@ public interface MariaDbMapper { statement.setNull(idx, Types.INTEGER); break; } - statement.setLong(idx, Long.parseLong(String.valueOf(value))); + statement.setLong(idx, Integer.parseInt(String.valueOf(value))); break; case TINYINT: if (value == null) { statement.setNull(idx, Types.TINYINT); break; } - statement.setLong(idx, Long.parseLong(String.valueOf(value))); + statement.setLong(idx, Integer.parseInt(String.valueOf(value))); break; case SMALLINT: if (value == null) { statement.setNull(idx, Types.SMALLINT); break; } - statement.setLong(idx, Long.parseLong(String.valueOf(value))); + statement.setInt(idx, Integer.parseInt(String.valueOf(value))); break; case DECIMAL: if (value == null) { @@ -787,16 +781,9 @@ public interface MariaDbMapper { statement.setNull(idx, Types.TIMESTAMP); break; } - statement.setTimestamp(idx, Timestamp.valueOf(String.valueOf(value))); - break; - case TIME: - if (value == null) { - statement.setNull(idx, Types.TIME); - break; - } - statement.setTime(idx, Time.valueOf(String.valueOf(value))); + statement.setString(idx, String.valueOf(value)); break; - case YEAR: + case TIME, YEAR: if (value == null) { statement.setNull(idx, Types.TIME); break; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java index 3a94045c9d..79a23932b5 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/QueueService.java @@ -12,6 +12,7 @@ public interface QueueService { * * @param table The table. * @param data The data. + * @throws SQLException The connection to the database could not be established. */ void insert(PrivilegedTableDto table, Map<String, Object> data) throws SQLException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java index 33ef0026a8..c93186f451 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/TableService.java @@ -104,18 +104,66 @@ public interface TableService { Long getCount(PrivilegedTableDto table, Instant timestamp) throws SQLException, QueryMalformedException; + /** + * Imports a dataset by metadata into the sidecar of the target database by given table. + * @param table The table. + * @param data The dataset metadata. + * @throws SidecarImportException The sidecar of the target database failed to import the dataset. + * @throws StorageNotFoundException The storage service was not able to find the dataset for import. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws QueryMalformedException The import query is malformed, likely due to a bug in the application. + * @throws RemoteUnavailableException Failed to establish connection to the sidecar. + */ void importDataset(PrivilegedTableDto table, ImportDto data) throws SidecarImportException, StorageNotFoundException, SQLException, QueryMalformedException, RemoteUnavailableException; + /** + * Imports a dataset by metadata into the sidecar of the target database by given table. + * @param table The table. + * @param data The dataset metadata. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws TableMalformedException The tuple is malformed and does not fit the table schema. + * @throws QueryMalformedException The delete query is malformed, likely due to a bug in the application. + */ void deleteTuple(PrivilegedTableDto table, TupleDeleteDto data) throws SQLException, TableMalformedException, QueryMalformedException; + /** + * Creates a tuple in a table. + * @param table The table. + * @param data The tuple. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws QueryMalformedException The create query is malformed, likely due to a bug in the application. + * @throws TableMalformedException The tuple is malformed and does not fit the table schema. + * @throws StorageUnavailableException Failed to establish a connection with the Storage Service. + * @throws StorageNotFoundException The storage service was not able to find the dataset for import. + */ void createTuple(PrivilegedTableDto table, TupleDto data) throws SQLException, QueryMalformedException, TableMalformedException, StorageUnavailableException, StorageNotFoundException; + /** + * Updates a tuple in a table. + * @param table The table. + * @param data The tuple. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws QueryMalformedException The update query is malformed, likely due to a bug in the application. + * @throws TableMalformedException The tuple is malformed and does not fit the table schema. + */ void updateTuple(PrivilegedTableDto table, TupleUpdateDto data) throws SQLException, QueryMalformedException, TableMalformedException; + /** + * Exports a table at given system-versioning time. + * @param table The table. + * @param timestamp The system-versioning time. + * @return The exported resource. + * @throws SQLException Failed to parse SQL query, contains invalid syntax. + * @throws SidecarExportException The sidecar of the target database failed to export the dataset. + * @throws StorageNotFoundException The storage service was not able to find the dataset for export. + * @throws StorageUnavailableException Failed to establish a connection with the Storage Service. + * @throws QueryMalformedException The export query is malformed, likely due to a bug in the application. + * @throws RemoteUnavailableException Failed to establish connection to the sidecar. + */ ExportResourceDto exportDataset(PrivilegedTableDto table, Instant timestamp) throws SQLException, SidecarExportException, StorageNotFoundException, StorageUnavailableException, QueryMalformedException, RemoteUnavailableException; diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java index f4bef4f067..9151f868de 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/ViewService.java @@ -15,12 +15,12 @@ import java.util.List; public interface ViewService { /** - * - * @param database + * Gets the metadata schema for a given database. + * @param database The database. * @return The list of view metadata. - * @throws SQLException - * @throws DatabaseMalformedException - * @throws ViewNotFoundException + * @throws SQLException The connection to the data database was unsuccessful. + * @throws DatabaseMalformedException The columns that are referenced in the views are unknown to the Metadata Database. Call {@link TableService#getSchemas(PrivilegedDatabaseDto)} beforehand. + * @throws ViewNotFoundException The view with given name was not found. */ List<ViewDto> getSchemas(PrivilegedDatabaseDto database) throws SQLException, DatabaseMalformedException, ViewNotFoundException; @@ -50,11 +50,35 @@ public interface ViewService { QueryResultDto data(PrivilegedViewDto view, Instant timestamp, Long page, Long size) throws SQLException, ViewMalformedException; + /** + * Deletes a view. + * @param view The view. + * @throws SQLException The connection to the data database was unsuccessful. + * @throws ViewMalformedException The query is malformed and was rejected by the data database. + */ void delete(PrivilegedViewDto view) throws SQLException, ViewMalformedException; + /** + * Counts tuples in a view at system-versioned timestamp. + * @param view The view. + * @param timestamp The system-versioned timestamp. + * @return The number of tuples. + * @throws SQLException The connection to the data database was unsuccessful. + * @throws QueryMalformedException The query is malformed and was rejected by the data database. + */ Long count(PrivilegedViewDto view, Instant timestamp) throws SQLException, QueryMalformedException; - ExportResourceDto exportDataset(PrivilegedDatabaseDto database, ViewDto view, Instant timestamp) - throws SQLException, QueryMalformedException, SidecarExportException, StorageNotFoundException, - StorageUnavailableException, RemoteUnavailableException; + /** + * Exports view data into a dataset. + * @param view The view. + * @return The dataset. + * @throws SQLException The connection to the data database was unsuccessful. + * @throws QueryMalformedException The query is malformed and was rejected by the data database. + * @throws SidecarExportException The sidecar of the target database failed to export the dataset. + * @throws RemoteUnavailableException Failed to establish connection to the sidecar. + * @throws StorageNotFoundException The storage service was not able to find the dataset for export. + * @throws StorageUnavailableException Failed to establish a connection with the Storage Service. + */ + ExportResourceDto exportDataset(PrivilegedViewDto view) throws SQLException, QueryMalformedException, + SidecarExportException, RemoteUnavailableException, StorageNotFoundException, StorageUnavailableException; } diff --git a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java index bc7a36acd5..366cfa5faf 100644 --- a/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java +++ b/dbrepo-data-service/services/src/main/java/at/tuwien/service/impl/ViewServiceMariaDbImpl.java @@ -228,12 +228,11 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe } @Override - public ExportResourceDto exportDataset(PrivilegedDatabaseDto database, ViewDto view, Instant timestamp) - throws SQLException, QueryMalformedException, StorageNotFoundException, StorageUnavailableException, - RemoteUnavailableException, SidecarExportException { + public ExportResourceDto exportDataset(PrivilegedViewDto view) throws SQLException, QueryMalformedException, + SidecarExportException, RemoteUnavailableException, StorageNotFoundException, StorageUnavailableException { final String fileName = RandomStringUtils.randomAlphabetic(40) + ".csv"; final String filePath = s3Config.getS3FilePath() + File.separator + fileName; - final ComboPooledDataSource dataSource = getPrivilegedDataSource(database); + final ComboPooledDataSource dataSource = getPrivilegedDataSource(view.getDatabase()); final Connection connection = dataSource.getConnection(); try { /* export to data database sidecar */ @@ -242,8 +241,8 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe .map(metadataMapper::viewColumnDtoToColumnDto) .toList(); final long start = System.currentTimeMillis(); - connection.prepareStatement(mariaDbMapper.tableOrViewToRawExportQuery(database.getInternalName(), - view.getInternalName(), columns, timestamp, filePath)) + connection.prepareStatement(mariaDbMapper.tableOrViewToRawExportQuery(view.getDatabase().getInternalName(), + view.getInternalName(), columns, null, filePath)) .executeUpdate(); log.debug("executed statement in {} ms", System.currentTimeMillis() - start); connection.commit(); @@ -254,8 +253,8 @@ public class ViewServiceMariaDbImpl extends HibernateConnector implements ViewSe } finally { dataSource.close(); } - dataDatabaseSidecarGateway.exportFile(database.getContainer().getSidecarHost(), - database.getContainer().getSidecarPort(), fileName); + dataDatabaseSidecarGateway.exportFile(view.getDatabase().getContainer().getSidecarHost(), + view.getDatabase().getContainer().getSidecarPort(), fileName); httpDataAccessCounter.increment(); return storageService.getResource(fileName); } diff --git a/dbrepo-gateway-service/dbrepo.conf b/dbrepo-gateway-service/dbrepo.conf index 6cb634f9f4..6d3dce2b9e 100644 --- a/dbrepo-gateway-service/dbrepo.conf +++ b/dbrepo-gateway-service/dbrepo.conf @@ -40,6 +40,10 @@ server { listen 80 default_server; server_name _; + location = /basic_status { + stub_status; + } + location /api/search { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; @@ -93,7 +97,7 @@ server { proxy_read_timeout 90; } - location ~ /api/database/([0-9]+)/view/([0-9]+)/data { + location ~ /api/database/([0-9]+)/view/([0-9]+)/(data|export) { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; diff --git a/dbrepo-metadata-db/1_setup-schema.sql b/dbrepo-metadata-db/1_setup-schema.sql index db90e94c1f..d52cb4cae8 100644 --- a/dbrepo-metadata-db/1_setup-schema.sql +++ b/dbrepo-metadata-db/1_setup-schema.sql @@ -144,14 +144,13 @@ CREATE TABLE IF NOT EXISTS `mdb_columns` tID BIGINT UNSIGNED NOT NULL, cName VARCHAR(64), internal_name VARCHAR(64) NOT NULL, - Datatype ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), + Datatype ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','SERIAL','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), length BIGINT UNSIGNED NULL, ordinal_position INTEGER NOT NULL, index_length BIGINT UNSIGNED NULL, description VARCHAR(2048), size BIGINT UNSIGNED, d BIGINT UNSIGNED, - auto_generated BOOLEAN DEFAULT false, is_null_allowed BOOLEAN NOT NULL DEFAULT true, val_min NUMERIC NULL, val_max NUMERIC NULL, @@ -208,7 +207,7 @@ CREATE TABLE IF NOT EXISTS `mdb_columns_cat` CREATE TABLE IF NOT EXISTS `mdb_constraints_foreign_key` ( - fkid BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + fkid SERIAL, tid BIGINT UNSIGNED NOT NULL, rtid BIGINT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, @@ -245,7 +244,7 @@ CREATE TABLE IF NOT EXISTS `mdb_constraints_foreign_key_reference` CREATE TABLE IF NOT EXISTS `mdb_constraints_unique` ( - uid BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + uid SERIAL, name VARCHAR(255) NOT NULL, tid BIGINT UNSIGNED NOT NULL, position INT NULL, @@ -362,17 +361,16 @@ CREATE TABLE IF NOT EXISTS `mdb_view_columns` ( id SERIAL, view_id BIGINT UNSIGNED NOT NULL, - dfID BIGINT UNSIGNED, name VARCHAR(64), internal_name VARCHAR(64) NOT NULL, column_type ENUM ('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR'), ordinal_position INTEGER NOT NULL, size BIGINT UNSIGNED, d BIGINT UNSIGNED, - auto_generated BOOLEAN DEFAULT false, is_null_allowed BOOLEAN NOT NULL DEFAULT true, PRIMARY KEY (id), - FOREIGN KEY (view_id) REFERENCES mdb_view (id) + FOREIGN KEY (view_id) REFERENCES mdb_view (id), + UNIQUE (view_id, internal_name) ) WITH SYSTEM VERSIONING; CREATE TABLE IF NOT EXISTS `mdb_identifiers` @@ -526,8 +524,10 @@ CREATE TABLE IF NOT EXISTS `mdb_image_types` d_default INT UNSIGNED, d_required BOOLEAN COMMENT 'When setting NULL, the service assumes the data type has no d', d_step INT UNSIGNED, - hint TEXT, + type_hint TEXT, + data_hint TEXT, documentation TEXT NOT NULL, + is_generated BOOLEAN NOT NULL, is_quoted BOOLEAN NOT NULL, is_buildable BOOLEAN NOT NULL, PRIMARY KEY (id), @@ -550,67 +550,74 @@ VALUES ('mariadb', 'docker.io', '11.1.3', 3306, 'org.hibernate.dialect.MariaDBDi 'mariadb'); INSERT INTO `mdb_image_types` (image_id, display_name, value, size_min, size_max, size_default, size_required, - size_step, d_min, d_max, d_default, d_required, d_step, hint, documentation, is_quoted, - is_buildable) -VALUES (1, 'BIGINT(size)', 'bigint', 0, null, null, false, 1, null, null, null, null, null, null, - 'https://mariadb.com/kb/en/bigint/', false, true), - (1, 'BINARY(size)', 'binary', 0, 255, 255, true, 1, null, null, null, null, null, 'size in Bytes', - 'https://mariadb.com/kb/en/binary/', false, true), - (1, 'BIT(size)', 'bit', 0, 64, null, false, 1, null, null, null, null, null, null, - 'https://mariadb.com/kb/en/bit/', false, true), - (1, 'BLOB(size)', 'blob', 0, 65535, null, false, 1, null, null, null, null, null, 'size in Bytes', - 'https://mariadb.com/kb/en/blob/', false, false), - (1, 'BOOL', 'bool', null, null, null, null, null, null, null, null, null, null, null, - 'https://mariadb.com/kb/en/bool/', false, true), - (1, 'CHAR(size)', 'char', 0, 255, 255, false, 1, null, null, null, null, null, null, - 'https://mariadb.com/kb/en/char/', false, true), + size_step, d_min, d_max, d_default, d_required, d_step, type_hint, data_hint, + documentation, is_quoted, is_buildable, is_generated) +VALUES (1, 'BIGINT(size)', 'bigint', 0, null, null, false, 1, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/bigint/', false, true, false), + (1, 'BINARY(size)', 'binary', 0, 255, 255, true, 1, null, null, null, null, null, 'size in Bytes', null, + 'https://mariadb.com/kb/en/binary/', false, true, false), + (1, 'BIT(size)', 'bit', 0, 64, null, false, 1, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/bit/', false, true, false), + (1, 'BLOB(size)', 'blob', 0, 65535, null, false, 1, null, null, null, null, null, 'size in Bytes', null, + 'https://mariadb.com/kb/en/blob/', false, false, false), + (1, 'BOOL', 'bool', null, null, null, null, null, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/bool/', false, true, false), + (1, 'CHAR(size)', 'char', 0, 255, 255, false, 1, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/char/', false, true, false), (1, 'DATE', 'date', null, null, null, null, null, null, null, null, null, null, - 'min. 1000-01-01, max. 9999-12-31', 'https://mariadb.com/kb/en/date/', true, true), + 'min. 1000-01-01, max. 9999-12-31', 'e.g. YYYY-MM-DD, YY-MM-DD, YYMMDD, YYYY/MM/DD', + 'https://mariadb.com/kb/en/date/', true, true, false), (1, 'DATETIME(fsp)', 'datetime', 0, 6, null, null, 1, null, null, null, null, null, 'fsp=microsecond precision, min. 1000-01-01 00:00:00.0, max. 9999-12-31 23:59:59.9', - 'https://mariadb.com/kb/en/datetime/', true, true), - (1, 'DECIMAL(size, d)', 'decimal', 0, 65, null, false, 1, 0, 38, null, false, null, null, - 'https://mariadb.com/kb/en/decimal/', false, true), - (1, 'DOUBLE(size, d)', 'double', null, null, null, false, null, null, null, null, false, null, null, - 'https://mariadb.com/kb/en/double/', false, true), + 'e.g. YYYY-MM-DD HH:MM:SS, YY-MM-DD HH:MM:SS, YYYYMMDDHHMMSS, YYMMDDHHMMSS, YYYYMMDD, YYMMDD', + 'https://mariadb.com/kb/en/datetime/', true, true, false), + (1, 'DECIMAL(size, d)', 'decimal', 0, 65, null, false, 1, 0, 38, null, false, null, null, null, + 'https://mariadb.com/kb/en/decimal/', false, true, false), + (1, 'DOUBLE(size, d)', 'double', null, null, null, false, null, null, null, null, false, null, null, null, + 'https://mariadb.com/kb/en/double/', false, true, false), (1, 'ENUM(v1,v2,...)', 'enum', null, null, null, null, null, null, null, null, null, null, null, - 'https://mariadb.com/kb/en/enum/', true, true), - (1, 'FLOAT(size)', 'float', null, null, null, false, null, null, null, null, null, null, null, - 'https://mariadb.com/kb/en/float/', false, true), - (1, 'INT(size)', 'int', null, null, null, false, null, null, null, null, null, null, 'size in Bytes', - 'https://mariadb.com/kb/en/int/', false, true), - (1, 'LONGBLOB', 'longblob', null, null, null, null, null, null, null, null, null, null, 'max. 3.999 GiB', - 'https://mariadb.com/kb/en/longblob/', false, true), - (1, 'LONGTEXT', 'longtext', null, null, null, null, null, null, null, null, null, null, 'max. 3.999 GiB', - 'https://mariadb.com/kb/en/longtext/', true, true), + 'e.g. value1, value2, ...', 'https://mariadb.com/kb/en/enum/', true, true, false), + (1, 'FLOAT(size)', 'float', null, null, null, false, null, null, null, null, null, null, null, null, + 'https://mariadb.com/kb/en/float/', false, true, false), + (1, 'INT(size)', 'int', null, null, null, false, null, null, null, null, null, null, 'size in Bytes', null, + 'https://mariadb.com/kb/en/int/', false, true, false), + (1, 'LONGBLOB', 'longblob', null, null, null, null, null, null, null, null, null, null, 'max. 3.999 GiB', null, + 'https://mariadb.com/kb/en/longblob/', false, true, false), + (1, 'LONGTEXT', 'longtext', null, null, null, null, null, null, null, null, null, null, 'max. 3.999 GiB', null, + 'https://mariadb.com/kb/en/longtext/', true, true, false), (1, 'MEDIUMBLOB', 'mediumblob', null, null, null, null, null, null, null, null, null, null, 'max. 15.999 MiB', - 'https://mariadb.com/kb/en/mediumblob/', false, true), - (1, 'MEDIUMINT', 'mediumint', null, null, null, null, null, null, null, null, null, null, 'size in Bytes', - 'https://mariadb.com/kb/en/mediumint/', false, true), + null, 'https://mariadb.com/kb/en/mediumblob/', false, true, false), + (1, 'MEDIUMINT', 'mediumint', null, null, null, null, null, null, null, null, null, null, 'size in Bytes', null, + 'https://mariadb.com/kb/en/mediumint/', false, true, false), (1, 'MEDIUMTEXT', 'mediumtext', null, null, null, null, null, null, null, null, null, null, 'size in Bytes', - 'https://mariadb.com/kb/en/mediumtext/', true, true), + null, 'https://mariadb.com/kb/en/mediumtext/', true, true, false), + (1, 'SERIAL', 'serial', null, null, null, null, null, null, null, null, null, null, null, + null, 'https://mariadb.com/kb/en/bigint/', true, true, true), (1, 'SET(v1,v2,...)', 'set', null, null, null, null, null, null, null, null, null, null, null, - 'https://mariadb.com/kb/en/set/', true, true), + 'e.g. value1, value2, ...', 'https://mariadb.com/kb/en/set/', true, true, false), (1, 'SMALLINT(size)', 'smallint', 0, null, null, false, null, null, null, null, null, null, 'size in Bytes', - 'https://mariadb.com/kb/en/smallint/', false, true), - (1, 'TEXT(size)', 'text', 0, null, null, false, null, null, null, null, null, null, 'size in Bytes', - 'https://mariadb.com/kb/en/text/', true, true), + null, 'https://mariadb.com/kb/en/smallint/', false, true, false), + (1, 'TEXT(size)', 'text', 0, null, null, false, null, null, null, null, null, null, 'size in Bytes', null, + 'https://mariadb.com/kb/en/text/', true, true, false), (1, 'TIME(fsp)', 'time', 0, 6, 0, false, null, null, null, null, null, null, - 'fsp=microsecond precision, min. 0, max. 6', 'https://mariadb.com/kb/en/time/', true, true), + 'fsp=microsecond precision, min. 0, max. 6', 'e.g. HH:MM:SS, HH:MM, HHMMSS, H:M:S', + 'https://mariadb.com/kb/en/time/', true, true, false), (1, 'TIMESTAMP(fsp)', 'timestamp', 0, 6, 0, false, null, null, null, null, null, null, - 'fsp=microsecond precision, min. 0, max. 6', 'https://mariadb.com/kb/en/timestamp/', true, true), - (1, 'TINYBLOB', 'tinyblob', null, null, null, null, null, null, null, null, null, null, - 'fsp=microsecond precision, min. 0, max. 6', 'https://mariadb.com/kb/en/timestamp/', false, true), - (1, 'TINYINT(size)', 'tinyint', 0, null, null, false, null, null, null, null, null, null, - 'size in Bytes', 'https://mariadb.com/kb/en/tinyint/', false, true), - (1, 'TINYTEXT', 'tinytext', null, null, null, null, null, null, null, null, null, null, - 'max. 255 characters', 'https://mariadb.com/kb/en/tinytext/', true, true), - (1, 'YEAR', 'year', 2, 4, null, false, 2, null, null, null, null, null, 'min. 1901, max. 2155', - 'https://mariadb.com/kb/en/year/', false, true), - (1, 'VARBINARY(size)', 'varbinary', 0, null, null, true, null, null, null, null, null, null, - null, 'https://mariadb.com/kb/en/varbinary/', false, true), - (1, 'VARCHAR(size)', 'varchar', 0, 65532, 255, true, null, null, null, null, null, null, - null, 'https://mariadb.com/kb/en/varchar/', false, true); + 'fsp=microsecond precision, min. 0, max. 6', + 'e.g. YYYY-MM-DD HH:MM:SS, YY-MM-DD HH:MM:SS, YYYYMMDDHHMMSS, YYMMDDHHMMSS, YYYYMMDD, YYMMDD', + 'https://mariadb.com/kb/en/timestamp/', true, true, false), + (1, 'TINYBLOB', 'tinyblob', null, null, null, null, null, null, null, null, null, null, null, + 'fsp=microsecond precision, min. 0, max. 6', 'https://mariadb.com/kb/en/timestamp/', false, true, false), + (1, 'TINYINT(size)', 'tinyint', 0, null, null, false, null, null, null, null, null, null, null, + 'size in Bytes', 'https://mariadb.com/kb/en/tinyint/', false, true, false), + (1, 'TINYTEXT', 'tinytext', null, null, null, null, null, null, null, null, null, null, null, + 'max. 255 characters', 'https://mariadb.com/kb/en/tinytext/', true, true, false), + (1, 'YEAR', 'year', 2, 4, null, false, 2, null, null, null, null, null, 'min. 1901, max. 2155', 'e.g. YYYY, YY', + 'https://mariadb.com/kb/en/year/', false, true, false), + (1, 'VARBINARY(size)', 'varbinary', 0, null, null, true, null, null, null, null, null, null, null, + null, 'https://mariadb.com/kb/en/varbinary/', false, true, false), + (1, 'VARCHAR(size)', 'varchar', 0, 65532, 255, true, null, null, null, null, null, null, null, + null, 'https://mariadb.com/kb/en/varchar/', false, true, false); INSERT INTO `mdb_ontologies` (prefix, uri, uri_pattern, sparql_endpoint, rdf_path) @@ -629,4 +636,4 @@ VALUES ('om', 'http://www.ontology-of-units-of-measure.org/resource/om-2/', ('owl', 'http://www.w3.org/2002/07/owl#', null, null, null), ('prov', 'http://www.w3.org/ns/prov#', null, null, null), ('db', 'http://dbpedia.org', 'http://dbpedia.org/ontology/.*', 'http://dbpedia.org/sparql', null); -COMMIT; +COMMIT; \ No newline at end of file diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/DataTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/DataTypeDto.java index cd31aa2255..312dcf9984 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/DataTypeDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/container/image/DataTypeDto.java @@ -18,23 +18,27 @@ public class DataTypeDto { @NotBlank @JsonProperty("display_name") - @Schema(example = "BIGINT") + @Schema(example = "TIME(fsp)") private String displayName; @NotBlank - @Schema(example = "bigint") + @Schema(example = "time") private String value; @JsonProperty("size_min") + @Schema(example = "0") private Integer sizeMin; @JsonProperty("size_max") + @Schema(example = "6") private Integer sizeMax; @JsonProperty("size_default") + @Schema(example = "0") private Integer sizeDefault; @JsonProperty("size_required") + @Schema(example = "false") private Boolean sizeRequired; @JsonProperty("d_min") @@ -50,17 +54,25 @@ public class DataTypeDto { private Boolean dRequired; @NotNull - @Schema(example = "https://mariadb.com/kb/en/bigint/") + @Schema(example = "https://mariadb.com/kb/en/time/") private String documentation; + @JsonProperty("data_hint") + @Schema(example = "e.g. HH:MM:SS, HH:MM, HHMMSS, H:M:S") + private String dataHint; + + @JsonProperty("type_hint") + @Schema(example = "fsp=microsecond precision, min. 0, max. 6") + private String typeHint; + @NotNull - @Schema(description = "frontend needs to quote this data type") @JsonProperty("is_quoted") + @Schema(example = "false", description = "frontend needs to quote this data type") private Boolean quoted; @NotNull @JsonProperty("is_buildable") - @Schema(description = "frontend can build this data type") + @Schema(example = "true", description = "frontend can build this data type") private Boolean buildable; } diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java index 75b0a3d684..613f9c5e71 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/ViewColumnDto.java @@ -43,9 +43,6 @@ public class ViewColumnDto { @Schema(example = "mdb_date") private String internalName; - @Schema - private String alias; - @NotNull @JsonProperty("auto_generated") @Schema(example = "false") diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java index 4e95fefc3e..92092fca33 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnDto.java @@ -58,11 +58,6 @@ public class ColumnDto { @Schema private String alias; - @NotNull - @JsonProperty("auto_generated") - @Schema(example = "false") - private Boolean autoGenerated; - @JsonProperty("index_length") private Long indexLength; diff --git a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java index 676600c6ff..d44b25b84e 100644 --- a/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java +++ b/dbrepo-metadata-service/api/src/main/java/at/tuwien/api/database/table/columns/ColumnTypeDto.java @@ -49,6 +49,9 @@ public enum ColumnTypeDto { @JsonProperty("set") SET("set"), + @JsonProperty("serial") + SERIAL("serial"), + @JsonProperty("bit") BIT("bit"), diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/DataType.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/DataType.java index 8333470ad3..a98da8d530 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/DataType.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/container/image/DataType.java @@ -5,8 +5,6 @@ import lombok.*; import org.hibernate.annotations.GenericGenerator; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import java.util.List; - @Data @Entity @Builder @@ -58,6 +56,12 @@ public class DataType { @Column(nullable = false) private String documentation; + @Column(name = "type_hint") + private String typeHint; + + @Column(name = "data_hint") + private String dataHint; + @Column(name = "is_quoted", nullable = false) private Boolean quoted; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/Database.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/Database.java index 2e154b8697..17b8308bba 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/Database.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/Database.java @@ -122,11 +122,12 @@ public class Database implements Serializable { private List<Table> tables; @ToString.Exclude - @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, mappedBy = "database", orphanRemoval = true) + @OrderBy("id DESC") + @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL, CascadeType.PERSIST}, mappedBy = "database", orphanRemoval = true) private List<View> views; @ToString.Exclude - @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, mappedBy = "database", orphanRemoval = true) + @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.ALL, CascadeType.PERSIST}, mappedBy = "database", orphanRemoval = true) private List<DatabaseAccess> accesses; @Column(nullable = false) diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/View.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/View.java index 44ffab2959..28f2ec69c2 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/View.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/View.java @@ -97,7 +97,7 @@ public class View { @ToString.Exclude @OnDelete(action = OnDeleteAction.CASCADE) @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, mappedBy = "view") - @OrderColumn(name = "ordinalPosition") + @OrderBy("ordinalPosition") private List<ViewColumn> columns; @CreatedDate diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/ViewColumn.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/ViewColumn.java index b9eff2c694..5016630500 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/ViewColumn.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/ViewColumn.java @@ -1,12 +1,11 @@ package at.tuwien.entities.database; import at.tuwien.entities.database.table.columns.TableColumnType; +import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.GenericGenerator; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import jakarta.persistence.*; - @Data @Entity @Builder(toBuilder = true) @@ -14,7 +13,9 @@ import jakarta.persistence.*; @AllArgsConstructor @NoArgsConstructor @EntityListeners(AuditingEntityListener.class) -@jakarta.persistence.Table(name = "mdb_view_columns") +@jakarta.persistence.Table(name = "mdb_view_columns", uniqueConstraints = { + @UniqueConstraint(columnNames = {"view_id", "internal_name"}) +}) public class ViewColumn implements Comparable<ViewColumn> { @Id @@ -34,10 +35,7 @@ public class ViewColumn implements Comparable<ViewColumn> { @Column(nullable = false, columnDefinition = "VARCHAR(64)") private String name; - @Column(name = "auto_generated", columnDefinition = "BOOLEAN default false") - private Boolean autoGenerated; - - @Column(nullable = false, columnDefinition = "VARCHAR(64)") + @Column(name = "internal_name", nullable = false, columnDefinition = "VARCHAR(64)") private String internalName; @Column(nullable = false, columnDefinition = "ENUM('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR')") diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java index 9a402201ea..08f6bd9426 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/Table.java @@ -88,12 +88,6 @@ public class Table { }) private Database database; - @ToString.Exclude - @OnDelete(action = OnDeleteAction.CASCADE) - @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, mappedBy = "table") - @OrderBy("ordinalPosition") - private List<TableColumn> columns; - @ToString.Exclude @org.springframework.data.annotation.Transient @OneToMany(fetch = FetchType.LAZY) @@ -124,6 +118,12 @@ public class Table { @Column(name = "avg_row_length") private Long avgRowLength; + @ToString.Exclude + @OnDelete(action = OnDeleteAction.CASCADE) + @OneToMany(fetch = FetchType.LAZY, cascade = {CascadeType.MERGE, CascadeType.PERSIST}, mappedBy = "table") + @OrderBy("ordinalPosition") + private List<TableColumn> columns; + @CreatedDate @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", timezone = "UTC") diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java index 9ddf89c453..841dbde754 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumn.java @@ -2,14 +2,13 @@ package at.tuwien.entities.database.table.columns; import at.tuwien.entities.database.table.Table; import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.persistence.*; import lombok.*; import org.hibernate.annotations.GenericGenerator; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.data.jpa.domain.support.AuditingEntityListener; -import jakarta.persistence.*; - import java.math.BigDecimal; import java.time.Instant; import java.util.List; @@ -47,9 +46,6 @@ public class TableColumn implements Comparable<TableColumn> { @Column(name = "cname", nullable = false, columnDefinition = "VARCHAR(64)") private String name; - @Column(name = "auto_generated", columnDefinition = "BOOLEAN default false") - private Boolean autoGenerated; - @Column(name = "internal_name", nullable = false, columnDefinition = "VARCHAR(64)") private String internalName; @@ -62,7 +58,7 @@ public class TableColumn implements Comparable<TableColumn> { @Transient private String alias; - @Column(name = "datatype", nullable = false, columnDefinition = "ENUM('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR')") + @Column(name = "Datatype", nullable = false, columnDefinition = "ENUM('CHAR','VARCHAR','BINARY','VARBINARY','TINYBLOB','TINYTEXT','TEXT','BLOB','MEDIUMTEXT','MEDIUMBLOB','LONGTEXT','LONGBLOB','ENUM','SET','SERIAL','BIT','TINYINT','BOOL','SMALLINT','MEDIUMINT','INT','BIGINT','FLOAT','DOUBLE','DECIMAL','DATE','DATETIME','TIMESTAMP','TIME','YEAR')") @Enumerated(EnumType.STRING) private TableColumnType columnType; diff --git a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnType.java b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnType.java index 074620a349..7f95c476dd 100644 --- a/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnType.java +++ b/dbrepo-metadata-service/entities/src/main/java/at/tuwien/entities/database/table/columns/TableColumnType.java @@ -20,6 +20,7 @@ public enum TableColumnType { LONGBLOB, ENUM, SET, + SERIAL, BIT, TINYINT, BOOL, diff --git a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java index 0555e1c62c..bc20219105 100644 --- a/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java +++ b/dbrepo-metadata-service/repositories/src/main/java/at/tuwien/mapper/MetadataMapper.java @@ -725,7 +725,6 @@ public interface MetadataMapper { @Mapping(target = "columnType", source = "data.type"), @Mapping(target = "isNullAllowed", source = "data.nullAllowed"), @Mapping(target = "name", source = "data.name"), - @Mapping(target = "autoGenerated", expression = "java(false)"), @Mapping(target = "internalName", expression = "java(nameToInternalName(data.getName()))"), }) TableColumn columnCreateDtoToTableColumn(ColumnCreateDto data, ContainerImage image); diff --git a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java index e5a1467296..75f76d440a 100644 --- a/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java +++ b/dbrepo-metadata-service/rest-service/src/main/java/at/tuwien/validation/EndpointValidator.java @@ -29,6 +29,7 @@ import java.util.Optional; @Component public class EndpointValidator { + public static final List<ColumnTypeDto> NEED_NOTHING = List.of(ColumnTypeDto.BOOL, ColumnTypeDto.SERIAL); public static final List<ColumnTypeDto> NEED_SIZE = List.of(ColumnTypeDto.VARCHAR, ColumnTypeDto.BINARY, ColumnTypeDto.VARBINARY); public static final List<ColumnTypeDto> CAN_HAVE_SIZE = List.of(ColumnTypeDto.CHAR, ColumnTypeDto.VARCHAR, ColumnTypeDto.BINARY, ColumnTypeDto.VARBINARY, ColumnTypeDto.BIT, ColumnTypeDto.TINYINT, ColumnTypeDto.SMALLINT, ColumnTypeDto.MEDIUMINT, ColumnTypeDto.INT); public static final List<ColumnTypeDto> CAN_HAVE_SIZE_AND_D = List.of(ColumnTypeDto.DOUBLE, ColumnTypeDto.DECIMAL); @@ -134,6 +135,35 @@ public class EndpointValidator { log.error("Validation failed: column {} needs at least 1 allowed set value", optional3.get().getName()); throw new MalformedException("Validation failed: column " + optional3.get().getName() + " needs at least 1 allowed set value"); } + /* check serial */ + final List<ColumnCreateDto> list4a = data.getColumns() + .stream() + .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL)) + .toList(); + if (list4a.size() > 1) { + log.error("Validation failed: only one column of type serial allowed"); + throw new MalformedException("Validation failed: only one column of type serial allowed"); + } + final Optional<ColumnCreateDto> optional4a = data.getColumns() + .stream() + .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL)) + .filter(ColumnCreateDto::getNullAllowed) + .findFirst(); + if (optional4a.isPresent()) { + log.error("Validation failed: column {} type serial demands non-null", optional4a.get().getName()); + throw new MalformedException("Validation failed: column " + optional4a.get().getName() + " type serial demands non-null"); + } + final Optional<ColumnCreateDto> optional4b = data.getColumns() + .stream() + .filter(c -> c.getType().equals(ColumnTypeDto.SERIAL) && data.getConstraints() + .getUniques() + .stream() + .noneMatch(uk -> uk.size() == 1 && uk.contains(c.getName()))) + .findFirst(); + if (optional4b.isPresent()) { + log.error("Validation failed: column {} type serial demands a unique constraint", optional4b.get().getName()); + throw new MalformedException("Validation failed: column " + optional4b.get().getName() + " type serial demands a unique constraint"); + } } public boolean validateOnlyMineOrWriteAccessOrHasRole(User owner, Principal principal, DatabaseAccess access, String role) { diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java index 4b6c1c2923..1ceb6fd75f 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/endpoints/TableEndpointUnitTest.java @@ -7,6 +7,7 @@ import at.tuwien.api.database.table.columns.ColumnCreateDto; import at.tuwien.api.database.table.columns.ColumnDto; import at.tuwien.api.database.table.columns.ColumnTypeDto; import at.tuwien.api.database.table.columns.concepts.ColumnSemanticsUpdateDto; +import at.tuwien.api.database.table.constraints.ConstraintsCreateDto; import at.tuwien.api.semantics.EntityDto; import at.tuwien.api.semantics.TableColumnEntityDto; import at.tuwien.entities.database.Database; @@ -69,6 +70,11 @@ public class TableEndpointUnitTest extends AbstractUnitTest { @Autowired private TableEndpoint tableEndpoint; + public static Stream<Arguments> needNothing_parameters() { + return EndpointValidator.NEED_NOTHING.stream() + .map(Arguments::arguments); + } + public static Stream<Arguments> needSize_parameters() { return EndpointValidator.NEED_SIZE.stream() .map(Arguments::arguments); @@ -282,6 +288,32 @@ public class TableEndpointUnitTest extends AbstractUnitTest { generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); } + @ParameterizedTest + @MethodSource("needNothing_parameters") + @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + public void create_publicNeedNothing_succeeds(ColumnTypeDto columnType) throws UserNotFoundException, SearchServiceException, + NotAllowedException, SemanticEntityNotFoundException, DataServiceConnectionException, TableNotFoundException, MalformedException, DataServiceException, DatabaseNotFoundException, AccessNotFoundException, OntologyNotFoundException, TableExistsException, SearchServiceConnectionException { + final TableCreateDto request = TableCreateDto.builder() + .name("Some Table") + .description("Some Description") + .columns(List.of(ColumnCreateDto.builder() + .name("ID") + .type(columnType) + .nullAllowed(false) + .build())) + .constraints(ConstraintsCreateDto.builder() + .uniques(List.of(List.of("ID"))) + .build()) + .build(); + + /* mock */ + when(tableService.createTable(DATABASE_3, request, USER_1_PRINCIPAL)) + .thenReturn(TABLE_1) /* some table */; + + /* test */ + generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); + } + @ParameterizedTest @MethodSource("needSize_parameters") @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) @@ -401,6 +433,56 @@ public class TableEndpointUnitTest extends AbstractUnitTest { generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); } + @Test + @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + public void create_publicHasMultipleSerial_fails() { + final TableCreateDto request = TableCreateDto.builder() + .name("Some Table") + .description("Some Description") + .columns(List.of(ColumnCreateDto.builder() + .name("ID") + .type(ColumnTypeDto.SERIAL) + .nullAllowed(false) + .build(), + ColumnCreateDto.builder() + .name("Counter") + .type(ColumnTypeDto.SERIAL) + .nullAllowed(false) + .build())) + .constraints(ConstraintsCreateDto.builder() + .uniques(List.of(List.of("ID"), + List.of("Counter"))) + .build()) + .build(); + + /* test */ + assertThrows(MalformedException.class, () -> { + generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); + }); + } + + @Test + @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) + public void create_publicSerialNullAllowed_fails() { + final TableCreateDto request = TableCreateDto.builder() + .name("Some Table") + .description("Some Description") + .columns(List.of(ColumnCreateDto.builder() + .name("ID") + .type(ColumnTypeDto.SERIAL) + .nullAllowed(true) // <<< + .build())) + .constraints(ConstraintsCreateDto.builder() + .uniques(List.of(List.of("ID"))) + .build()) + .build(); + + /* test */ + assertThrows(MalformedException.class, () -> { + generic_create(DATABASE_3_ID, DATABASE_3, request, USER_1_PRINCIPAL, USER_1, DATABASE_3_USER_1_WRITE_OWN_ACCESS); + }); + } + @ParameterizedTest @MethodSource("canHaveSizeAndD_parameters") @WithMockUser(username = USER_3_USERNAME, authorities = {"create-table"}) diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java index 8a72f2cabb..c849900985 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/mapper/MetadataMapperUnitTest.java @@ -182,8 +182,6 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { @Test public void customDatabaseToDatabaseDto_succeeds() { - final Database debug = DATABASE_1; - /* test */ final DatabaseDto response = metadataMapper.customDatabaseToDatabaseDto(DATABASE_1); assertEquals(DATABASE_1_ID, response.getId()); @@ -241,11 +239,10 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { assertEquals(TABLE_1_COLUMNS.get(i).getTable().getId(), table0.getColumns().get(i).getTableId()); assertEquals(TABLE_1_COLUMNS.get(i).getName(), table0.getColumns().get(i).getName()); assertEquals(TABLE_1_COLUMNS.get(i).getInternalName(), table0.getColumns().get(i).getInternalName()); - assertEquals(List.of(ColumnTypeDto.BIGINT, ColumnTypeDto.DATE, ColumnTypeDto.VARCHAR, ColumnTypeDto.DECIMAL, ColumnTypeDto.DECIMAL).get(i), table0.getColumns().get(i).getColumnType()); + assertEquals(List.of(ColumnTypeDto.SERIAL, ColumnTypeDto.DATE, ColumnTypeDto.VARCHAR, ColumnTypeDto.DECIMAL, ColumnTypeDto.DECIMAL).get(i), table0.getColumns().get(i).getColumnType()); assertEquals(TABLE_1_COLUMNS.get(i).getSize(), table0.getColumns().get(i).getSize()); assertEquals(TABLE_1_COLUMNS.get(i).getD(), table0.getColumns().get(i).getD()); assertEquals(TABLE_1_COLUMNS.get(i).getIsNullAllowed(), table0.getColumns().get(i).getIsNullAllowed()); - assertEquals(TABLE_1_COLUMNS.get(i).getAutoGenerated(), table0.getColumns().get(i).getAutoGenerated()); assertEquals(TABLE_1_COLUMNS.get(i).getEnums(), table0.getColumns().get(i).getEnums()); assertEquals(TABLE_1_COLUMNS.get(i).getSets(), table0.getColumns().get(i).getSets()); } @@ -264,7 +261,7 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { assertEquals(TABLE_1_COLUMNS_BRIEF_0_DTO.getInternalName(), table0pk.getColumn().getInternalName()); assertEquals(TABLE_1_ID, table0pk.getTable().getId()); assertEquals(DATABASE_1_ID, table0pk.getTable().getDatabaseId()); - assertEquals(ColumnTypeDto.BIGINT, table0pk.getColumn().getColumnType()); + assertEquals(ColumnTypeDto.SERIAL, table0pk.getColumn().getColumnType()); assertNull(table0pk.getColumn().getAlias()); assertEquals(TABLE_1_ID, table0pk.getColumn().getTableId()); assertEquals(DATABASE_1_ID, table0pk.getColumn().getDatabaseId()); @@ -298,7 +295,6 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { assertEquals(TABLE_2_COLUMNS.get(i).getSize(), table1.getColumns().get(i).getSize()); assertEquals(TABLE_2_COLUMNS.get(i).getD(), table1.getColumns().get(i).getD()); assertEquals(TABLE_2_COLUMNS.get(i).getIsNullAllowed(), table1.getColumns().get(i).getIsNullAllowed()); - assertEquals(TABLE_2_COLUMNS.get(i).getAutoGenerated(), table1.getColumns().get(i).getAutoGenerated()); assertEquals(TABLE_2_COLUMNS.get(i).getEnums(), table1.getColumns().get(i).getEnums()); assertEquals(TABLE_2_COLUMNS.get(i).getSets(), table1.getColumns().get(i).getSets()); } @@ -372,7 +368,6 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { assertEquals(TABLE_3_COLUMNS.get(i).getSize(), table2.getColumns().get(i).getSize()); assertEquals(TABLE_3_COLUMNS.get(i).getD(), table2.getColumns().get(i).getD()); assertEquals(TABLE_3_COLUMNS.get(i).getIsNullAllowed(), table2.getColumns().get(i).getIsNullAllowed()); - assertEquals(TABLE_3_COLUMNS.get(i).getAutoGenerated(), table2.getColumns().get(i).getAutoGenerated()); assertEquals(TABLE_3_COLUMNS.get(i).getEnums(), table2.getColumns().get(i).getEnums()); assertEquals(TABLE_3_COLUMNS.get(i).getSets(), table2.getColumns().get(i).getSets()); } @@ -417,7 +412,6 @@ public class MetadataMapperUnitTest extends AbstractUnitTest { assertEquals(TABLE_4_COLUMNS.get(i).getSize(), table3.getColumns().get(i).getSize()); assertEquals(TABLE_4_COLUMNS.get(i).getD(), table3.getColumns().get(i).getD()); assertEquals(TABLE_4_COLUMNS.get(i).getIsNullAllowed(), table3.getColumns().get(i).getIsNullAllowed()); - assertEquals(TABLE_4_COLUMNS.get(i).getAutoGenerated(), table3.getColumns().get(i).getAutoGenerated()); assertEquals(TABLE_4_COLUMNS.get(i).getEnums(), table3.getColumns().get(i).getEnums()); assertEquals(TABLE_4_COLUMNS.get(i).getSets(), table3.getColumns().get(i).getSets()); } diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java index 94636bb3c5..551a6c350a 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/TableServiceUnitTest.java @@ -176,7 +176,6 @@ public class TableServiceUnitTest extends AbstractUnitTest { assertEquals("i_am_spa_shu_l", column0.getInternalName()); assertEquals(TableColumnType.TEXT, column0.getColumnType()); assertTrue(column0.getIsNullAllowed()); - assertFalse(column0.getAutoGenerated()); /* constraints */ final Constraints constraints = response.getConstraints(); assertEquals(0, constraints.getPrimaryKey().size()); diff --git a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java index 3ed06bfd7c..68eca34967 100644 --- a/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java +++ b/dbrepo-metadata-service/rest-service/src/test/java/at/tuwien/service/ViewServicePersistenceTest.java @@ -2,6 +2,7 @@ package at.tuwien.service; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.View; +import at.tuwien.entities.database.ViewColumn; import at.tuwien.exception.*; import at.tuwien.gateway.DataServiceGateway; import at.tuwien.gateway.SearchServiceGateway; @@ -63,7 +64,7 @@ public class ViewServicePersistenceTest extends AbstractUnitTest { licenseRepository.save(LICENSE_1); userRepository.saveAll(List.of(USER_1, USER_2, USER_3)); containerRepository.save(CONTAINER_1); - databaseRepository.save(DATABASE_1); + databaseRepository.saveAll(List.of(DATABASE_1, DATABASE_2, DATABASE_3)); } @Test diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java index 0013f01563..4866fea2c1 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java @@ -191,7 +191,9 @@ public class TableServiceImpl implements TableService { /* delete at data service */ dataServiceGateway.deleteTable(table.getDatabase().getId(), table.getId()); /* update in metadata database */ - table.getDatabase().getTables().remove(table); + table.getDatabase() + .getTables() + .remove(table); final Database database = databaseRepository.save(table.getDatabase()); /* update in search service */ searchServiceGateway.update(database); diff --git a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java index 0826d9dcc8..17a2c26d89 100644 --- a/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java +++ b/dbrepo-metadata-service/services/src/main/java/at/tuwien/service/impl/ViewServiceImpl.java @@ -75,7 +75,9 @@ public class ViewServiceImpl implements ViewService { /* delete in data service */ dataServiceGateway.deleteView(view.getDatabase().getId(), view.getId()); /* delete in metadata database */ - view.getDatabase().getViews().remove(view); + view.getDatabase() + .getViews() + .remove(view); final Database database = databaseRepository.save(view.getDatabase()); /* update in search service */ searchServiceGateway.update(database); diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java index 924db22930..3ab89a3905 100644 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java +++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/AbstractUnitTest.java @@ -38,7 +38,7 @@ public abstract class AbstractUnitTest extends BaseTest { DATABASE_1_PRIVILEGED_DTO.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_1_DTO, IDENTIFIER_2_DTO, IDENTIFIER_3_DTO, IDENTIFIER_4_DTO))); DATABASE_1_PRIVILEGED_DTO.setTables(new LinkedList<>(List.of(TABLE_1_DTO, TABLE_2_DTO, TABLE_3_DTO, TABLE_4_DTO))); DATABASE_1_PRIVILEGED_DTO.setViews(new LinkedList<>(List.of(VIEW_1_DTO, VIEW_2_DTO, VIEW_3_DTO))); - TABLE_1_DTO.setColumns(TABLE_1_COLUMNS_DTO); + TABLE_1_DTO.setColumns(new LinkedList<>(TABLE_1_COLUMNS_DTO)); TABLE_1_DTO.setConstraints(TABLE_1_CONSTRAINTS_DTO); TABLE_2.setDatabase(DATABASE_1); TABLE_2.setColumns(new LinkedList<>(TABLE_2_COLUMNS)); @@ -46,12 +46,12 @@ public abstract class AbstractUnitTest extends BaseTest { TABLE_2.setConstraints(TABLE_2_CONSTRAINTS); TABLE_2_PRIVILEGED_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO)); TABLE_2_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); - TABLE_2_DTO.setColumns(TABLE_2_COLUMNS_DTO); + TABLE_2_DTO.setColumns(new LinkedList<>(TABLE_2_COLUMNS_DTO)); TABLE_2_DTO.setConstraints(TABLE_2_CONSTRAINTS_DTO); TABLE_3.setDatabase(DATABASE_1); TABLE_3.setColumns(new LinkedList<>(TABLE_3_COLUMNS)); TABLE_3.setConstraints(TABLE_3_CONSTRAINTS); - TABLE_3_DTO.setColumns(TABLE_3_COLUMNS_DTO); + TABLE_3_DTO.setColumns(new LinkedList<>(TABLE_3_COLUMNS_DTO)); TABLE_3_DTO.setConstraints(TABLE_3_CONSTRAINTS_DTO); TABLE_4.setDatabase(DATABASE_1); TABLE_4.setColumns(new LinkedList<>(TABLE_4_COLUMNS)); @@ -59,14 +59,14 @@ public abstract class AbstractUnitTest extends BaseTest { TABLE_4_DTO.setColumns(TABLE_4_COLUMNS_DTO); TABLE_4_DTO.setConstraints(TABLE_4_CONSTRAINTS_DTO); VIEW_1.setDatabase(DATABASE_1); - VIEW_1.setColumns(VIEW_1_COLUMNS); + VIEW_1.setColumns(new LinkedList<>(VIEW_1_COLUMNS)); VIEW_1.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_3))); VIEW_1_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); VIEW_2.setDatabase(DATABASE_1); - VIEW_2.setColumns(VIEW_2_COLUMNS); + VIEW_2.setColumns(new LinkedList<>(VIEW_2_COLUMNS)); VIEW_2_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); VIEW_3.setDatabase(DATABASE_1); - VIEW_3.setColumns(VIEW_3_COLUMNS); + VIEW_3.setColumns(new LinkedList<>(VIEW_3_COLUMNS)); VIEW_3_PRIVILEGED_DTO.setDatabase(DATABASE_1_PRIVILEGED_DTO); IDENTIFIER_1.setDatabase(DATABASE_1); IDENTIFIER_2.setDatabase(DATABASE_1); @@ -77,6 +77,7 @@ public abstract class AbstractUnitTest extends BaseTest { DATABASE_2.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS, DATABASE_2_USER_3_READ_ACCESS))); DATABASE_2_PRIVILEGED_DTO.setAccesses(new LinkedList<>(List.of(DATABASE_2_USER_2_WRITE_ALL_ACCESS_DTO, DATABASE_2_USER_3_READ_ACCESS_DTO))); DATABASE_2.setTables(new LinkedList<>(List.of(TABLE_5, TABLE_6, TABLE_7))); + VIEW_4.setColumns(new LinkedList<>(VIEW_4_COLUMNS)); DATABASE_2.setViews(new LinkedList<>(List.of(VIEW_4))); DATABASE_2.setIdentifiers(new LinkedList<>(List.of(IDENTIFIER_5))); DATABASE_2_PRIVILEGED_DTO.setTables(new LinkedList<>(List.of(TABLE_5_DTO, TABLE_6_DTO, TABLE_7_DTO))); diff --git a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java index f372879434..c6c0e4ec10 100644 --- a/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java +++ b/dbrepo-metadata-service/test/src/main/java/at/tuwien/test/BaseTest.java @@ -1509,9 +1509,8 @@ public abstract class BaseTest { .name("id") .internalName("id") .ordinalPosition(0) - .columnType(ColumnTypeDto.BIGINT) + .columnType(ColumnTypeDto.SERIAL) .isNullAllowed(false) - .autoGenerated(false) .enums(null) .sets(null) .build(), @@ -1525,7 +1524,6 @@ public abstract class BaseTest { .ordinalPosition(1) .columnType(ColumnTypeDto.DATE) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build(), @@ -1540,7 +1538,6 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.VARCHAR) .size(255L) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build(), @@ -1556,7 +1553,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build(), @@ -1574,7 +1570,6 @@ public abstract class BaseTest { .concept(CONCEPT_1_DTO) .unit(UNIT_1_DTO) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build()); @@ -2089,7 +2084,6 @@ public abstract class BaseTest { .internalName("timestamp") .columnType(TableColumnType.TIMESTAMP) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_4_2_ID) @@ -2099,7 +2093,6 @@ public abstract class BaseTest { .internalName("value") .columnType(TableColumnType.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static List<ColumnCreateDto> TABLE_4_COLUMNS_CREATE_DTO = List.of(ColumnCreateDto.builder() @@ -2144,7 +2137,6 @@ public abstract class BaseTest { .internalName("timestamp") .columnType(ColumnTypeDto.TIMESTAMP) .isNullAllowed(false) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_4_2_ID) @@ -2154,7 +2146,6 @@ public abstract class BaseTest { .internalName("value") .columnType(ColumnTypeDto.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static Long TABLE_8_ID = 8L; @@ -2392,7 +2383,6 @@ public abstract class BaseTest { .internalName(COLUMN_8_1_INTERNAL_NAME) .columnType(COLUMN_8_1_TYPE) .isNullAllowed(COLUMN_8_1_NULL) - .autoGenerated(COLUMN_8_1_AUTO_GENERATED) .build(), TableColumn.builder() .id(COLUMN_8_2_ID) @@ -2402,7 +2392,6 @@ public abstract class BaseTest { .internalName(COLUMN_8_2_INTERNAL_NAME) .columnType(COLUMN_8_2_TYPE) .isNullAllowed(COLUMN_8_2_NULL) - .autoGenerated(COLUMN_8_2_AUTO_GENERATED) .size(COLUMN_8_2_SIZE) .d(COLUMN_8_2_D) .build(), @@ -2414,7 +2403,6 @@ public abstract class BaseTest { .internalName(COLUMN_8_3_INTERNAL_NAME) .columnType(COLUMN_8_3_TYPE) .isNullAllowed(COLUMN_8_3_NULL) - .autoGenerated(COLUMN_8_3_AUTO_GENERATED) .build()); public final static List<ColumnDto> TABLE_8_COLUMNS_DTO = List.of(ColumnDto.builder() @@ -2425,7 +2413,6 @@ public abstract class BaseTest { .internalName(COLUMN_8_1_INTERNAL_NAME) .columnType(COLUMN_8_1_TYPE_DTO) .isNullAllowed(COLUMN_8_1_NULL) - .autoGenerated(COLUMN_8_1_AUTO_GENERATED) .build(), ColumnDto.builder() .id(COLUMN_8_2_ID) @@ -2435,7 +2422,6 @@ public abstract class BaseTest { .internalName(COLUMN_8_2_INTERNAL_NAME) .columnType(COLUMN_8_2_TYPE_DTO) .isNullAllowed(COLUMN_8_2_NULL) - .autoGenerated(COLUMN_8_2_AUTO_GENERATED) .build(), ColumnDto.builder() .id(COLUMN_8_3_ID) @@ -2445,7 +2431,6 @@ public abstract class BaseTest { .internalName(COLUMN_8_3_INTERNAL_NAME) .columnType(COLUMN_8_3_TYPE_DTO) .isNullAllowed(COLUMN_8_3_NULL) - .autoGenerated(COLUMN_8_3_AUTO_GENERATED) .build()); public final static Long TABLE_8_DATA_COUNT = 6L; @@ -2770,9 +2755,8 @@ public abstract class BaseTest { .table(TABLE_1) .name("id") .internalName("id") - .columnType(TableColumnType.BIGINT) + .columnType(TableColumnType.SERIAL) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_1_2_ID) @@ -2782,7 +2766,6 @@ public abstract class BaseTest { .internalName("date") .columnType(TableColumnType.DATE) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_1_3_ID) @@ -2793,7 +2776,6 @@ public abstract class BaseTest { .columnType(TableColumnType.VARCHAR) .size(255L) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_1_4_ID) @@ -2805,7 +2787,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_1_5_ID) @@ -2819,7 +2800,6 @@ public abstract class BaseTest { .concept(CONCEPT_1) .unit(UNIT_1) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static List<ColumnCreateDto> TABLE_1_COLUMNS_CREATE_DTO = List.of(ColumnCreateDto.builder() @@ -2908,7 +2888,6 @@ public abstract class BaseTest { .columnType(TableColumnType.VARCHAR) .size(255L) .isNullAllowed(false) - .autoGenerated(false) .enums(null) .sets(null) .build(), @@ -2923,7 +2902,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build(), @@ -2938,7 +2916,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build()); @@ -2968,7 +2945,6 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.VARCHAR) .size(255L) .isNullAllowed(false) - .autoGenerated(false) .enums(null) .sets(null) .build(), @@ -2983,7 +2959,6 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.DOUBLE) .size(22L) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build(), @@ -2998,7 +2973,6 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.DOUBLE) .size(22L) .isNullAllowed(true) - .autoGenerated(false) .enums(null) .sets(null) .build()); @@ -3084,7 +3058,6 @@ public abstract class BaseTest { .id(COLUMN_3_1_ID) .table(TABLE_3) .ordinalPosition(0) - .autoGenerated(true) .columnType(TableColumnType.BIGINT) .name("id") .internalName("id") @@ -3096,7 +3069,6 @@ public abstract class BaseTest { .id(COLUMN_3_2_ID) .table(TABLE_3) .ordinalPosition(1) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("linie") .internalName("linie") @@ -3108,7 +3080,6 @@ public abstract class BaseTest { .id(COLUMN_3_3_ID) .table(TABLE_3) .ordinalPosition(2) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("richtung") .internalName("richtung") @@ -3120,7 +3091,6 @@ public abstract class BaseTest { .id(COLUMN_3_4_ID) .table(TABLE_3) .ordinalPosition(3) - .autoGenerated(false) .columnType(TableColumnType.DATE) .name("betriebsdatum") .internalName("betriebsdatum") @@ -3132,7 +3102,6 @@ public abstract class BaseTest { .id(COLUMN_3_5_ID) .table(TABLE_3) .ordinalPosition(4) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fahrzeug") .internalName("fahrzeug") @@ -3144,7 +3113,6 @@ public abstract class BaseTest { .id(COLUMN_3_6_ID) .table(TABLE_3) .ordinalPosition(5) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("kurs") .internalName("kurs") @@ -3156,7 +3124,6 @@ public abstract class BaseTest { .id(COLUMN_3_7_ID) .table(TABLE_3) .ordinalPosition(6) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("seq_von") .internalName("seq_von") @@ -3168,7 +3135,6 @@ public abstract class BaseTest { .id(COLUMN_3_8_ID) .table(TABLE_3) .ordinalPosition(7) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_diva_von") .internalName("halt_diva_von") @@ -3180,7 +3146,6 @@ public abstract class BaseTest { .id(COLUMN_3_9_ID) .table(TABLE_3) .ordinalPosition(8) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_punkt_diva_von") .internalName("halt_punkt_diva_von") @@ -3192,7 +3157,6 @@ public abstract class BaseTest { .id(COLUMN_3_10_ID) .table(TABLE_3) .ordinalPosition(9) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_kurz_von1") .internalName("halt_kurz_von1") @@ -3204,7 +3168,6 @@ public abstract class BaseTest { .id(COLUMN_3_11_ID) .table(TABLE_3) .ordinalPosition(10) - .autoGenerated(false) .columnType(TableColumnType.DATE) .name("datum_von") .internalName("datum_von") @@ -3216,7 +3179,6 @@ public abstract class BaseTest { .id(COLUMN_3_12_ID) .table(TABLE_3) .ordinalPosition(11) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("soll_an_von") .internalName("soll_an_von") @@ -3228,7 +3190,6 @@ public abstract class BaseTest { .id(COLUMN_3_13_ID) .table(TABLE_3) .ordinalPosition(12) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("ist_an_von") .internalName("ist_an_von") @@ -3240,7 +3201,6 @@ public abstract class BaseTest { .id(COLUMN_3_14_ID) .table(TABLE_3) .ordinalPosition(13) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("soll_ab_von") .internalName("soll_ab_von") @@ -3252,7 +3212,6 @@ public abstract class BaseTest { .id(COLUMN_3_15_ID) .table(TABLE_3) .ordinalPosition(14) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("ist_ab_von") .internalName("ist_ab_von") @@ -3264,7 +3223,6 @@ public abstract class BaseTest { .id(COLUMN_3_16_ID) .table(TABLE_3) .ordinalPosition(15) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("seq_nach") .internalName("seq_nach") @@ -3276,7 +3234,6 @@ public abstract class BaseTest { .id(COLUMN_3_17_ID) .table(TABLE_3) .ordinalPosition(16) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_diva_nach") .internalName("halt_diva_nach") @@ -3288,7 +3245,6 @@ public abstract class BaseTest { .id(COLUMN_3_18_ID) .table(TABLE_3) .ordinalPosition(17) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_punkt_diva_nach") .internalName("halt_punkt_diva_nach") @@ -3300,7 +3256,6 @@ public abstract class BaseTest { .id(COLUMN_3_19_ID) .table(TABLE_3) .ordinalPosition(18) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_kurz_nach1") .internalName("halt_kurz_nach1") @@ -3312,7 +3267,6 @@ public abstract class BaseTest { .id(COLUMN_3_20_ID) .table(TABLE_3) .ordinalPosition(19) - .autoGenerated(false) .columnType(TableColumnType.DATE) .name("datum_nach") .internalName("datum_nach") @@ -3324,7 +3278,6 @@ public abstract class BaseTest { .id(COLUMN_3_21_ID) .table(TABLE_3) .ordinalPosition(20) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("soll_an_nach") .internalName("soll_an_nach") @@ -3336,7 +3289,6 @@ public abstract class BaseTest { .id(COLUMN_3_22_ID) .table(TABLE_3) .ordinalPosition(21) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("ist_an_nach1") .internalName("ist_an_nach1") @@ -3348,7 +3300,6 @@ public abstract class BaseTest { .id(COLUMN_3_23_ID) .table(TABLE_3) .ordinalPosition(22) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("soll_ab_nach") .internalName("soll_ab_nach") @@ -3360,7 +3311,6 @@ public abstract class BaseTest { .id(COLUMN_3_24_ID) .table(TABLE_3) .ordinalPosition(23) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("ist_ab_nach") .internalName("ist_ab_nach") @@ -3372,7 +3322,6 @@ public abstract class BaseTest { .id(COLUMN_3_25_ID) .table(TABLE_3) .ordinalPosition(24) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fahrt_id") .internalName("fahrt_id") @@ -3384,7 +3333,6 @@ public abstract class BaseTest { .id(COLUMN_3_26_ID) .table(TABLE_3) .ordinalPosition(25) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fahrweg_id") .internalName("fahrweg_id") @@ -3396,7 +3344,6 @@ public abstract class BaseTest { .id(COLUMN_3_27_ID) .table(TABLE_3) .ordinalPosition(26) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fw_no") .internalName("fw_no") @@ -3408,7 +3355,6 @@ public abstract class BaseTest { .id(COLUMN_3_28_ID) .table(TABLE_3) .ordinalPosition(27) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fw_typ") .internalName("fw_typ") @@ -3420,7 +3366,6 @@ public abstract class BaseTest { .id(COLUMN_3_29_ID) .table(TABLE_3) .ordinalPosition(28) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fw_kurz") .internalName("fw_kurz") @@ -3432,7 +3377,6 @@ public abstract class BaseTest { .id(COLUMN_3_30_ID) .table(TABLE_3) .ordinalPosition(29) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("fw_lang") .internalName("fw_lang") @@ -3444,7 +3388,6 @@ public abstract class BaseTest { .id(COLUMN_3_31_ID) .table(TABLE_3) .ordinalPosition(30) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("umlauf_von") .internalName("umlauf_von") @@ -3456,7 +3399,6 @@ public abstract class BaseTest { .id(COLUMN_3_32_ID) .table(TABLE_3) .ordinalPosition(31) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_id_von") .internalName("halt_id_von") @@ -3468,7 +3410,6 @@ public abstract class BaseTest { .id(COLUMN_3_33_ID) .table(TABLE_3) .ordinalPosition(32) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_id_nach") .internalName("halt_id_nach") @@ -3480,7 +3421,6 @@ public abstract class BaseTest { .id(COLUMN_3_34_ID) .table(TABLE_3) .ordinalPosition(33) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_punkt_id_von") .internalName("halt_punkt_id_von") @@ -3492,7 +3432,6 @@ public abstract class BaseTest { .id(COLUMN_3_35_ID) .table(TABLE_3) .ordinalPosition(34) - .autoGenerated(false) .columnType(TableColumnType.INT) .name("halt_punkt_id_nach") .internalName("halt_punkt_id_nach") @@ -3506,7 +3445,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(true) .columnType(ColumnTypeDto.BIGINT) .name("id") .internalName("id") @@ -3519,7 +3457,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("linie") .internalName("linie") @@ -3532,7 +3469,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("richtung") .internalName("richtung") @@ -3545,7 +3481,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.DATE) .name("betriebsdatum") .internalName("betriebsdatum") @@ -3558,7 +3493,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fahrzeug") .internalName("fahrzeug") @@ -3571,7 +3505,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("kurs") .internalName("kurs") @@ -3584,7 +3517,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("seq_von") .internalName("seq_von") @@ -3597,7 +3529,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_diva_von") .internalName("halt_diva_von") @@ -3610,7 +3541,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_punkt_diva_von") .internalName("halt_punkt_diva_von") @@ -3623,7 +3553,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_kurz_von1") .internalName("halt_kurz_von1") @@ -3636,7 +3565,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.DATE) .name("datum_von") .internalName("datum_von") @@ -3649,7 +3577,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("soll_an_von") .internalName("soll_an_von") @@ -3662,7 +3589,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("ist_an_von") .internalName("ist_an_von") @@ -3675,7 +3601,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("soll_ab_von") .internalName("soll_ab_von") @@ -3688,7 +3613,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("ist_ab_von") .internalName("ist_ab_von") @@ -3701,7 +3625,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("seq_nach") .internalName("seq_nach") @@ -3714,7 +3637,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_diva_nach") .internalName("halt_diva_nach") @@ -3727,7 +3649,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_punkt_diva_nach") .internalName("halt_punkt_diva_nach") @@ -3740,7 +3661,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_kurz_nach1") .internalName("halt_kurz_nach1") @@ -3753,7 +3673,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.DATE) .name("datum_nach") .internalName("datum_nach") @@ -3766,7 +3685,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("soll_an_nach") .internalName("soll_an_nach") @@ -3779,7 +3697,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("ist_an_nach1") .internalName("ist_an_nach1") @@ -3792,7 +3709,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("soll_ab_nach") .internalName("soll_ab_nach") @@ -3805,7 +3721,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("ist_ab_nach") .internalName("ist_ab_nach") @@ -3818,7 +3733,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fahrt_id") .internalName("fahrt_id") @@ -3831,7 +3745,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fahrweg_id") .internalName("fahrweg_id") @@ -3844,7 +3757,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fw_no") .internalName("fw_no") @@ -3857,7 +3769,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fw_typ") .internalName("fw_typ") @@ -3870,7 +3781,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fw_kurz") .internalName("fw_kurz") @@ -3883,7 +3793,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("fw_lang") .internalName("fw_lang") @@ -3896,7 +3805,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("umlauf_von") .internalName("umlauf_von") @@ -3909,7 +3817,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_id_von") .internalName("halt_id_von") @@ -3922,7 +3829,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_id_nach") .internalName("halt_id_nach") @@ -3935,7 +3841,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_punkt_id_von") .internalName("halt_punkt_id_von") @@ -3948,7 +3853,6 @@ public abstract class BaseTest { .tableId(TABLE_3_ID) .table(TABLE_3_DTO) .databaseId(DATABASE_1_ID) - .autoGenerated(false) .columnType(ColumnTypeDto.INT) .name("halt_punkt_id_nach") .internalName("halt_punkt_id_nach") @@ -4014,7 +3918,6 @@ public abstract class BaseTest { .internalName("id") .columnType(TableColumnType.BIGINT) .isNullAllowed(false) - .autoGenerated(true) .build(), TableColumn.builder() .id(COLUMN_5_2_ID) @@ -4024,7 +3927,6 @@ public abstract class BaseTest { .internalName("animal_name") .columnType(TableColumnType.VARCHAR) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_3_ID) @@ -4034,7 +3936,6 @@ public abstract class BaseTest { .internalName("hair") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_4_ID) @@ -4044,7 +3945,6 @@ public abstract class BaseTest { .internalName("feathers") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_5_ID) @@ -4054,7 +3954,6 @@ public abstract class BaseTest { .internalName("bread") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_6_ID) @@ -4064,7 +3963,6 @@ public abstract class BaseTest { .internalName("eggs") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_7_ID) @@ -4074,7 +3972,6 @@ public abstract class BaseTest { .internalName("milk") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_8_ID) @@ -4084,7 +3981,6 @@ public abstract class BaseTest { .internalName("water") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_9_ID) @@ -4094,7 +3990,6 @@ public abstract class BaseTest { .internalName("airborne") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_10_ID) @@ -4104,7 +3999,6 @@ public abstract class BaseTest { .internalName("waterborne") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_11_ID) @@ -4114,7 +4008,6 @@ public abstract class BaseTest { .internalName("aquantic") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_12_ID) @@ -4124,7 +4017,6 @@ public abstract class BaseTest { .internalName("predator") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_13_ID) @@ -4134,7 +4026,6 @@ public abstract class BaseTest { .internalName("backbone") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_14_ID) @@ -4144,7 +4035,6 @@ public abstract class BaseTest { .internalName("breathes") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_15_ID) @@ -4154,7 +4044,6 @@ public abstract class BaseTest { .internalName("venomous") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_16_ID) @@ -4164,7 +4053,6 @@ public abstract class BaseTest { .internalName("fin") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_17_ID) @@ -4174,7 +4062,6 @@ public abstract class BaseTest { .internalName("legs") .columnType(TableColumnType.INT) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_18_ID) @@ -4184,7 +4071,6 @@ public abstract class BaseTest { .internalName("tail") .columnType(TableColumnType.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_19_ID) @@ -4194,7 +4080,6 @@ public abstract class BaseTest { .internalName("domestic") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_20_ID) @@ -4204,7 +4089,6 @@ public abstract class BaseTest { .internalName("catsize") .columnType(TableColumnType.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_5_21_ID) @@ -4214,7 +4098,6 @@ public abstract class BaseTest { .internalName("class_type") .columnType(TableColumnType.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static List<ColumnDto> TABLE_5_COLUMNS_DTO = List.of(ColumnDto.builder() @@ -4226,7 +4109,6 @@ public abstract class BaseTest { .internalName("id") .columnType(ColumnTypeDto.BIGINT) .isNullAllowed(false) - .autoGenerated(true) .build(), ColumnDto.builder() .id(COLUMN_5_2_ID) @@ -4237,7 +4119,6 @@ public abstract class BaseTest { .internalName("animal_name") .columnType(ColumnTypeDto.VARCHAR) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_3_ID) @@ -4248,7 +4129,6 @@ public abstract class BaseTest { .internalName("hair") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_4_ID) @@ -4259,7 +4139,6 @@ public abstract class BaseTest { .internalName("feathers") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_5_ID) @@ -4270,7 +4149,6 @@ public abstract class BaseTest { .internalName("bread") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_6_ID) @@ -4281,7 +4159,6 @@ public abstract class BaseTest { .internalName("eggs") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_7_ID) @@ -4292,7 +4169,6 @@ public abstract class BaseTest { .internalName("milk") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_8_ID) @@ -4303,7 +4179,6 @@ public abstract class BaseTest { .internalName("water") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_9_ID) @@ -4314,7 +4189,6 @@ public abstract class BaseTest { .internalName("airborne") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_10_ID) @@ -4325,7 +4199,6 @@ public abstract class BaseTest { .internalName("waterborne") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_11_ID) @@ -4336,7 +4209,6 @@ public abstract class BaseTest { .internalName("aquantic") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_12_ID) @@ -4347,7 +4219,6 @@ public abstract class BaseTest { .internalName("predator") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_13_ID) @@ -4358,7 +4229,6 @@ public abstract class BaseTest { .internalName("backbone") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_14_ID) @@ -4369,7 +4239,6 @@ public abstract class BaseTest { .internalName("breathes") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_15_ID) @@ -4380,7 +4249,6 @@ public abstract class BaseTest { .internalName("venomous") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_16_ID) @@ -4391,7 +4259,6 @@ public abstract class BaseTest { .internalName("fin") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_17_ID) @@ -4402,7 +4269,6 @@ public abstract class BaseTest { .internalName("legs") .columnType(ColumnTypeDto.INT) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_18_ID) @@ -4413,7 +4279,6 @@ public abstract class BaseTest { .internalName("tail") .columnType(ColumnTypeDto.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_19_ID) @@ -4424,7 +4289,6 @@ public abstract class BaseTest { .internalName("domestic") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_20_ID) @@ -4435,7 +4299,6 @@ public abstract class BaseTest { .internalName("catsize") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_5_21_ID) @@ -4446,7 +4309,6 @@ public abstract class BaseTest { .internalName("class_type") .columnType(ColumnTypeDto.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static List<ForeignKeyCreateDto> TABLE_5_FOREIGN_KEYS_INVALID_CREATE = List.of(ForeignKeyCreateDto.builder() @@ -4594,7 +4456,6 @@ public abstract class BaseTest { .internalName("id") .columnType(TableColumnType.BIGINT) .isNullAllowed(false) - .autoGenerated(true) .build(), TableColumn.builder() .id(68L) @@ -4604,7 +4465,6 @@ public abstract class BaseTest { .internalName("firstname") .columnType(TableColumnType.VARCHAR) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() .id(69L) @@ -4614,7 +4474,6 @@ public abstract class BaseTest { .internalName("lastname") .columnType(TableColumnType.VARCHAR) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() .id(70L) @@ -4624,7 +4483,6 @@ public abstract class BaseTest { .internalName("birth") .columnType(TableColumnType.YEAR) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() .id(71L) @@ -4634,7 +4492,6 @@ public abstract class BaseTest { .internalName("reminder") .columnType(TableColumnType.TIME) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() .id(72L) @@ -4644,7 +4501,6 @@ public abstract class BaseTest { .internalName("ref_id") .columnType(TableColumnType.BIGINT) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static ColumnBriefDto TABLE_6_COLUMNS_BRIEF_0_DTO = ColumnBriefDto.builder() @@ -4663,7 +4519,6 @@ public abstract class BaseTest { .internalName("id") .columnType(ColumnTypeDto.BIGINT) .isNullAllowed(false) - .autoGenerated(true) .build(), ColumnDto.builder() .id(68L) @@ -4674,7 +4529,6 @@ public abstract class BaseTest { .internalName("firstname") .columnType(ColumnTypeDto.VARCHAR) .isNullAllowed(false) - .autoGenerated(false) .build(), ColumnDto.builder() .id(69L) @@ -4685,7 +4539,6 @@ public abstract class BaseTest { .internalName("lastname") .columnType(ColumnTypeDto.VARCHAR) .isNullAllowed(false) - .autoGenerated(false) .build(), ColumnDto.builder() .id(70L) @@ -4696,7 +4549,6 @@ public abstract class BaseTest { .internalName("birth") .columnType(ColumnTypeDto.YEAR) .isNullAllowed(false) - .autoGenerated(false) .build(), ColumnDto.builder() .id(71L) @@ -4707,7 +4559,6 @@ public abstract class BaseTest { .internalName("reminder") .columnType(ColumnTypeDto.TIME) .isNullAllowed(false) - .autoGenerated(false) .build(), ColumnDto.builder() .id(72L) @@ -4718,7 +4569,6 @@ public abstract class BaseTest { .internalName("ref_id") .columnType(ColumnTypeDto.BIGINT) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static List<List<String>> TABLE_6_UNIQUES_CREATE = List.of( @@ -4785,7 +4635,6 @@ public abstract class BaseTest { .internalName("name_id") .columnType(TableColumnType.BIGINT) .isNullAllowed(false) - .autoGenerated(false) .build(), TableColumn.builder() .id(COLUMN_7_2_ID) @@ -4795,7 +4644,6 @@ public abstract class BaseTest { .internalName("zoo_id") .columnType(TableColumnType.BIGINT) .isNullAllowed(false) - .autoGenerated(false) .build()); public final static List<ColumnDto> TABLE_7_COLUMNS_DTO = List.of(ColumnDto.builder() @@ -4807,7 +4655,6 @@ public abstract class BaseTest { .internalName("name_id") .columnType(ColumnTypeDto.BIGINT) .isNullAllowed(false) - .autoGenerated(false) .build(), ColumnDto.builder() .id(COLUMN_7_2_ID) @@ -4818,7 +4665,6 @@ public abstract class BaseTest { .internalName("zoo_id") .columnType(ColumnTypeDto.BIGINT) .isNullAllowed(false) - .autoGenerated(false) .build()); public final static Long VIEW_1_ID = 1L; @@ -4841,7 +4687,6 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.VARCHAR) .size(255L) .isNullAllowed(false) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(2L) @@ -4852,7 +4697,6 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.DOUBLE) .size(22L) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(3L) @@ -4863,7 +4707,6 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.DOUBLE) .size(22L) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static View VIEW_1 = View.builder() @@ -4915,7 +4758,6 @@ public abstract class BaseTest { .columnType(TableColumnType.VARCHAR) .size(255L) .isNullAllowed(false) - .autoGenerated(false) .view(VIEW_1) .build(), ViewColumn.builder() @@ -4928,7 +4770,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_1) .build(), ViewColumn.builder() @@ -4941,7 +4782,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_1) .build() ); @@ -5010,18 +4850,15 @@ public abstract class BaseTest { .ordinalPosition(1) .columnType(ColumnTypeDto.DATE) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(5L) .name("loc") .internalName("loc") - .alias("loc") .ordinalPosition(2) .columnType(ColumnTypeDto.VARCHAR) .size(255L) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(6L) @@ -5032,7 +4869,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(7L) @@ -5043,7 +4879,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .build() ); @@ -5068,18 +4903,16 @@ public abstract class BaseTest { .internalName("date") .columnType(TableColumnType.DATE) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_2) .build(), ViewColumn.builder() .id(5L) .ordinalPosition(1) - .name("Location") - .internalName("location") + .name("loc") + .internalName("loc") .columnType(TableColumnType.VARCHAR) .size(255L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_2) .build(), ViewColumn.builder() @@ -5091,7 +4924,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_2) .build(), ViewColumn.builder() @@ -5103,7 +4935,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_2) .build() ); @@ -5169,7 +5000,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(9L) @@ -5182,7 +5012,6 @@ public abstract class BaseTest { .concept(CONCEPT_1_DTO) .unit(UNIT_1_DTO) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(10L) @@ -5192,7 +5021,6 @@ public abstract class BaseTest { .columnType(ColumnTypeDto.VARCHAR) .size(255L) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(11L) @@ -5201,7 +5029,6 @@ public abstract class BaseTest { .ordinalPosition(3) .columnType(ColumnTypeDto.DATE) .isNullAllowed(true) - .autoGenerated(false) .build() ); @@ -5242,7 +5069,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_3) .build(), ViewColumn.builder() @@ -5254,7 +5080,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_3) .build(), ViewColumn.builder() @@ -5265,7 +5090,6 @@ public abstract class BaseTest { .columnType(TableColumnType.VARCHAR) .size(255L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_3) .build(), ViewColumn.builder() @@ -5275,7 +5099,6 @@ public abstract class BaseTest { .internalName("date") .columnType(TableColumnType.DATE) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_3) .build() ); @@ -5325,7 +5148,6 @@ public abstract class BaseTest { .internalName("animal_name") .columnType(ColumnTypeDto.VARCHAR) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(13L) @@ -5334,7 +5156,6 @@ public abstract class BaseTest { .internalName("hair") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(14L) @@ -5343,7 +5164,6 @@ public abstract class BaseTest { .internalName("feathers") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(15L) @@ -5352,7 +5172,6 @@ public abstract class BaseTest { .internalName("eggs") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(16L) @@ -5361,7 +5180,6 @@ public abstract class BaseTest { .internalName("milk") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(17L) @@ -5370,7 +5188,6 @@ public abstract class BaseTest { .internalName("airborne") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(18L) @@ -5379,7 +5196,6 @@ public abstract class BaseTest { .internalName("aquantic") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(19L) @@ -5388,7 +5204,6 @@ public abstract class BaseTest { .internalName("predator") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(20L) @@ -5397,7 +5212,6 @@ public abstract class BaseTest { .internalName("backbone") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(21L) @@ -5406,7 +5220,6 @@ public abstract class BaseTest { .internalName("breathes") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(22L) @@ -5415,7 +5228,6 @@ public abstract class BaseTest { .internalName("venomous") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(23L) @@ -5424,7 +5236,6 @@ public abstract class BaseTest { .internalName("fin") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(24L) @@ -5433,7 +5244,6 @@ public abstract class BaseTest { .internalName("legs") .columnType(ColumnTypeDto.INT) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(25L) @@ -5442,7 +5252,6 @@ public abstract class BaseTest { .internalName("tail") .columnType(ColumnTypeDto.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(26L) @@ -5451,7 +5260,6 @@ public abstract class BaseTest { .internalName("domestic") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(27L) @@ -5460,7 +5268,6 @@ public abstract class BaseTest { .internalName("catsize") .columnType(ColumnTypeDto.BOOL) .isNullAllowed(true) - .autoGenerated(false) .build(), ViewColumnDto.builder() .id(28L) @@ -5469,7 +5276,6 @@ public abstract class BaseTest { .internalName("class_type") .columnType(ColumnTypeDto.DECIMAL) .isNullAllowed(true) - .autoGenerated(false) .build()); public final static View VIEW_4 = View.builder() @@ -5498,6 +5304,161 @@ public abstract class BaseTest { .columns(VIEW_4_COLUMNS_DTO) .build(); + public final static List<ViewColumn> VIEW_4_COLUMNS = List.of( + ViewColumn.builder() + .id(12L) + .ordinalPosition(0) + .name("Animal Name") + .internalName("animal_name") + .columnType(TableColumnType.VARCHAR) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(13L) + .ordinalPosition(1) + .name("Hair") + .internalName("hair") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(14L) + .ordinalPosition(2) + .name("Feathers") + .internalName("feathers") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(15L) + .ordinalPosition(3) + .name("Eggs") + .internalName("eggs") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(16L) + .ordinalPosition(4) + .name("Milk") + .internalName("milk") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(17L) + .ordinalPosition(5) + .name("Airborne") + .internalName("airborne") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(18L) + .ordinalPosition(6) + .name("Aquantic") + .internalName("aquantic") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(19L) + .ordinalPosition(7) + .name("Predator") + .internalName("predator") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(20L) + .ordinalPosition(8) + .name("Backbone") + .internalName("backbone") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(21L) + .ordinalPosition(9) + .name("Breathes") + .internalName("breathes") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(22L) + .ordinalPosition(10) + .name("Venomous") + .internalName("venomous") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(23L) + .ordinalPosition(11) + .name("Fin") + .internalName("fin") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(24L) + .ordinalPosition(12) + .name("Legs") + .internalName("legs") + .columnType(TableColumnType.INT) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(25L) + .ordinalPosition(13) + .name("Tail") + .internalName("tail") + .columnType(TableColumnType.DECIMAL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(26L) + .ordinalPosition(14) + .name("Domestic") + .internalName("domestic") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(27L) + .ordinalPosition(15) + .name("Catsize") + .internalName("catsize") + .columnType(TableColumnType.BOOL) + .isNullAllowed(true) + .view(VIEW_4) + .build(), + ViewColumn.builder() + .id(28L) + .ordinalPosition(16) + .name("Class Type") + .internalName("class_type") + .columnType(TableColumnType.DECIMAL) + .isNullAllowed(true) + .view(VIEW_4) + .build()); + public final static Long VIEW_5_ID = 5L; public final static Boolean VIEW_5_INITIAL_VIEW = false; public final static String VIEW_5_NAME = "Mock View"; @@ -5544,7 +5505,6 @@ public abstract class BaseTest { .columnType(TableColumnType.VARCHAR) .size(255L) .isNullAllowed(false) - .autoGenerated(false) .view(VIEW_5) .build(), ViewColumn.builder() @@ -5557,7 +5517,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_5) .build(), ViewColumn.builder() @@ -5570,7 +5529,6 @@ public abstract class BaseTest { .size(10L) .d(0L) .isNullAllowed(true) - .autoGenerated(false) .view(VIEW_5) .build()); diff --git a/dbrepo-metric-db/prometheus.yml b/dbrepo-metric-db/prometheus.yml index a3c1945b64..10df4f1895 100644 --- a/dbrepo-metric-db/prometheus.yml +++ b/dbrepo-metric-db/prometheus.yml @@ -17,3 +17,7 @@ scrape_configs: metrics_path: '/metrics' static_configs: - targets: ['ui:3000', 'auth-service:9000', 'analyse-service:8080', 'search-service:8080', 'data-db-sidecar:8080', 'broker-service:15692', 'storage-service:9090', 'upload-service:8080', 'dashboard-service:3000'] +# - job_name: 'gateway scrape' +# metrics_path: '/metrics' +# static_configs: +# - targets: ['dbrepo-gateway-service-sidecar:9113'] diff --git a/dbrepo-search-service/.gitignore b/dbrepo-search-service/.gitignore index 4acceedc9a..12a8c1aa36 100644 --- a/dbrepo-search-service/.gitignore +++ b/dbrepo-search-service/.gitignore @@ -10,6 +10,12 @@ __pycache__/ coverage.txt report.xml +# Libraries +./lib/dbrepo-1.4.4* +./lib/dbrepo-1.4.5* +./lib/dbrepo-1.4.6* +./lib/dbrepo-1.4.7rc* + # Distribution / packaging .Python build/ diff --git a/dbrepo-search-service/Pipfile.lock b/dbrepo-search-service/Pipfile.lock index 44765766be..0a41895317 100644 --- a/dbrepo-search-service/Pipfile.lock +++ b/dbrepo-search-service/Pipfile.lock @@ -388,7 +388,7 @@ }, "dbrepo": { "hashes": [ - "sha256:5aa92850231c25a57ffa58395e0f6bbda2818b1f0d4edd83f51fd8143d909451" + "sha256:654d487f1c0fd99b4978f5756aec4046f3e6019aeb225ecdd449768795f6e7e0" ], "markers": "python_version >= '3.11'", "path": "./lib/dbrepo-1.4.7.tar.gz" @@ -1690,101 +1690,107 @@ }, "yarl": { "hashes": [ - "sha256:047b258e00b99091b6f90355521f026238c63bd76dcf996d93527bb13320eefd", - "sha256:06ff23462398333c78b6f4f8d3d70410d657a471c2c5bbe6086133be43fc8f1a", - "sha256:07f9eaf57719d6721ab15805d85f4b01a5b509a0868d7320134371bcb652152d", - "sha256:0aa92e3e30a04f9462a25077db689c4ac5ea9ab6cc68a2e563881b987d42f16d", - "sha256:0cf21f46a15d445417de8fc89f2568852cf57fe8ca1ab3d19ddb24d45c0383ae", - "sha256:0fd7b941dd1b00b5f0acb97455fea2c4b7aac2dd31ea43fb9d155e9bc7b78664", - "sha256:147e36331f6f63e08a14640acf12369e041e0751bb70d9362df68c2d9dcf0c87", - "sha256:16a682a127930f3fc4e42583becca6049e1d7214bcad23520c590edd741d2114", - "sha256:176110bff341b6730f64a1eb3a7070e12b373cf1c910a9337e7c3240497db76f", - "sha256:19268b4fec1d7760134f2de46ef2608c2920134fb1fa61e451f679e41356dc55", - "sha256:1b16f6c75cffc2dc0616ea295abb0e1967601bd1fb1e0af6a1de1c6c887f3439", - "sha256:1bfc25aa6a7c99cf86564210f79a0b7d4484159c67e01232b116e445b3036547", - "sha256:1ca3894e9e9f72da93544f64988d9c052254a338a9f855165f37f51edb6591de", - "sha256:1dda53508df0de87b6e6b0a52d6718ff6c62a5aca8f5552748404963df639269", - "sha256:217a782020b875538eebf3948fac3a7f9bbbd0fd9bf8538f7c2ad7489e80f4e8", - "sha256:2192f718db4a8509f63dd6d950f143279211fa7e6a2c612edc17d85bf043d36e", - "sha256:29a84a46ec3ebae7a1c024c055612b11e9363a8a23238b3e905552d77a2bc51b", - "sha256:3007a5b75cb50140708420fe688c393e71139324df599434633019314ceb8b59", - "sha256:30600ba5db60f7c0820ef38a2568bb7379e1418ecc947a0f76fd8b2ff4257a97", - "sha256:337912bcdcf193ade64b9aae5a4017a0a1950caf8ca140362e361543c6773f21", - "sha256:37001e5d4621cef710c8dc1429ca04e189e572f128ab12312eab4e04cf007132", - "sha256:3d569f877ed9a708e4c71a2d13d2940cb0791da309f70bd970ac1a5c088a0a92", - "sha256:4009def9be3a7e5175db20aa2d7307ecd00bbf50f7f0f989300710eee1d0b0b9", - "sha256:46a9772a1efa93f9cd170ad33101c1817c77e0e9914d4fe33e2da299d7cf0f9b", - "sha256:47eede5d11d669ab3759b63afb70d28d5328c14744b8edba3323e27dc52d298d", - "sha256:498b3c55087b9d762636bca9b45f60d37e51d24341786dc01b81253f9552a607", - "sha256:4e0d45ebf975634468682c8bec021618b3ad52c37619e5c938f8f831fa1ac5c0", - "sha256:4f24f08b6c9b9818fd80612c97857d28f9779f0d1211653ece9844fc7b414df2", - "sha256:55c144d363ad4626ca744556c049c94e2b95096041ac87098bb363dcc8635e8d", - "sha256:582cedde49603f139be572252a318b30dc41039bc0b8165f070f279e5d12187f", - "sha256:587c3cc59bc148a9b1c07a019346eda2549bc9f468acd2f9824d185749acf0a6", - "sha256:5cd5dad8366e0168e0fd23d10705a603790484a6dbb9eb272b33673b8f2cce72", - "sha256:5d02d700705d67e09e1f57681f758f0b9d4412eeb70b2eb8d96ca6200b486db3", - "sha256:625f207b1799e95e7c823f42f473c1e9dbfb6192bd56bba8695656d92be4535f", - "sha256:659603d26d40dd4463200df9bfbc339fbfaed3fe32e5c432fe1dc2b5d4aa94b4", - "sha256:689a99a42ee4583fcb0d3a67a0204664aa1539684aed72bdafcbd505197a91c4", - "sha256:68ac1a09392ed6e3fd14be880d39b951d7b981fd135416db7d18a6208c536561", - "sha256:6a615cad11ec3428020fb3c5a88d85ce1b5c69fd66e9fcb91a7daa5e855325dd", - "sha256:73bedd2be05f48af19f0f2e9e1353921ce0c83f4a1c9e8556ecdcf1f1eae4892", - "sha256:742aef0a99844faaac200564ea6f5e08facb285d37ea18bd1a5acf2771f3255a", - "sha256:75ff4c819757f9bdb35de049a509814d6ce851fe26f06eb95a392a5640052482", - "sha256:781e2495e408a81e4eaeedeb41ba32b63b1980dddf8b60dbbeff6036bcd35049", - "sha256:7a9f917966d27f7ce30039fe8d900f913c5304134096554fd9bea0774bcda6d1", - "sha256:7e2637d75e92763d1322cb5041573279ec43a80c0f7fbbd2d64f5aee98447b17", - "sha256:8089d4634d8fa2b1806ce44fefa4979b1ab2c12c0bc7ef3dfa45c8a374811348", - "sha256:816d24f584edefcc5ca63428f0b38fee00b39fe64e3c5e558f895a18983efe96", - "sha256:8385ab36bf812e9d37cf7613999a87715f27ef67a53f0687d28c44b819df7cb0", - "sha256:85cb3e40eaa98489f1e2e8b29f5ad02ee1ee40d6ce6b88d50cf0f205de1d9d2c", - "sha256:8648180b34faaea4aa5b5ca7e871d9eb1277033fa439693855cf0ea9195f85f1", - "sha256:8892fa575ac9b1b25fae7b221bc4792a273877b9b56a99ee2d8d03eeb3dbb1d2", - "sha256:88c7d9d58aab0724b979ab5617330acb1c7030b79379c8138c1c8c94e121d1b3", - "sha256:8a2f8fb7f944bcdfecd4e8d855f84c703804a594da5123dd206f75036e536d4d", - "sha256:8f4e475f29a9122f908d0f1f706e1f2fc3656536ffd21014ff8a6f2e1b14d1d8", - "sha256:8f50eb3837012a937a2b649ec872b66ba9541ad9d6f103ddcafb8231cfcafd22", - "sha256:91d875f75fabf76b3018c5f196bf3d308ed2b49ddcb46c1576d6b075754a1393", - "sha256:94b2bb9bcfd5be9d27004ea4398fb640373dd0c1a9e219084f42c08f77a720ab", - "sha256:9557c9322aaa33174d285b0c1961fb32499d65ad1866155b7845edc876c3c835", - "sha256:95e16e9eaa2d7f5d87421b8fe694dd71606aa61d74b824c8d17fc85cc51983d1", - "sha256:96952f642ac69075e44c7d0284528938fdff39422a1d90d3e45ce40b72e5e2d9", - "sha256:985623575e5c4ea763056ffe0e2d63836f771a8c294b3de06d09480538316b13", - "sha256:99ff3744f5fe48288be6bc402533b38e89749623a43208e1d57091fc96b783b9", - "sha256:9abe80ae2c9d37c17599557b712e6515f4100a80efb2cda15f5f070306477cd2", - "sha256:a152751af7ef7b5d5fa6d215756e508dd05eb07d0cf2ba51f3e740076aa74373", - "sha256:a2e4725a08cb2b4794db09e350c86dee18202bb8286527210e13a1514dc9a59a", - "sha256:a56fbe3d7f3bce1d060ea18d2413a2ca9ca814eea7cedc4d247b5f338d54844e", - "sha256:ab3abc0b78a5dfaa4795a6afbe7b282b6aa88d81cf8c1bb5e394993d7cae3457", - "sha256:b03384eed107dbeb5f625a99dc3a7de8be04fc8480c9ad42fccbc73434170b20", - "sha256:b0547ab1e9345dc468cac8368d88ea4c5bd473ebc1d8d755347d7401982b5dd8", - "sha256:b4c1ecba93e7826dc71ddba75fb7740cdb52e7bd0be9f03136b83f54e6a1f511", - "sha256:b693c63e7e64b524f54aa4888403c680342d1ad0d97be1707c531584d6aeeb4f", - "sha256:b6d0147574ce2e7b812c989e50fa72bbc5338045411a836bd066ce5fc8ac0bce", - "sha256:b9cfef3f14f75bf6aba73a76caf61f9d00865912a04a4393c468a7ce0981b519", - "sha256:b9f805e37ed16cc212fdc538a608422d7517e7faf539bedea4fe69425bc55d76", - "sha256:bab03192091681d54e8225c53f270b0517637915d9297028409a2a5114ff4634", - "sha256:bc24f968b82455f336b79bf37dbb243b7d76cd40897489888d663d4e028f5069", - "sha256:c14b504a74e58e2deb0378b3eca10f3d076635c100f45b113c18c770b4a47a50", - "sha256:c2089a9afef887664115f7fa6d3c0edd6454adaca5488dba836ca91f60401075", - "sha256:c8ed4034f0765f8861620c1f2f2364d2e58520ea288497084dae880424fc0d9f", - "sha256:cd2660c01367eb3ef081b8fa0a5da7fe767f9427aa82023a961a5f28f0d4af6c", - "sha256:d8361c7d04e6a264481f0b802e395f647cd3f8bbe27acfa7c12049efea675bd1", - "sha256:d9baec588f015d0ee564057aa7574313c53a530662ffad930b7886becc85abdf", - "sha256:dbd9ff43a04f8ffe8a959a944c2dca10d22f5f99fc6a459f49c3ebfb409309d9", - "sha256:e3f8bfc1db82589ef965ed234b87de30d140db8b6dc50ada9e33951ccd8ec07a", - "sha256:e6a2c5c5bb2556dfbfffffc2bcfb9c235fd2b566d5006dfb2a37afc7e3278a07", - "sha256:e749af6c912a7bb441d105c50c1a3da720474e8acb91c89350080dd600228f0e", - "sha256:e85d86527baebb41a214cc3b45c17177177d900a2ad5783dbe6f291642d4906f", - "sha256:ee2c68e4f2dd1b1c15b849ba1c96fac105fca6ffdb7c1e8be51da6fabbdeafb9", - "sha256:f3ab950f8814f3b7b5e3eebc117986f817ec933676f68f0a6c5b2137dd7c9c69", - "sha256:f4f4547944d4f5cfcdc03f3f097d6f05bbbc915eaaf80a2ee120d0e756de377d", - "sha256:f72a0d746d38cb299b79ce3d4d60ba0892c84bbc905d0d49c13df5bace1b65f8", - "sha256:fc2c80bc87fba076e6cbb926216c27fba274dae7100a7b9a0983b53132dd99f2", - "sha256:fe4d2536c827f508348d7b40c08767e8c7071614250927233bf0c92170451c0a" + "sha256:0127bc2ea72c1eaae6808ace661f0edf222f32ffa987d37f2dbb4798288f2656", + "sha256:0358b697abdf1f2d68038bd02ef8ddcc4813835744f79c755f8743aa485585e7", + "sha256:06306c74f0775621a70fa5acd292119bbb6961d1f9a5f3d657a4c8c15b86f7b9", + "sha256:06b5b462cadf59c1df28ffbb0a3971fa16b60cf0c9d59a38bf5679a986d18685", + "sha256:097094a979af7b31520517c59179f6817b8426724343cecbec0eb3af1f8fb6cf", + "sha256:0c791a2d42da20ac568e5c0cc9b8af313188becd203a936ad959b578dafbcebb", + "sha256:1656a8b531a96427f26f498b7d0f19931166ff30e4344eca99bdb27faca14fc5", + "sha256:18614630533ac37ec373bd8035aec8fa4dd9aedac641209c06de7e082622ff77", + "sha256:1e5fa4c4e55cdacef1844f609bc9a02c8cd29c324a71ca1d3ee454701d4bb496", + "sha256:1edaf4171fc1582352ac5d9b2783966fa0f4ff86187279ef2a491613d23b894a", + "sha256:2124c642b8cc9b68e5981e429842dadc32bb850b010cccec9d24236253a19f60", + "sha256:229f222bb47cd7ab225648efd1ae47fe6943f18e4c91bce66471faf09fe33128", + "sha256:2429a651a2191c3fb8c9de21546c6046da539034d51dcb8df52302748004593d", + "sha256:25a4e29ee758596b2a0daffa4814714e9b464077ca862baf78ed0e8698e46b61", + "sha256:27c323b28723faed046f906c70466144c4dd12046a0128a301b29a65cfeff758", + "sha256:2add8ed2acf42398dfaa7dffd32e4d18ffbae341d62c8d4765bd9929336379b5", + "sha256:2bece7fdc13e23db005879b67190db0d397f6ba89c81dc7e3c77e9f5819aff7f", + "sha256:2eafb4e92f72a3b6c27f1d5e921d046e2728850af8887f86857c3fe868a5b5c0", + "sha256:32840ff92c713053591ff0e66845d4e9f4bea8fd5fba3da00f8d92e77722f24e", + "sha256:33896afca6fb4e1988c099534c52823870dfc8730bc6f96a3831f24c1e0ab814", + "sha256:350b468a217d433cbb4482e9414a14dfd360a3d5ab92013175925abb234364cc", + "sha256:38cab8f91b1085f1fd0765d40c46c8f43282f109018d5fcd017c46ac3eaba0cf", + "sha256:3e24a778470f3a9e9c11250d09daf5dea93369bc51aefca6605dbc963737a117", + "sha256:4224bbbc8a2e9b9a3828d36c1bab7458441d7fb9fb3af321eb735732ba8ee89d", + "sha256:4424082edff76fe46ff08851e91865097c0ad780fa79b87063dc5d5b80efc9d6", + "sha256:454707fb16f180984da6338d1f51897f0b8d8c4c2e0592d9d1e9fa02a5bb8218", + "sha256:4b1ab96a1ac91bd1233706d638ade35f663684deaa4e5e5f190858cba044afb9", + "sha256:4c5ff3e7609c214667c7d7e00d5f4f3576fefde47ebcb7e492c015117dafebbf", + "sha256:5107d89c9edec6ee077970a95fb9eeb4776ea8c2337b6a39c0ade9a58f50f3e4", + "sha256:5156c12a97405339ec93facbc7860566db381af2de1bec338195563fb64f37ef", + "sha256:553a1e3537aeeb29c0eb29ef28b80e0e801697fa71d96ac60675b284ff8e582a", + "sha256:5e1cc7823f43781390965c4762b54262cfcf76b6f152e489d00a5a1ac63063e4", + "sha256:5eef9804e65eb292e9c5587e88fe6a27a11f121d358312ac47211e8f42876751", + "sha256:6237637b496bc04819190e724a4e61ff2f251abf432f70cf491b3bc4a3f2f253", + "sha256:627bb5bc4ed3d3ebceb9fb55717cec6cd58bb47fdb5669169ebbc248e9bf156c", + "sha256:676d7356bb30825b7dbdad4fdd7a9feac379d074e5d4a36299767d72857ded42", + "sha256:6960b0d2e713e726cb2914e3051e080b12412f70dcb8731cf7a8fb52c37931bb", + "sha256:6b93a666cd8cfd43f605d1b81a32b9e290bf45c74c2bfd51ba705449c78448c7", + "sha256:6ca160b4c649f0d56daef04751eef4571de46ed4b80f9051a87d090fef32f08e", + "sha256:70ac7893e67a81ed1346ee3e71203ca4b0c3550c005b1d1cf87bc1e61eecd04b", + "sha256:73c4af08e9bb9a9aa7df6c789b05b924b9a0c6a368bb0e418d0b85181b64b631", + "sha256:748dcacc19c69957f7063ea4fb359fa2180735b1a638c81a4a96b86a382a6f29", + "sha256:75d9762f65205a86381298eb9079f27c60b84de0c262e402dcf45c6cbc385234", + "sha256:7711d83dafe52cda16ff2dd205cd83c05e4c06d5aaac596ae2cf7d50d094a530", + "sha256:7aa9f9af452c3e8486a0b88fddd58352e6cea17b691b18861d26e46cf65ffff0", + "sha256:7f713d8f3c4e2eac0d91b741e8ef2e1082022de244685601ec83e899b445d86a", + "sha256:81edbd9bf9f25cd995e6d51c307e1d279587d40b7473e258fef6d5e548560cd2", + "sha256:83363a5789f128618041b9a737c7b146f1965abddf4294b0444591406b437c1e", + "sha256:85e273e59b8b1a5f60a89df82cddeaf918181abd7ae7a2f2f899b68b0c774ff1", + "sha256:8ad2e487824ba4cda87851a371139e255410e45d3bf2e334194789278d709cec", + "sha256:8b7f902f13a230686f01bcff17cd9ba045653069811c8fd5027f0f414b417e2f", + "sha256:8f074a24aa9a6a3d406474ec889ebb5d661f329349068e05e8dfcb3c4be67752", + "sha256:9084d99933824ed8d665f10f4ce62d08fed714e7678d5ff11a8c2c98b2dc18f9", + "sha256:928f7a61c4311f3dd003af19bb779f99683f97a0559b765c80fdb8846dab0452", + "sha256:97fcaf530318369da3cfd6ff52f5ab38daf8cb10ecee9a76efebf8031de09eef", + "sha256:994d27b24b61b1870f3571395c840433faabec5dcd239bd11ff6af7e34234bb6", + "sha256:9ae454916aa3abe28d0ef1c21ca1e8e36a14ccf52183d465dfaccffaa7ed462c", + "sha256:9fac5416c44e8e1d8ea9440096f88e1a7273257f3157184c5c715060e0c448a1", + "sha256:a2fe45c1143eefb680a4589c55e671fabd482a7f8c7791f311ea3bcc20139246", + "sha256:a3f8be3e785009ffa148e66474fea5c787ccb203b3d0bd1f22e1e22f7da0f3b3", + "sha256:a616c2e4b60cb8cdd9eb3b0c6fda4ab5f3e26244b427aaade560dcf63c5754fb", + "sha256:a94c9058c5703c172904103d7b479f7e23dd4e5f8e67b49f6cd256d35ff169cb", + "sha256:b1208f2e081d34832f509cbe311237a0543effe23d60b2fa14c0d3f86e6d1d07", + "sha256:b4b25de7e85ba90b2ff230153123b6b000a7f69c41d84a3a0dc3f878334c8509", + "sha256:bbe72c41cdd55c88b238a8925849fde4069c0cdcdef83f8d967f8f3982659326", + "sha256:c0a86dd3e85c6aa3fc73236eb5cf7ce69dd8ad7abcd23f8ae1126831c8e40c2f", + "sha256:c3b08d9e98d1a15338fcfbd52c02003704322c2d460c9b9be7df08f2952bdce6", + "sha256:c4d9c221cc8e32b14196498679bf2b324bec1d1127c4ba934d98e19298faa661", + "sha256:c4f882e42c6cea89488b9a16919edde8c0b1a98f307c05abdd3dd3bc4368af40", + "sha256:c5cc25cbd9ae01d49ac7b504ef5f3cbdcc8d139f9750dcfa0b80d405b4645cc2", + "sha256:c7f2deac59dc3e0528bdded248e637e789e5111ba1723a8d7a262eb93e133e15", + "sha256:c8b034b60e74fb29064f765851e77e5910055e1c4a3cb75c32eccf2b470fc00f", + "sha256:c9b9159eeeb7cd1c7131dc7f5878454f97a4dc20cd157e6474174ccac448b844", + "sha256:c9c405ca78c70c3599d8956e53be0c9def9c51ad949964a49ad96c79729a5b1a", + "sha256:ceb200918c9bd163bd390cc169b254b23b4be121026b003be93a4f2f5b554b4b", + "sha256:d06040266b5e6512a37b4703684d1798124764b43328254799e9678c588882a6", + "sha256:d3f5e201bd170fb97c643e84df58e221372cd053fbb291ebbd878b165ea5057e", + "sha256:d4aa7cca009817789fd5b8e52e8122f9e85dc580c88b816a93321c00a8acbced", + "sha256:d772ae3c12d3b8629db656050c86ee66924eaa98f7125a889175a59cfaafdb19", + "sha256:d816969b55a970b3accc7f9e4ea8f60043e3f7de96f21c06063d747ffc2f18ba", + "sha256:d885dcdca7bae42bc9a2f6cbf766abcb2a6cc043b1905fc3782c6ea1f74a2b95", + "sha256:db903458a457a53ee0f764ed11c5b5368398e216b442c42dca9d90fbd2bbf31c", + "sha256:dc63bb79e896d6ce6aaf672ac304b54969280e949c45727867fc154a17ec7ab2", + "sha256:dd042e6c3bf36448e3e3ed302b12ce79762480f4aff8e7a167cdf8c35dc93297", + "sha256:ddea4abc4606c10dddb70651b210b7ab5b663148d6d7bc85d76963c923629891", + "sha256:df57f3c3ef760489f2e82192e6c93286c2bc80d6d854ef940e5345ae7153cd4b", + "sha256:e1ddf05eeb422810b1aa919095db0691493442eebbf9cfb0f1e478a7b2fbdf3d", + "sha256:e2e3cb74684ff357e6b3c82dd71031d3c1fd7ee9f9b0a5205e5568c963e074f9", + "sha256:e4f64c8c52dde564bf3251b41d7a6746564b0fc0516cebe9c9e6695224440d22", + "sha256:e4f7efb38331e8327c1cc7fb2a2905a7db03d1a7fdb04706bf6465d0e44d41d4", + "sha256:e61b2019ebb5345510b833c4dd1f4afb1f0c07753f86f184c63836ffc3fb08ba", + "sha256:e7e38bf6e52797084c5c396db5bb519615727e491e9003e2449631457bf77738", + "sha256:eae041f535fe2e57681954f7cccb81854d777ce4c2a87749428ebe6c71c02ec0", + "sha256:eb964d18c01b7a1263a6f07b88d63711fcd564fc429d934279cf12f4b467bf53", + "sha256:ef780f9d480ffb423380abeb4cfcad66ecb8f93526dfa367d322fdad9ec7c25f", + "sha256:efc0430b80ed834c80c99c32946cfc6ee29dfcd7c62ad3c8f15657322ade7942", + "sha256:f2508ee2bad8381b5254eadc35d32fe800d12eb2c63b744183341f3a66e435a7", + "sha256:fee9acd5e39c8611957074dfba06552e430020eea831caf5eb2cea30f10e06bd" ], "markers": "python_version >= '3.8'", - "version": "==1.14.0" + "version": "==1.15.0" } }, "develop": { diff --git a/dbrepo-search-service/init/.gitignore b/dbrepo-search-service/init/.gitignore new file mode 100644 index 0000000000..588a8e9445 --- /dev/null +++ b/dbrepo-search-service/init/.gitignore @@ -0,0 +1,5 @@ +# Libraries +./lib/dbrepo-1.4.4* +./lib/dbrepo-1.4.5* +./lib/dbrepo-1.4.6* +./lib/dbrepo-1.4.7rc* \ No newline at end of file diff --git a/dbrepo-search-service/init/Pipfile.lock b/dbrepo-search-service/init/Pipfile.lock index 8c6ddaeaa8..01e860ce11 100644 --- a/dbrepo-search-service/init/Pipfile.lock +++ b/dbrepo-search-service/init/Pipfile.lock @@ -1128,101 +1128,107 @@ }, "yarl": { "hashes": [ - "sha256:047b258e00b99091b6f90355521f026238c63bd76dcf996d93527bb13320eefd", - "sha256:06ff23462398333c78b6f4f8d3d70410d657a471c2c5bbe6086133be43fc8f1a", - "sha256:07f9eaf57719d6721ab15805d85f4b01a5b509a0868d7320134371bcb652152d", - "sha256:0aa92e3e30a04f9462a25077db689c4ac5ea9ab6cc68a2e563881b987d42f16d", - "sha256:0cf21f46a15d445417de8fc89f2568852cf57fe8ca1ab3d19ddb24d45c0383ae", - "sha256:0fd7b941dd1b00b5f0acb97455fea2c4b7aac2dd31ea43fb9d155e9bc7b78664", - "sha256:147e36331f6f63e08a14640acf12369e041e0751bb70d9362df68c2d9dcf0c87", - "sha256:16a682a127930f3fc4e42583becca6049e1d7214bcad23520c590edd741d2114", - "sha256:176110bff341b6730f64a1eb3a7070e12b373cf1c910a9337e7c3240497db76f", - "sha256:19268b4fec1d7760134f2de46ef2608c2920134fb1fa61e451f679e41356dc55", - "sha256:1b16f6c75cffc2dc0616ea295abb0e1967601bd1fb1e0af6a1de1c6c887f3439", - "sha256:1bfc25aa6a7c99cf86564210f79a0b7d4484159c67e01232b116e445b3036547", - "sha256:1ca3894e9e9f72da93544f64988d9c052254a338a9f855165f37f51edb6591de", - "sha256:1dda53508df0de87b6e6b0a52d6718ff6c62a5aca8f5552748404963df639269", - "sha256:217a782020b875538eebf3948fac3a7f9bbbd0fd9bf8538f7c2ad7489e80f4e8", - "sha256:2192f718db4a8509f63dd6d950f143279211fa7e6a2c612edc17d85bf043d36e", - "sha256:29a84a46ec3ebae7a1c024c055612b11e9363a8a23238b3e905552d77a2bc51b", - "sha256:3007a5b75cb50140708420fe688c393e71139324df599434633019314ceb8b59", - "sha256:30600ba5db60f7c0820ef38a2568bb7379e1418ecc947a0f76fd8b2ff4257a97", - "sha256:337912bcdcf193ade64b9aae5a4017a0a1950caf8ca140362e361543c6773f21", - "sha256:37001e5d4621cef710c8dc1429ca04e189e572f128ab12312eab4e04cf007132", - "sha256:3d569f877ed9a708e4c71a2d13d2940cb0791da309f70bd970ac1a5c088a0a92", - "sha256:4009def9be3a7e5175db20aa2d7307ecd00bbf50f7f0f989300710eee1d0b0b9", - "sha256:46a9772a1efa93f9cd170ad33101c1817c77e0e9914d4fe33e2da299d7cf0f9b", - "sha256:47eede5d11d669ab3759b63afb70d28d5328c14744b8edba3323e27dc52d298d", - "sha256:498b3c55087b9d762636bca9b45f60d37e51d24341786dc01b81253f9552a607", - "sha256:4e0d45ebf975634468682c8bec021618b3ad52c37619e5c938f8f831fa1ac5c0", - "sha256:4f24f08b6c9b9818fd80612c97857d28f9779f0d1211653ece9844fc7b414df2", - "sha256:55c144d363ad4626ca744556c049c94e2b95096041ac87098bb363dcc8635e8d", - "sha256:582cedde49603f139be572252a318b30dc41039bc0b8165f070f279e5d12187f", - "sha256:587c3cc59bc148a9b1c07a019346eda2549bc9f468acd2f9824d185749acf0a6", - "sha256:5cd5dad8366e0168e0fd23d10705a603790484a6dbb9eb272b33673b8f2cce72", - "sha256:5d02d700705d67e09e1f57681f758f0b9d4412eeb70b2eb8d96ca6200b486db3", - "sha256:625f207b1799e95e7c823f42f473c1e9dbfb6192bd56bba8695656d92be4535f", - "sha256:659603d26d40dd4463200df9bfbc339fbfaed3fe32e5c432fe1dc2b5d4aa94b4", - "sha256:689a99a42ee4583fcb0d3a67a0204664aa1539684aed72bdafcbd505197a91c4", - "sha256:68ac1a09392ed6e3fd14be880d39b951d7b981fd135416db7d18a6208c536561", - "sha256:6a615cad11ec3428020fb3c5a88d85ce1b5c69fd66e9fcb91a7daa5e855325dd", - "sha256:73bedd2be05f48af19f0f2e9e1353921ce0c83f4a1c9e8556ecdcf1f1eae4892", - "sha256:742aef0a99844faaac200564ea6f5e08facb285d37ea18bd1a5acf2771f3255a", - "sha256:75ff4c819757f9bdb35de049a509814d6ce851fe26f06eb95a392a5640052482", - "sha256:781e2495e408a81e4eaeedeb41ba32b63b1980dddf8b60dbbeff6036bcd35049", - "sha256:7a9f917966d27f7ce30039fe8d900f913c5304134096554fd9bea0774bcda6d1", - "sha256:7e2637d75e92763d1322cb5041573279ec43a80c0f7fbbd2d64f5aee98447b17", - "sha256:8089d4634d8fa2b1806ce44fefa4979b1ab2c12c0bc7ef3dfa45c8a374811348", - "sha256:816d24f584edefcc5ca63428f0b38fee00b39fe64e3c5e558f895a18983efe96", - "sha256:8385ab36bf812e9d37cf7613999a87715f27ef67a53f0687d28c44b819df7cb0", - "sha256:85cb3e40eaa98489f1e2e8b29f5ad02ee1ee40d6ce6b88d50cf0f205de1d9d2c", - "sha256:8648180b34faaea4aa5b5ca7e871d9eb1277033fa439693855cf0ea9195f85f1", - "sha256:8892fa575ac9b1b25fae7b221bc4792a273877b9b56a99ee2d8d03eeb3dbb1d2", - "sha256:88c7d9d58aab0724b979ab5617330acb1c7030b79379c8138c1c8c94e121d1b3", - "sha256:8a2f8fb7f944bcdfecd4e8d855f84c703804a594da5123dd206f75036e536d4d", - "sha256:8f4e475f29a9122f908d0f1f706e1f2fc3656536ffd21014ff8a6f2e1b14d1d8", - "sha256:8f50eb3837012a937a2b649ec872b66ba9541ad9d6f103ddcafb8231cfcafd22", - "sha256:91d875f75fabf76b3018c5f196bf3d308ed2b49ddcb46c1576d6b075754a1393", - "sha256:94b2bb9bcfd5be9d27004ea4398fb640373dd0c1a9e219084f42c08f77a720ab", - "sha256:9557c9322aaa33174d285b0c1961fb32499d65ad1866155b7845edc876c3c835", - "sha256:95e16e9eaa2d7f5d87421b8fe694dd71606aa61d74b824c8d17fc85cc51983d1", - "sha256:96952f642ac69075e44c7d0284528938fdff39422a1d90d3e45ce40b72e5e2d9", - "sha256:985623575e5c4ea763056ffe0e2d63836f771a8c294b3de06d09480538316b13", - "sha256:99ff3744f5fe48288be6bc402533b38e89749623a43208e1d57091fc96b783b9", - "sha256:9abe80ae2c9d37c17599557b712e6515f4100a80efb2cda15f5f070306477cd2", - "sha256:a152751af7ef7b5d5fa6d215756e508dd05eb07d0cf2ba51f3e740076aa74373", - "sha256:a2e4725a08cb2b4794db09e350c86dee18202bb8286527210e13a1514dc9a59a", - "sha256:a56fbe3d7f3bce1d060ea18d2413a2ca9ca814eea7cedc4d247b5f338d54844e", - "sha256:ab3abc0b78a5dfaa4795a6afbe7b282b6aa88d81cf8c1bb5e394993d7cae3457", - "sha256:b03384eed107dbeb5f625a99dc3a7de8be04fc8480c9ad42fccbc73434170b20", - "sha256:b0547ab1e9345dc468cac8368d88ea4c5bd473ebc1d8d755347d7401982b5dd8", - "sha256:b4c1ecba93e7826dc71ddba75fb7740cdb52e7bd0be9f03136b83f54e6a1f511", - "sha256:b693c63e7e64b524f54aa4888403c680342d1ad0d97be1707c531584d6aeeb4f", - "sha256:b6d0147574ce2e7b812c989e50fa72bbc5338045411a836bd066ce5fc8ac0bce", - "sha256:b9cfef3f14f75bf6aba73a76caf61f9d00865912a04a4393c468a7ce0981b519", - "sha256:b9f805e37ed16cc212fdc538a608422d7517e7faf539bedea4fe69425bc55d76", - "sha256:bab03192091681d54e8225c53f270b0517637915d9297028409a2a5114ff4634", - "sha256:bc24f968b82455f336b79bf37dbb243b7d76cd40897489888d663d4e028f5069", - "sha256:c14b504a74e58e2deb0378b3eca10f3d076635c100f45b113c18c770b4a47a50", - "sha256:c2089a9afef887664115f7fa6d3c0edd6454adaca5488dba836ca91f60401075", - "sha256:c8ed4034f0765f8861620c1f2f2364d2e58520ea288497084dae880424fc0d9f", - "sha256:cd2660c01367eb3ef081b8fa0a5da7fe767f9427aa82023a961a5f28f0d4af6c", - "sha256:d8361c7d04e6a264481f0b802e395f647cd3f8bbe27acfa7c12049efea675bd1", - "sha256:d9baec588f015d0ee564057aa7574313c53a530662ffad930b7886becc85abdf", - "sha256:dbd9ff43a04f8ffe8a959a944c2dca10d22f5f99fc6a459f49c3ebfb409309d9", - "sha256:e3f8bfc1db82589ef965ed234b87de30d140db8b6dc50ada9e33951ccd8ec07a", - "sha256:e6a2c5c5bb2556dfbfffffc2bcfb9c235fd2b566d5006dfb2a37afc7e3278a07", - "sha256:e749af6c912a7bb441d105c50c1a3da720474e8acb91c89350080dd600228f0e", - "sha256:e85d86527baebb41a214cc3b45c17177177d900a2ad5783dbe6f291642d4906f", - "sha256:ee2c68e4f2dd1b1c15b849ba1c96fac105fca6ffdb7c1e8be51da6fabbdeafb9", - "sha256:f3ab950f8814f3b7b5e3eebc117986f817ec933676f68f0a6c5b2137dd7c9c69", - "sha256:f4f4547944d4f5cfcdc03f3f097d6f05bbbc915eaaf80a2ee120d0e756de377d", - "sha256:f72a0d746d38cb299b79ce3d4d60ba0892c84bbc905d0d49c13df5bace1b65f8", - "sha256:fc2c80bc87fba076e6cbb926216c27fba274dae7100a7b9a0983b53132dd99f2", - "sha256:fe4d2536c827f508348d7b40c08767e8c7071614250927233bf0c92170451c0a" + "sha256:0127bc2ea72c1eaae6808ace661f0edf222f32ffa987d37f2dbb4798288f2656", + "sha256:0358b697abdf1f2d68038bd02ef8ddcc4813835744f79c755f8743aa485585e7", + "sha256:06306c74f0775621a70fa5acd292119bbb6961d1f9a5f3d657a4c8c15b86f7b9", + "sha256:06b5b462cadf59c1df28ffbb0a3971fa16b60cf0c9d59a38bf5679a986d18685", + "sha256:097094a979af7b31520517c59179f6817b8426724343cecbec0eb3af1f8fb6cf", + "sha256:0c791a2d42da20ac568e5c0cc9b8af313188becd203a936ad959b578dafbcebb", + "sha256:1656a8b531a96427f26f498b7d0f19931166ff30e4344eca99bdb27faca14fc5", + "sha256:18614630533ac37ec373bd8035aec8fa4dd9aedac641209c06de7e082622ff77", + "sha256:1e5fa4c4e55cdacef1844f609bc9a02c8cd29c324a71ca1d3ee454701d4bb496", + "sha256:1edaf4171fc1582352ac5d9b2783966fa0f4ff86187279ef2a491613d23b894a", + "sha256:2124c642b8cc9b68e5981e429842dadc32bb850b010cccec9d24236253a19f60", + "sha256:229f222bb47cd7ab225648efd1ae47fe6943f18e4c91bce66471faf09fe33128", + "sha256:2429a651a2191c3fb8c9de21546c6046da539034d51dcb8df52302748004593d", + "sha256:25a4e29ee758596b2a0daffa4814714e9b464077ca862baf78ed0e8698e46b61", + "sha256:27c323b28723faed046f906c70466144c4dd12046a0128a301b29a65cfeff758", + "sha256:2add8ed2acf42398dfaa7dffd32e4d18ffbae341d62c8d4765bd9929336379b5", + "sha256:2bece7fdc13e23db005879b67190db0d397f6ba89c81dc7e3c77e9f5819aff7f", + "sha256:2eafb4e92f72a3b6c27f1d5e921d046e2728850af8887f86857c3fe868a5b5c0", + "sha256:32840ff92c713053591ff0e66845d4e9f4bea8fd5fba3da00f8d92e77722f24e", + "sha256:33896afca6fb4e1988c099534c52823870dfc8730bc6f96a3831f24c1e0ab814", + "sha256:350b468a217d433cbb4482e9414a14dfd360a3d5ab92013175925abb234364cc", + "sha256:38cab8f91b1085f1fd0765d40c46c8f43282f109018d5fcd017c46ac3eaba0cf", + "sha256:3e24a778470f3a9e9c11250d09daf5dea93369bc51aefca6605dbc963737a117", + "sha256:4224bbbc8a2e9b9a3828d36c1bab7458441d7fb9fb3af321eb735732ba8ee89d", + "sha256:4424082edff76fe46ff08851e91865097c0ad780fa79b87063dc5d5b80efc9d6", + "sha256:454707fb16f180984da6338d1f51897f0b8d8c4c2e0592d9d1e9fa02a5bb8218", + "sha256:4b1ab96a1ac91bd1233706d638ade35f663684deaa4e5e5f190858cba044afb9", + "sha256:4c5ff3e7609c214667c7d7e00d5f4f3576fefde47ebcb7e492c015117dafebbf", + "sha256:5107d89c9edec6ee077970a95fb9eeb4776ea8c2337b6a39c0ade9a58f50f3e4", + "sha256:5156c12a97405339ec93facbc7860566db381af2de1bec338195563fb64f37ef", + "sha256:553a1e3537aeeb29c0eb29ef28b80e0e801697fa71d96ac60675b284ff8e582a", + "sha256:5e1cc7823f43781390965c4762b54262cfcf76b6f152e489d00a5a1ac63063e4", + "sha256:5eef9804e65eb292e9c5587e88fe6a27a11f121d358312ac47211e8f42876751", + "sha256:6237637b496bc04819190e724a4e61ff2f251abf432f70cf491b3bc4a3f2f253", + "sha256:627bb5bc4ed3d3ebceb9fb55717cec6cd58bb47fdb5669169ebbc248e9bf156c", + "sha256:676d7356bb30825b7dbdad4fdd7a9feac379d074e5d4a36299767d72857ded42", + "sha256:6960b0d2e713e726cb2914e3051e080b12412f70dcb8731cf7a8fb52c37931bb", + "sha256:6b93a666cd8cfd43f605d1b81a32b9e290bf45c74c2bfd51ba705449c78448c7", + "sha256:6ca160b4c649f0d56daef04751eef4571de46ed4b80f9051a87d090fef32f08e", + "sha256:70ac7893e67a81ed1346ee3e71203ca4b0c3550c005b1d1cf87bc1e61eecd04b", + "sha256:73c4af08e9bb9a9aa7df6c789b05b924b9a0c6a368bb0e418d0b85181b64b631", + "sha256:748dcacc19c69957f7063ea4fb359fa2180735b1a638c81a4a96b86a382a6f29", + "sha256:75d9762f65205a86381298eb9079f27c60b84de0c262e402dcf45c6cbc385234", + "sha256:7711d83dafe52cda16ff2dd205cd83c05e4c06d5aaac596ae2cf7d50d094a530", + "sha256:7aa9f9af452c3e8486a0b88fddd58352e6cea17b691b18861d26e46cf65ffff0", + "sha256:7f713d8f3c4e2eac0d91b741e8ef2e1082022de244685601ec83e899b445d86a", + "sha256:81edbd9bf9f25cd995e6d51c307e1d279587d40b7473e258fef6d5e548560cd2", + "sha256:83363a5789f128618041b9a737c7b146f1965abddf4294b0444591406b437c1e", + "sha256:85e273e59b8b1a5f60a89df82cddeaf918181abd7ae7a2f2f899b68b0c774ff1", + "sha256:8ad2e487824ba4cda87851a371139e255410e45d3bf2e334194789278d709cec", + "sha256:8b7f902f13a230686f01bcff17cd9ba045653069811c8fd5027f0f414b417e2f", + "sha256:8f074a24aa9a6a3d406474ec889ebb5d661f329349068e05e8dfcb3c4be67752", + "sha256:9084d99933824ed8d665f10f4ce62d08fed714e7678d5ff11a8c2c98b2dc18f9", + "sha256:928f7a61c4311f3dd003af19bb779f99683f97a0559b765c80fdb8846dab0452", + "sha256:97fcaf530318369da3cfd6ff52f5ab38daf8cb10ecee9a76efebf8031de09eef", + "sha256:994d27b24b61b1870f3571395c840433faabec5dcd239bd11ff6af7e34234bb6", + "sha256:9ae454916aa3abe28d0ef1c21ca1e8e36a14ccf52183d465dfaccffaa7ed462c", + "sha256:9fac5416c44e8e1d8ea9440096f88e1a7273257f3157184c5c715060e0c448a1", + "sha256:a2fe45c1143eefb680a4589c55e671fabd482a7f8c7791f311ea3bcc20139246", + "sha256:a3f8be3e785009ffa148e66474fea5c787ccb203b3d0bd1f22e1e22f7da0f3b3", + "sha256:a616c2e4b60cb8cdd9eb3b0c6fda4ab5f3e26244b427aaade560dcf63c5754fb", + "sha256:a94c9058c5703c172904103d7b479f7e23dd4e5f8e67b49f6cd256d35ff169cb", + "sha256:b1208f2e081d34832f509cbe311237a0543effe23d60b2fa14c0d3f86e6d1d07", + "sha256:b4b25de7e85ba90b2ff230153123b6b000a7f69c41d84a3a0dc3f878334c8509", + "sha256:bbe72c41cdd55c88b238a8925849fde4069c0cdcdef83f8d967f8f3982659326", + "sha256:c0a86dd3e85c6aa3fc73236eb5cf7ce69dd8ad7abcd23f8ae1126831c8e40c2f", + "sha256:c3b08d9e98d1a15338fcfbd52c02003704322c2d460c9b9be7df08f2952bdce6", + "sha256:c4d9c221cc8e32b14196498679bf2b324bec1d1127c4ba934d98e19298faa661", + "sha256:c4f882e42c6cea89488b9a16919edde8c0b1a98f307c05abdd3dd3bc4368af40", + "sha256:c5cc25cbd9ae01d49ac7b504ef5f3cbdcc8d139f9750dcfa0b80d405b4645cc2", + "sha256:c7f2deac59dc3e0528bdded248e637e789e5111ba1723a8d7a262eb93e133e15", + "sha256:c8b034b60e74fb29064f765851e77e5910055e1c4a3cb75c32eccf2b470fc00f", + "sha256:c9b9159eeeb7cd1c7131dc7f5878454f97a4dc20cd157e6474174ccac448b844", + "sha256:c9c405ca78c70c3599d8956e53be0c9def9c51ad949964a49ad96c79729a5b1a", + "sha256:ceb200918c9bd163bd390cc169b254b23b4be121026b003be93a4f2f5b554b4b", + "sha256:d06040266b5e6512a37b4703684d1798124764b43328254799e9678c588882a6", + "sha256:d3f5e201bd170fb97c643e84df58e221372cd053fbb291ebbd878b165ea5057e", + "sha256:d4aa7cca009817789fd5b8e52e8122f9e85dc580c88b816a93321c00a8acbced", + "sha256:d772ae3c12d3b8629db656050c86ee66924eaa98f7125a889175a59cfaafdb19", + "sha256:d816969b55a970b3accc7f9e4ea8f60043e3f7de96f21c06063d747ffc2f18ba", + "sha256:d885dcdca7bae42bc9a2f6cbf766abcb2a6cc043b1905fc3782c6ea1f74a2b95", + "sha256:db903458a457a53ee0f764ed11c5b5368398e216b442c42dca9d90fbd2bbf31c", + "sha256:dc63bb79e896d6ce6aaf672ac304b54969280e949c45727867fc154a17ec7ab2", + "sha256:dd042e6c3bf36448e3e3ed302b12ce79762480f4aff8e7a167cdf8c35dc93297", + "sha256:ddea4abc4606c10dddb70651b210b7ab5b663148d6d7bc85d76963c923629891", + "sha256:df57f3c3ef760489f2e82192e6c93286c2bc80d6d854ef940e5345ae7153cd4b", + "sha256:e1ddf05eeb422810b1aa919095db0691493442eebbf9cfb0f1e478a7b2fbdf3d", + "sha256:e2e3cb74684ff357e6b3c82dd71031d3c1fd7ee9f9b0a5205e5568c963e074f9", + "sha256:e4f64c8c52dde564bf3251b41d7a6746564b0fc0516cebe9c9e6695224440d22", + "sha256:e4f7efb38331e8327c1cc7fb2a2905a7db03d1a7fdb04706bf6465d0e44d41d4", + "sha256:e61b2019ebb5345510b833c4dd1f4afb1f0c07753f86f184c63836ffc3fb08ba", + "sha256:e7e38bf6e52797084c5c396db5bb519615727e491e9003e2449631457bf77738", + "sha256:eae041f535fe2e57681954f7cccb81854d777ce4c2a87749428ebe6c71c02ec0", + "sha256:eb964d18c01b7a1263a6f07b88d63711fcd564fc429d934279cf12f4b467bf53", + "sha256:ef780f9d480ffb423380abeb4cfcad66ecb8f93526dfa367d322fdad9ec7c25f", + "sha256:efc0430b80ed834c80c99c32946cfc6ee29dfcd7c62ad3c8f15657322ade7942", + "sha256:f2508ee2bad8381b5254eadc35d32fe800d12eb2c63b744183341f3a66e435a7", + "sha256:fee9acd5e39c8611957074dfba06552e430020eea831caf5eb2cea30f10e06bd" ], "markers": "python_version >= '3.8'", - "version": "==1.14.0" + "version": "==1.15.0" } }, "develop": { diff --git a/dbrepo-search-service/init/lib/dbrepo-1.4.7.tar.gz b/dbrepo-search-service/init/lib/dbrepo-1.4.7.tar.gz index 5774a413a678f3179e5e215737c5e39f5a773ef8..936ec4dac16fe8f065ac7d37a09aedca421086a6 100644 GIT binary patch delta 31394 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 delta 31325 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 diff --git a/dbrepo-search-service/init/test/test_app.py b/dbrepo-search-service/init/test/test_app.py index a8e6d9755b..0df10e51c7 100644 --- a/dbrepo-search-service/init/test/test_app.py +++ b/dbrepo-search-service/init/test/test_app.py @@ -41,7 +41,6 @@ class OpenSearchClientTest(unittest.TestCase): internal_name="id", database_id=req.id, table_id=1, - auto_generated=True, column_type=ColumnType.BIGINT, is_public=True, is_null_allowed=False)])] @@ -90,6 +89,5 @@ class OpenSearchClientTest(unittest.TestCase): self.assertEqual(ColumnType.BIGINT, database.tables[0].columns[0].column_type) self.assertEqual(1, database.tables[0].columns[0].database_id) self.assertEqual(1, database.tables[0].columns[0].table_id) - self.assertEqual(True, database.tables[0].columns[0].auto_generated) self.assertEqual(True, database.tables[0].columns[0].is_public) self.assertEqual(False, database.tables[0].columns[0].is_null_allowed) diff --git a/dbrepo-search-service/lib/dbrepo-1.4.7.tar.gz b/dbrepo-search-service/lib/dbrepo-1.4.7.tar.gz index 5774a413a678f3179e5e215737c5e39f5a773ef8..936ec4dac16fe8f065ac7d37a09aedca421086a6 100644 GIT binary patch delta 31394 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 delta 31325 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 diff --git a/dbrepo-search-service/test/test_opensearch_client.py b/dbrepo-search-service/test/test_opensearch_client.py index 2bab038128..adf421af74 100644 --- a/dbrepo-search-service/test/test_opensearch_client.py +++ b/dbrepo-search-service/test/test_opensearch_client.py @@ -55,8 +55,8 @@ req = Database(id=1, routing_key="dbrepo.1.1", is_public=True, columns=[Column(id=1, database_id=1, table_id=1, name="ID", internal_name="id", - auto_generated=True, column_type=ColumnType.BIGINT, is_public=True, - is_null_allowed=False, size=20, d=0, + column_type=ColumnType.BIGINT, is_public=True, is_null_allowed=False, + size=20, d=0, concept=Concept(id=1, uri="http://www.wikidata.org/entity/Q2221906", created=datetime.datetime(2024, 3, 1, 10, tzinfo=datetime.timezone.utc)), @@ -104,7 +104,6 @@ class OpenSearchClientTest(unittest.TestCase): internal_name="id", database_id=req.id, table_id=1, - auto_generated=True, column_type=ColumnType.BIGINT, is_public=True, is_null_allowed=False)])] @@ -153,7 +152,6 @@ class OpenSearchClientTest(unittest.TestCase): self.assertEqual(ColumnType.BIGINT, database.tables[0].columns[0].column_type) self.assertEqual(1, database.tables[0].columns[0].database_id) self.assertEqual(1, database.tables[0].columns[0].table_id) - self.assertEqual(True, database.tables[0].columns[0].auto_generated) self.assertEqual(True, database.tables[0].columns[0].is_public) self.assertEqual(False, database.tables[0].columns[0].is_null_allowed) @@ -308,4 +306,3 @@ class OpenSearchClientTest(unittest.TestCase): # response = client.general_search(type="database", field_value_pairs={"name": "Test", # "id": None}) # self.assertTrue(len(response) > 0) - diff --git a/dbrepo-ui/bun.lockb b/dbrepo-ui/bun.lockb index 32e73e364f9bd9e573f92d3f4a72d9596cb21363..3f85eb8de9c7a334e2a6a89d3cbcf75254751610 100755 GIT binary patch delta 55131 zcmex3SNz%n@d<jGi%yux{B~^kx^x*^t6@(g^96<A)E^JOGg`@tMsD7^knz}gRt6B* zI5AwFDR<e#3Wa(`CI$up28M<-CI$w628M=<j0_Ci3=9pSObiTy3=9p)#l<C+1*r^g z85tNv7#JFMGDE}<Fhb}s76t|(28M=HEDQ|13=9o>p>%3qNoGlAYVigr{|;1rL4I*b za&a+3E*k>_7Xw3mLtbKDer5^-gBBYD0}lg3gE>0`gERv}gAOCaK_?l&3L9RrGcZUn zFf@oUGBAiSFf^2vrt0RVmLw{3GB9v5Ff?#O9iE(#SX82yRs4<<;vgnQh<sv2W_~dP z1H%a}h=+G^F);8k)H5_}<bo(z#|^P4H#0X?HzkQ-J~zYxMLZyd3=N6Jm3hh8nI&Ht zAO^SdLiF9_h44@FLey38LiFwBgM?&JYDrNg0|Ub*C_fV_p8(Py!@$rG4q`AcG<ZS{ z=oWw&_)Y-g(r`gY$hZkYg8Y^MBr0r$AoM~gT_(W5Aj-hdV8;uw_{HQxCV9m_A`A?| z3=9ohMIgF!^YcMTfMJaY#QC2lZ)6hBye9^+!&4mM2^(>U8!{4$^UL!X816y&U&JA1 zzZQq+Hipt#P`X$WV%rNzNNgoaLXt;%enASz+AEU{nZ+5yCVMi=2YSgt%$g?$v0G6N z;vYUah#9465SRXzh47<fArVxWn41GKt2D15r!+k?k5`d_L7ai1;osz)%<_T#N)VR` zDnWdbS*)9$lb^)kqYTl_3>Cko3<-}PiV#;M6(uI87Bes`R)MH{sRGe&Jz0}Q-_l+d zVrp`JURqLq1w()Wgr8NMpJ&Rzz~Bz$A5(|u&P^>!Pc>p-*fx10i+Fv#2E+#rnh>A% zXhM?6GIdA{n=3%*#Nra&?937dRRu_>J<x)P3n@VK7v<;Vlol{BoX}-pkY!+KSfk6p zAj81W&=2L8=`t`#GB7km=rS<KF)%ck=rS;<fHIkgE(3!C14F|%9f-tb9R>zv28M=> zIt&a-3=9pEbQl=q85kOhp>!xzof(ubr310(zcwUu_G?3u2b%)KL&+u(b39BS@@6Iw z54@BG(cBCTD$ww2oxG7%JyP2o67~w_kg)$`!N8!%z|b(y65_lbOOQ5(h6YQB@wcrY zc|Nr`IWZ?OCH0&Y#QI%UkQB4d3ZkxjvLTyz{bdV?XHMHPFsLywG_10PnBHd#@kEUU zB=jrnA)y#+4{>xZRD8At#C2yKAfYes2#M?DjKrL51_p-tj*yg*kyxyomXnwcOSe-T z!M-tS*zN>z9-A{HF?3r%3|i_8i5^}TNP_KihR{1E|725lEVhL>W1j^i8?Ui|1VX$8 z#Jcp<JWvV5P@0#STaaH=GEWv_3(R?YCnvI}OFr|0h!*E07H2RpFx>TmIR4P&hwSo< zCnhs;s57pbtjXbSc;6qAs4n?KbR6@C1Y$vANrrBAYUM5{A6Aa7pS+MmTya|<B=9<e zAi7|xm-<8e8b0|ZhkSjuFC++yk}W|wl_A;;VpmyaNh(O7B(<nGwTOX1BMjol_ArQU zp)g297bg~j%4&v?aER+ui<3$-b5a;)MM6TXB@&`84@yTsX(tF>-=G@_2}H?AND5(v z(jOxr{JT*4B$VC?r58f!UMO7^0daUbln#N?j!;@Z0^$K#D9sI~>lqq;hC?KtL+O}M zh!3qoAvr}g6ym^$L`af<nFxvf+li3a7J$nCOoD`fO)@0h7bHW>nUoAs#}o>oe}q89 zSEVp8aOE&CG{B-Wtynj;qNFG>GZhlOpb{%BGba^R{^Ls3(A12PnBRmz%(<8jaahpg zhg|aYR%Vd$zA~{W9Tam%Ga;%f4K4CO5xx`3@6CclU{e-2uQaU4gd~)inGo+K=VX>< zGB7aw%7&N@OBneDsbF(5i*?J3a~K$Q=0N0E=76(SeM5#Z$QlNQqQsQU3S$O_rMZxB zNiNDSE-o)-(1jL2+GY@o6wDwF(9H)M&`^?CkeHN{$^c7gu!w~v09ZnTMKmlyea;7^ z#CnDXSPFrp0EPxwN`oa;Sc-!sVOY|Ir6^cRge4qUii9O?Sc-$CY*<PKC;1cxh6Y%Y zg{8RU;$l$Sih-jX<U)pq@0E}!O0R-M!Idg#2o)En7AG?>ysm^qS#eo<J}4~zR6}z3 zr)o&bYM=a&M_jSC2Ey~Gh3K||(#gfey5$*(C2J;2^6J+wsfJ{;OO=okZ%-w}4RabG zq5c_4KW%`RvJ5Ier5s{sS0$vVF0F**k{GBtR+W(4qXhK}OC>b-R6ugi$qH~iSKqLq z0%Gxu3W%qhD<B4CL;1=1Ir&8?3=Dx43=C4BHd6&8pKDY=96GNZ;!QrN{LgZT{`=(+ z^~cL0=5B-r?!t0NGU_M?1!6rzLlIQse;Fj9Cg-Fk7BMg|h?s#CFf{mfL(-vBHzY*< znL;e~>w#D#)(i33h8~E8u*&O84<rPN%hGjA64Q%c_dv{l1f@^)Ffd5egWAtfg+3D) z7_=A|8lomLFc>i~H0VuaV9;S;XyBL#sU7(zKrDJQ0TSf86Ckzc8&gODb`9#V8?um` zx>FY7@a(A&A7|!)@+$+w;i(Yu{It}P`s54-22kPyHSA$oHEt>-ZqqYMbU}@noaqpk zub&PH>aS3KX0dKDsOk!s3P~HunYx*IY55GRWg+}eGa(^VP?VorP*TjWVirVyc1~(3 zD1?({F-$(pFDePE*I+eMN@iLbC|y68{E=VW@c2wf0?7s?gv{cS2XnzGr(xGzNU+SD z3u!d;%!dTWmdTa^^7We+K<q*<j+QNiBp+yT)G&P^BrvWlf&}8pMUYr7SPT)5f%-vZ zCL}einh7y?(GrNO`j$ZQ&)k`iFq^s*tiQgY1FF$r86+_3pc>P15=%-_Qy2=N8iHp+ z0yinMs34hvfx&4eB=*=>KnyNQO92Tp{8<h*xZ(41h<g5&5DP)&Y(`=ULvChC2`JDE zW`aCY&(OfL3gUx_(AGzlEX07)yo}Vu6b1&4)ewjMS_Pr2Ai@kOP<8oGIuKeOXXY2B zreqc~h_8b<jC&m<ME<XZ&~Mj*EM{o9x0Zo{AJo=ONzE%PO=Vy>w-%EA_O6BatbFoE zLHYWx8z2GsVgtk<_n`dDVl$JZ%o2u}O^}E>wE<!s>t=|*L**dey1oSx?c29NlEaKG zkm#?3($QNWxy5b^r0uA*1(Ivnw}1<v`i3`~!HkAWn<4pj2b7+_84|M-H$%duZ8Id? zJfPuV2Bk~$$`gxo85q2GL;QbrH$>f;-4KTsBo-B?mKNm{r{;k>RM+=F)ScM_Qm4$& zkeaHSmRVF>au6)Q(C~CGL_u*$Vo7OnYVq~ShQj`aR=XjgrU$h~W;Z05VQpL6gCOG= z8cOq0GLthI82(S*C@fwt40S|GX+chEMQRbOvV_%Xu(}Rbx54Tza2>_KKxwNi3SP&- zYGqiZ3#&w7l_ae8hSk=vN*PwU!s^JB{1V-QqWpr3lNXApOBSAnBp#pBki;N+1`=2K zlOKwx*GHU%!~pLZNWzmm2MNOMry=}3=O6){T$HS9Y{bA|bQ+>NCqD(;6z@Hc!}K$d zppL!(Ns^hxiA6<;l??tDAm)L4uM7<J4C<F43Uf2_G7A!miv=%1stoidBF80&L+@RN zIPBtONM3-osZg4VpdlS-+wAyNh=XBmGgu4o$3>7ipe7D9e2PnoQWJA481k<}9F%+= z;?g9OL{M455P2QqQ_1TPheV%-$ip1!0Of;6R2Uc-IG|~q@fM_I^7bYqB<|jVgs{bJ z1_mxr-iKwH%eNpF`~XRSYVXMl#nd^A?}FUP(2z0tqL{kp*Lx7dp5B9q!XkCmeTbuO z-h((QJ+U+$)F-+A01`^4p!EI+5YKI$>?kf@59@*7zX=JW%QqpqPu_&MBq=j5B{MI* zSn3JHw(q+jPJgruQdt$}<|l!|hVd!HYpb6^Oh3L0Qd|_J7U$=br7}Eu1}SfDJ%gBg z<{8+&`i87$5NAg|gBYCm0+L3(AqpC{?1B_*^Pv`Y?1Fgz<x7Y|p{a=B!ApoaCA%OF zf%OxUc0me&;@6M@kn;`1;on|^%w=Y1aGRVcAzy!&0pjk<&{4UR#FA9qw7lYdQ1SH) z5NDachd8r1BQqP+J~;Ls61vLoA=V1NhlCTl{H+fV^TR$uoc;41l>P_~kNSq&A0Zl> zK0z$F@CoAX8}A_Q4f+BxpfoQZG|b45_6_2o^3<e)#N=#-x8EWD@BR)B*oGV5A^OgI zhghWY6GA6um4V`m;m}V=Ilk^E$l=Tk4f7{AN{ZJD{e)P1{0GE3Sh;x^YW%kE5dY5n z4yh;Vp~h?d1^c5x@h`*~Fn+;zh%@89L(Fyg4zbqwKPdPa8sz>%oO$X$Sbu#3$A3uX z4`5&fkGnqo2N}^h_79SPq@V`%GctmQiWry}88kr6!taoVs|Pb9c$n3YnGrmACIzMM zFfoFMlzuQVf=7nfze5~g#R{=!$7fLZ)H5_}`34EV(mc?ZSZ2EHH%P(}{036M(D3;y zq^9&@X9N!rKVX9xaGs43Jg^L_OHO@dV9;b>XgI^c2p-=x<AgX=@CzgaSAK<<+x8XW z!Q!tB48ouW?!V6vmwo>N9^`6>{tEG#=T}G&8hnM+xYA!CLHFu2C<Z~ptc(nN3=9oR zc_H*<UWfzJGV@YE4bu`nM(_xDCX_DF&B;$rEJ-cU&B@HoEMdsxXJn`c4Uwl-q$Yz3 zJoJH-{JhkX%-mFl+|1m}WZks93!foz`Qi&Cj_*Q~=x#wq@W}NAs82n<faA8o4oa6K zCMALTq()yLA*v$G2p+0``;MU=JXF3<m=QcCzd;z{6S*%CA07e65ktcgsE?<7hUA$> zXo%%P#aZ7&qHrMtgr30wNtDeDkPrjq0MM9z90Md|w}?YRrX*!@mkgibLUBg$$TEv0 zB*}b`fH>!#1SCMWNHBti_#5^~FoLHR&Q3llBVR8h%?KX9cY<1`$N-7oSQ$uy6lH+; zHdz*ua6M%i!96t4cz>p$Mcy7ci0SIG5L1QZ8Np+o0dkDs(QgF>h<u#_#C5z-I<>f< zC^eNKiXl-E66`Dr5E>+rnVZOvT3lL^nN!SQCJWJ6l3$!(T9lkBDGLc*K3RzG4=O_v za%Qn^MoCFQadByKQDSi_!}`ewWyKX6RUxWMGE(z0(<&Ltp!|6%kYvAR^H16T(j0Tl zv=irb-(J1>hvfxEM(fEZt?d~nPUf_+XBA{(U~rktYh%q?%EZ9n1ZHh#VqmZWvpzC0 zFt~wOjOLR)ZS7fenHd;-Ci~jiurNa<SOr)>EMFTN78V8u53t(nlRNF~86_v5w6kZ7 zp3G@)&$@z@fx%|-*-RT2R*-658*4_h$tUgY8OtYgI@mKFob2gf&-it6r-MCb5IX}y z5CcO4<77d5bH*i;IUVhpm^dbTIodJWPwsTIXPiFyq@z9K>&cu>_KZ4{J)P`1(>NIz z>=+mtSSJTMnR9OAWMHshU}#{O9w^IbF`3iZp3!u&r?Wk0Jr|@)$~gI=wK?OB$tRud z85JjUy4Z83ax*YkfwWAXSZB_-V{)ep$TcTjKo)Si+H*GWFfh1)-88Yzobw0|!~%xN zf==d~e|Q)eoWOboUCbFLOy+d6=X}Ns5n}|I$Em>w(akh@qMbQs4j%)98(96sXBLw= z-R+s!_$Pb0+c8>B?sT_jteAY#-JWsZWKIuz&L8{`XE9BlxZPrMr-wc33;}Q)*;_OI zo6PBH&zUU9z~I2Z(7-%d(7~K@u^<D37sO}}bH=xmPkP!j22SSmvgh0?#J~^;mI-t> z=VTLx1ToX(i|*!}5yFtrW1M`^(VTO=Fav`#149G<WI<<h#?r~2-u8^gCU<(<GxAS9 z>21$xC(6L!2M>xKQHYHYk6sgHV9;Y=XkeHe=xol!A~yMyj~%DI7{n7C;IOC^gM=Lu z$ia*oCwKbVGrpR9($}6bd@`q>J?9*8SjY)FnzQ~FXJ9ayeAdpI(^vu~e$mmKsZ?UJ z*I9cG35dyzlP7|`+v#u5sV)f<6LdFcY@5s(V9yE4&k<lJU$isljF4hr@B#BC)|s;| zkz!yln9S>7&3I)pXP`Z!%4E+#d&UcsI|J<*)h3?|v}ethVPLSB-0NY@xlx9J!3-RT zf-dHqpJf;r48cJ^(bt?YW%9`&d&X6hIfLyvU&}Et1b~wxD79G2LjsIxGAMm?PCglI z&$xXuXNWy#qyhtj4a7VrbH=HYJ45Ulk4`=r0&)dss6AuVWY180&I5{&5M!P!=xNR< zKlx;+J!iNQk{IU<C5WGyz{&rT5+t=TPoB8af<qbR<cS{UoMFlk3&HWuI!PIv^S|1F z6oHZr)8vW%=A4EqkmSG$N)D{~Dxequ`F^bmL^C@$(R^2d*un~mM@|=2hzr<3am-q$ z3JNh_TWik!stgRqpuwNXpk((+6_)=dhFfr`!8jKk%^AZcb4J;7wy8mkVVoRjYtDH< z4dQl&$$^39oZp~w44`6x(@Gtpn`v@js5xhjIz%5cD9v(SP=`2_WwM~VITMe@<Wtdh zj1H4IW9%6xP4<idg>h$$J>&1mCu8hceKZ*u947bLS#!?Tgyc&`u#pcn85ryt7#f%+ z3of*nd@|OaF=H}koIT_G$)0ictc=>=qAt{$(^DIwixnKZrzUg8+p|8^WnhS&%o}gb z>Y&HK5D8|@)PsqA(PLl;28+4tGcd%0SxfX87&5^uUIPY(L@+DQ0496dfPo<$EM{cL zz>qrGH^GL*kbxl{Ec6Y|3N?ah*klBg6*Pu9Aj_D6AsnQG^Pn*UgEb@r#G14IF$R_O zzV_CvttJc%X_G;$*Cq@M5g-<)vneFAFo7bLv)`0~!5x<5IrGdI7);^3#byvwnJ0s? z!>h@jsrIZk<_rvapulA;oqRIYo^zQw1A_qrLj&7n!9a7?Yv!Qz2eMDf0-Rv%tyzUF z85mMPHnZ-rWMGH`v!tv*Rfey<HDki$&UAa$k5&u}A(MGstXci6LHf=*S~Ipy_RO$n zJUO{D!=6!k^2rQ)&LkU1nqUPd*Eu$jw8RYN-M3+2Faf(G(8-)t*p`7I0c_JpTLy+a zFe~1Ufgxo&FF&IViyZ?)6j)5w9+Xr-?wxASzz_o#`)CghDOOJhm~5v5%wKmMK&7>> zy)~zXBg8c<;BZWGgs0wAbI!Gnu&i{^!-B&Rma{=+ho%#xBw?I9G1i>1a&l*`J>!wd zCv)vN1)L#?9Gq2HeVm~dG47k(nP<<c;=;h-H5n8zd6PNw?K#i7KvF5=<cYcFoHDL( z>z&Ox{ahh7a)a||8&r;EvS7YB=MGoM;4RbSiH|H8T_<~G+jF=<jDi#vO>Ri(gY}#n z1A`qXT$p&=CwCRvv3k0LBgopCv(X(=euGOv&cp7I;NS!W2kT#u9JqwF_kg&C0bBr- zd%z>j)0}fHRE~A>#b9&Rry#k>zM<Bj=q|SB4D^Ki$;q6v*%K1M?2`pU%~`j5f?UDt zV$Jy;uIi$%Ij5o*L=~jj5b6c78<Ny}y&#F3Z!)OP`0NF7Jp(A0bDDZX>|&jMQJB$! z!yDokR*+vf7kWct3=%vap(>fcHI(vX&T@Okpvj))_MBZl3=AHSOju{mdC3Q2o519W zA?BRyz7X@lam#6m;DwrV*7!oIST=A>ZuNzf)!<NN{5+Yn(w<Y>4-#sSq?YIh^A)Ia zp9$rG-O75~4_vm#Sab6GLqdXSa^M?_$(>d9oW=eSH*kQ<_fP(iI*b|YM~47NXn;-O zYzlxhL0G}H$Dsg-eGuD!LFFJ}Y841^EekjlE1*1fP}s2E4`g640@w6{K@gk4Zs7=m zr?xtC&S^mqiy_Xq5d^UclBWfNAsK>W`b0TK3yxq&q<~d2woUG=v*+9s3{eku8snGA zob{k8-m~7GvmgW#s7#<Lk8@rK#Ip>O1*6P4TS6ga7VG4Tq2`QtCwn&7Gg?jVY_MmY z7zS?B##(cp4TD4`!(_oqb4Jn0o{jdL+2Ifuuz<xjOg`CY&$=;^fx&O`*+y&D|B;|} zG>GLL1!GNzvmV1)`qAKw+-S{O84ap(KspY>S)4I2u|PO$CY<#U&eDv9sVjuDcE*BA zRgiiA;VjoUm{>QQbukW9nt{}b#=}^VaMoNn>miKAshR+Z3FgUyuI7x1lQ}!=IoT2+ zElzL)fw63IXNNs2OA@G->g}**O-=%t+*@bOxjYF;9V=5ZsBQukW8RZbcG`2UN`{!s z08W(8k|E_LBRGp{rNDWi=A59xYEaXPZL*+)1xE@*8>FrBAqA3NS-^%Eq%tsAf|hfE z+vcEweo%9oY4XIm796RN^uh*Cu5VKz@yP*B=IUvXM9KnAF_CEyyV=2p%uR#n1E(|2 zt7))A4{BTqr$bUO(`3Py7A)zY1jHL?%{eh0?j~n*##@s;`|LTDG9VT*g4=yDlTY^9 zGj>nr?6>FKn*m9Z;Ka@OCxd|@65QGZwXxDNAuTRJP#=f$VkQHFBLhQ&D7e}a%7W-) z1w{;}Qx?olP!noN76U^Vq%yBF=lqogaWtgOZjlXX<U^W`P1&GC(i>~dc_JGU2#_*@ zIS1liNEF*n_MBwTS(yW|kz;aTsyXMO99Ss>>IZ#;s%HY1WCppAECeYjDsmYZbit(~ z$WNPdA^IR4l;^pSz=qUi+If)Dj$tyWzmT5?N-&_3eq|n{;9#D9QJT?$BM;&q#>s)p zEhc+TwdZWhhv);_&bVjt$*K0NoCTm{cy_8at8W3wk093M0&v!uYR!5ZE-POM6H6}y zXWpsSteXpAI(`<yOtCG3scS8Qsk;allPm@o22-tBK`R)1CWCC-Tnsm*7^c^;1ZG}q z2~6y43CujnQkahTQgBf*)tYr>DNNnRQkXj1GMHFv8Pq(^lVy-FV4plO#+*~GoPi;P zfuRAy<F8_10QH&J!MUWa3X(e5CQmG}V5tHbz&q83qZ$$~kaU<*4M|TB9fztRF%M~y zbJjqz1jF=+vWylSHSqlCV$M0C29j>Tsf+UzR3)TC$y5u`#|+MbVYM)Qpw7&sT1Yy8 z)U?+SygGAEsXB;0NY)LigV?}6eIf^=1qW0P+*<;*rWV+9{;h+!mKD^_;?%8&=!T?? z)XAL-?K$VwL+W*w$rF!SaMUv}L_vb8&YaVu0Tyr<yDT^wASn$TCanKJyve-w)|@tt z5Z6KqjD|*-7ErhSN+YCDU<LQsniv=o;AWRKA(e-mCz@dPg0v|$GcbTw-heY4XJ0cc z!axnjXUz-@phX%GIj<H5hB&yHD_R&BGT=OcR+yO}eOawAQ$Wq0L#;5|LH3EX!Q?<H zbJ`%0&oudBt~uv|HU<XJ+ER#pf7&25C_A`h_G*WDHt?4PM>`}AAyQA;k+nH=z^nsV zFsTDs?p+7Wa*$KpI$=hFoH?r#Qg%R6-lI-Pna2fgt0;HDR8F)rXD#mnl@DhftvNS# zLCP+0i;nU0<jz(0oH5;yGJ|3AMK24EZb(G3Ob&D~=X}u303I{|m+7p@Jq!%KlX(NI zSxtIDbr^^>xtD<<4Ak~zd^y>3jXkSNAGp&NV9mL@50ac9N&0agBr!6BJL|Ij5FQ(- zR$&eAXJ7~dnZdfUAJ!Kuo4~+O1{Uj?$iUDBW(iGVV5kDKdM3eoEWakf`b!a$VLg^j zlc7BuPN6A~<OfOMVN)Q!VFmS&ITuZV6z`Cr5SZM#!Je~vDkMn3$(ZrdWX_HDoD9<- z!2>Cx-KIg}pK)?vxjAP$lm{_!_cVyFz`8lVPJ@gn@qr`6Vmd@0B&C#2hp6NLXYifV zVTl8j0RBPcz(Ylx7Be9F7{P;XIWr*sVFXuf8)iTXGH~p0KAQoFImXEotIRpYW<mT4 z;T6q-sAK|HNSkIs>;reNSl`V8H9<i`9SXA{z6UoESTkmWda-BStvRR7h9nwrJ<ob# zHn`K}WX;Jn2VxGWwPDWbHV0mq*qL*d&4Gj(*nY-6lRdZFbMnq*0I!W<o-9~r!7&$- z0m0)foC@<`iAB)MoHJq`149xxs|LoIv+kM)i)@Ygux|3|`Oqk4;$AS>Yo{G&=>mxD zOyEL&?*fQ%knzE<3m{<#jzLDv$)3CHInx$GhOxLHF|ZJ#0#e|<T?om?kd$k^2ofrg zSZ!Ve@fRz&`hK<u63UP+fze_}46sbU2rBLuLsUXy{ODpxCTEx|7-%v1<R0({<z9Qv z-Af=Nl#m$ZSqd3xfbfEsLJCNx$%0<yj0+}n?z88-w-jOy#BFxVAn5^;0-BaV;)4O~ zwtdSWaSq9GUzS14VgRKaMu*9r`|TO4C!gGJ&$(_n1A{9#urG$1b4ssZVDJX>1oO>V z(^i0n3C~7bb52_U85rW59JtbgV+ADnf@=y+nUxTunL)J(W8CD<gZ7+LS3;r#5&=h7 zLcGNe>P&D-uYv>&18BsFwS5(+HF(y}n(^@DlZWhCl~yw_m`*->$eJ~LH3Ne!m^B5? zy0{vYSa}_-nV8p1K6S{B$qGy{7EbOwV$a#W7UE^r$rq!|Ikne8>Mn3Ek+XUoq@D&x zBkOJu4>Ux>`FkBC3L#PNz8>N>7I2fccReIoKukEe9+D8i?J-u)4Gav9U=zGHK!$+0 zCSP<i=bW+u;s)?&JLmrmkS-PjxWR0-5t0EQ{rsGbkmzCr6^X1XHiEJhZ-6!DE2uam zQq?v=%mXK0&iqY~q{%S(Vw?rXCWwQWK;C8L+YBn?L5)C<&5(2m7U%r21(KN{yr`{^ zdKSXlwG~oBLU<C}ka=a>AQcfr?$S0$c7^bCwnM5V2(M*3q?rWa-9q6R?0{565V;l< z-i;lQv<#8c+6hU^?BE>Pv=ib7@E|wqft?_~oej2T;@LI%)LA>$@ZI1(e3dn0_hip= z_M8uPBPr*U+XG3TkS<ch9!O!p2u^(y_CPW|!{os2=A4iBKvD(cWWmW69D5;#K-`nK z7p~3SoO32z4m5oJaW81pi`T)L({LX|6}Yr!&D;lSBZ7ui*TTg?jm)R}AlU&NiL9dg z85qpKNymFXJV7{{GuBS_ykyV0em{Khsm`49_I`*?aCeB6`v53E^6s<dv_1e+6=-YD zntlM>2)484+;{-uAvSP6|2UcRian>tK}g7Qg6oi;gAiY`fCifwPfb2~#h#V#5Gbql zdf9Lsf>_4_E=H>lLDE0N<cl%poa+xkLKRY=y*vc*I5=f9Do*yiX3rXN7}U1+y=Kk2 z>@cVW4q|<Rv+Rz*#Jb?DYezs12dPsy3Tml?SQ&8E1~}^noaJx~rmh3dx&UWM9EZs! z90&CfK;|ujv);g2Mkiph6(>MZ22!^N&SE$T6LW#HI$$i$GbbTF=a_u4#)9$G<gPn* zoc5<+`CKs2oO8-4NVq|&_Y<cekqj9r`gIDT8`5g4J`E`Y*d|{Lu;4fiD|`Z-%~`e2 zfE>~5Z_QbC1`=c7I)`z`<dgU8IX|3%Siw9QG^ubF!eIlADRCyAg_IcJo+9h?v!JZg z>uAk+@hqgc0GEKATIV3mAIRuH$vKD|+vJH)Em+QhQg?5iHLK`(P&NY<N}lH-X^0in zwq=|?x$~ht)7kTrxg6{`IWIt*%`{nXqd8~(1&BgO6}I^T%;}(UxQ`d0CGzw@Wkw5* zi*R?=nRAw3gd|*WhUYwf5t2)}KqG^!Mwb{E>?iY<TXS|_f`uN)yu+6ug$txI6u%5f zpPZ8e4_a_shC9l^oO3!<ih1%yC$JP~=8|FZ#Sn8&gDVhS93YQzUWM~Ob6xybA+ZA~ zlDwfjNOPzCD#X2z_RH0)5MMKZ>kY|k5MOgn77Q@w42SZ-W0$N`uYpo%Z>}}x-D?oj znZXl1O4k_}%)v7+pmM3|I>ZD>gKfukh+W_?W&APu<O_QywHx5TPr3ndJ|lPzXwD6o zLeNao9jF}ZWWjoKPO+OXInZQp*ksRF_MDS$LM&yNEEsIgC^7luD|^<iTMP`IlX*L= zIp5tvP9jdXA<kt32UOi{m;*tb(mhZ)rpXsQ%{iIwKvY6nMFDr<6|93f=bSr`0)_#c zRL|UjL?@*3Ww{GU#>`+FEbc;7vV)rm&38e;1}bq+--Xx=j&xSed!Rw?v%c1xj`twC zA%%YFJ&0~dyLl;84xHFodG3SyETEb)={_XcgUe;k&G#W`h8Z+`&iV5`EM!5ga^nY( z(1WNfegMhR5SKoA0BHcROrI#kXu<Ii!h;NBXFP<s7F<7YE_(<G8Afn{`u!oq#Sk;i z9zk5pIyvxz1;-<Z6gb8?XFY;Aj0N1VQ+f<ZYb=um_nC91J%%_864=WgLo9#{4nKMf z310A;0#2<b5YK`Gj<IMm=NHh7tmhYdPVJ`<t0C&5pF(me+vJIdEI6LR-S1+~`Q<4C zLpXSrJTMeIb^FzxlleIVLmGI{3KUM6&mj(A1og2PmrnNlX3zQRIZ{Zns=NRd`JfC? z`vT%EW>7DX^Y9CZO^lNRubFc)zJ$m@hBDk=!cyYISaZ&aFBus885kNQ!2^0cuOI;c zF77yeUO~LVF?nLJ1<NZ?*#}BA+g?HZ4xX>%{PzkHeJqm&Cs}a3hV;{zK*7m4W%9|N z_MCEW7#KW3Gy0IJjyI4-7sq75Wfm-NK+|x(<<^{>Zz1IuB;>u{LP{)V(0meO&1BEt z_M98vLcGKT8q4H-{}vK7kanH+J4oDs=eIeN-@!8CL`QSZS??hFSV5VZ(PQ$-KlYrH z-$O<?87B*dm~&o!4+~Pk5OY@E4-5=}lh6LKW{vv*%DiX)STio4%=yor_2~z22>i3= zl>Z2^ff-!0Cw+vB|1wXWxZHx{BP0Y_LB$ml^QXyP|Lr*4KS5fx;1tL@`4gyt;9GCa z`REg*BLE(G<W&3&$=u*>9%t+qh`YgZjI*bnWVB~3{l>sxKlLo5HRFZpo{Wt4oZr4f zoDOMa8T^1GW(H6jma$|yCljMR=cOMI2SE~s!A}@Z@RG&!lOP3me!|+OpkmtM7bL-g z&0y{L1+Lm{tvS#Af@C5VklCC}zaaq*8341I?#aSv&)M)B;v4D7pm5*+8{!y_$ro!a zIR3!gDHv+bY5NC~t69Klwf+yRO$}Ok^Y9PEfsi>@lfUq2_BZD&_zN)wqHh&c4$>5O z_7{@I87EKNV9u)Z57a#Bjj?8|nC{8WXwT?2y_22Mp0({i1B1)-UUo)n&MW^RDUJmc zQLJ1Hj0|pI3D#H!Mg|*Di;{IF10zEMMDQmABSQp)8OX@UU^m^Doza?g4I?8%2t-ta ziIE`-!kom!$lwK0kj%`;5CCCrW@cpYfG~d}n9eMW3_%dlsVs~PaS-Nb7Dfj5$-Exc zjPBD<ax>bqwy-iXSb`#+buTL;gDr@~_-lG652HP+F&iU8GDv`R8XF^n<#b;jMjIA3 zMuu3hSPVNOgDaS|ke!ji8qB)G&dA^lX329fGFVLpHBKTq7#WJeVox|2p#w;9oQw=b zlh0<`uyDe(a&y5f%j05XNC#`U%Eidw4ra-4!&u4Oj0~Azu`}F^41r*lEDy{nNj!`U z!C<kiJd6z9U={-}BZDW1#TY)FQ;5-?b2Bd^c!>eHKxci&%gEq5*>}GU2OlGN0S%;} zsOMt@ui63^1FU;NJdk%dfAcYd*Ka{o8S_K*Kx)Pkeuy6MSQY0cen#*(3hU&Hmn}H> z8Nmyaz;<#P2{3|JWkGtZB?1sbAZ?UY0uT$Bz@ym$j0~Y5x3iiHGD0#aYl|QwgE>fy z@yK*fF-CjV|ANp!<g^lE1h3g)23K5VP#!xd;c{*gf|$z&Zu`6vVg#=#;{vy?OoSos zf$++Nk>xH4GlG|GF-#8>V>IWK5rOy-qBKebA_?ZPJ`{nbB}S>~o|26AjB(RDLDbCY zCqdM$>6}uG_N=mEjG#4r&eoiXVld}|+B$QmpOj*>=e#V&2wuj)I(gzkb51F7h^xUN z#Tq2e$lyPj*U6f5zc?d!1q>h9H~+*TAqei}aGFR!^gx;zITDQExon2X7q6IeDo8Sd z=Mk8|`bs1j!E2!yCSSa7!6C^AUaiIeE<0GHAZ}v>4HvLFNHH?FfpRWqn-s+VU<Yv? zk%C97hdGmm^mH#dMmx@UX-LdNS`!nc8Np*U;AwWwJJO8M)g2cPnR5!rFf#Z;YUNyW z)(RO$hPcU~I`^6k#0wnYL5BueMurHm?SEw%8G^wRVW5HLW;sUi^dRTtiFeF7&&e@@ zmjOa}+VT*0LU@_-jNoO95Z-QiMsU5!4lYiO6d1vy$B?B(6BQsn0=2=-S?_~*-~iWE zgt(h?^2Jzl&MZYp5&>6zoG+m~NSFjDK_UY@KFQez<w1PEM~M--yb!cdPC$7&mkOgD zYk)GST=aFf=Il{s1h3kGtfM-o46y~`Y7P}hn1FL6WBPPYRYrTp!_zxe8SObmRAF{r z^tIqnWdv{PgEVt{R3QNY?wWI6gDQj!xACaK<O0`PaHv7jG9zfRj&aI#PjyD?dgy{& z1{MYe22}<I1~vu;25klgFkhd6fq{_$+>imUjyGUnU|?bZw^_h^BL)TrW(M%u39z_1 zRNj(-fq|6)TnB^I*?~!{{Cd!uXi#<l8{`F5h)jbV;0+ZA(I5-`pnPN+q|P7e-~gyR zhz2=02r3>76$jBE@lepBc#we+Pzhw3dHPxnM)7)(xv@}bWSX4;JjVm}IC!Ta1GxPO zRte&Rj0Nq5011#ngWLr=cK}4^f;Iwy82KPm7#J9kX^_JTpdKrP%44HJ4gu}z1I2I! zG={36>Iu`}eS-`P$O=IgS3{FXJ=7o&4T|y>sDoOe;`nHg`YuqCn=Y%xC~gTdb}}?Y zO@pSO*--b+g&GH<LF(o~t(nijz+f}IR*O;G6Qtq}RQN8413C@?vecd7HPo25P;n3q z3XYFZJ~GWQ{jL_H{PZtcj0%hl(|NTS<-th+oDo3E86kN9bkGcli;V^u&Bh4H8=N5L zf)>9+^??qq0qFzLpa2kniVH#2foM>Si!eg+o+u*&C~O%RM4<}Bp%M~M4ahV|qZCw~ z3?l;rD2*yZ)vGW<GPMRHc*6vP6;wZA8e%^Q8bJPIAW1zajoLyTgh7MCUx|T%As%ul z5koN}c+UU>NF3zDHmF8?G(Q6a!&F8{u`~;+9+?J3**s{JEriO$=z16fnFgs@1R@w1 z7?5dD`MClb<SU`{Drl6fVFYjaVAuu~-wqYu3AK0+l)n!eRfizv*E4_^pddO5)p!gd z!GKJIgpNbyPk=a}(~qDAoq-yB4k`|!LFR#ue*#4oHX5Y#5{O{XXJ7y^K#A)L)Szo% z2?hob4HCZr<%4M6>9Kmya`QP<m>3!q1Fxa#iJ?IO{Sm4j3k^xM$P&B^3=IFEAq_eQ z3*>QZGzTcRGC^uWekMpR6oAs8?HV9`AR6RvVGzN<z<^0}Lky5)VqoB$-mA|jt_gCh zGE_Y_8WbUFAbX}?)n}CF1X-g2Qa=5uKC}$d0&y7_7(g_Lslx=`^~d1M1m2d$;Ku~X z;z3N1GAab5h=G9tM1z=NOpr1u62xI(U;xqL3=9kfP(B_S5}bGxfSgN=L1d}})riEo z6kJdjLPMY!>N8{-6wYO!aAsg&D2J-6gsKD6({l}>^+^>}Sv54^>Y&O%G>F*%A{aoU zrH}w`f~s$Zii2pz>1Pe0*`W<845C40e>ap5qCxx#P(FwT@uxCDitss5abz0gi}_G- zd^AYiA|?hSaQkX0R0D_xNvwdncO_IDndX{4*9hwFEl_D>8kAjkKtpdAR31c2FfcG& zg7T?AL(&};3<9S+Qp^E`&sC;+@cv4MFHoO;gVH~sK18NL8h%4#j0wa6H9D9fRSr8d zq#WUZii2nnlN&0|1L80+Fo0+flOIHYHrLj}7|f6qCJ5z&Xi$M71Qi#7iX+n?H;OSs zvb-cSq-c<ZszathLJClaC_>FshSK$_Py;le0$Na72TJQfX#*&21U1MQs?Q8+u@#iI z1K9@Z8$i`NKtsqCs@?-idqd2rXYheA7<{3$A5>!iRADgGfCwl*8mcY^Y7sIGYAqx~ z#gS=HX3JoPv?@xNAtiSeSY15>1Bd|%>T0k60|P!96y&u~2Q@K6YWp6jgZrTL1gHZi zLg`7+keLRRp8=(3fjk82kj#Zz459@Y7#P+;6>NZtBhw(E%^-q-fdQEYd0-1v-!_oN z(`(J3xf^uGBPe$u(`pP14ELe#e+kw08fq*u4Knr(R2)QuYOSwOJ~kRuYW#$n_nVoa z9$Z-efm*}{k_Gh#SRiSg14?tTK+-NBlrO*n30Nr>NZOW#>cd8Zq!d{onNJByD}w|X z7#NgU>LC`XLIprH$VX~WJ~kTUIZdcMhz6<Gf;vnGDh{GSDM1g)$4S>?Q2<J#rcjrf zLFJKYkcH+@c?+mKG7V}M*+J#)q4FRal*V14A?X2?ulIzy+#9M8M1x%J3l;ZgfwVBv zSipOQ8S<g(Ks3l91yDXYv=FFs+XOWLM1z9170O4ZLE;@y7k5JCK{QCb2g(Q00t^fc zbD(_U=z3B$;8*Vq$~7#I;^Qeas9!=IgpKA^U|?YQ22}u}K|%T*$_LS`(_^g|)u-oJ zF=}Xnvglu^95M~k^A9QxqS>aewPF;Xe#VMX09<*pf+8N&oo0pP0yZcgM1vZCvQRz^ zXt4bZG%y$x7GQHho|l7q07Qe5gd&u$$O^Ha0VDv*RT`|2@<N*xQYjliL&OlO0UHg< z48~A-WEy0#2~-?JgP4}AkmAG|#9?4yu&!r?wBMYd0w5Zs(HSc41$BToR30A<%GQBU z3xc8Qk!g^*AyD%|q3Y_xp$b7X$beXA2qZuiCPL*wG$`m&pnPmJC?wLL`ZHM}C2}rQ zJ%|Q5AP>ri()A2b2ABpZ$cI{709A-g^Dr<l)IjBHSs~?38`LKqQ1MQvJ`fFZP&ZV* z7b=cSg9lFfpc?yGA=z>&R3S1AGH5zf97Ka0Is@v%IZ$yB4N^A`8UhQU;>a|p@>>NJ z2h-DC?VvrkHBey?4KijOl#h)DS-&1C528W*4N&K7fr^7@koZ=p_qIV()Ly9b4nWl% zU}c#8*p5*WG*rTH2r7t7gB)`NYWNALA)sTUL55#|=98;XeIOd7{yLNoqCx6zKqKK6 zR2-QG$=_yWm|krUb;Mn$B4iq5=zUi3`5p|PpoV>c`s^!IJ%|P+;oq!~W*R#iB(rg{ zL5ejlD9sI01UjCE4U$Cpq2dB;4AZ$C7&#L`E)s$&0@0uoDAb{fG}yq$tT5O?j;m(y zU;`h8!H@v8ED5R)M1z<aY>*Nq8>&ACWa;!?2S)Mfa~v2sz@c6UQpmu-fJ}q(S_xE7 zDO4UC4GNfYs62=UxxE6)$3}ys>Oceo14A7f!*pp!MnSM68lZyMXpkjMP>-}i)q!Zx zI7lzl<NY9yF)%PpW`h)+Gob1~G^p;G164N<N-u!QFJNP+2ak|1f?BW?>g#1}kRgkW zQ1LBLjoY9aK{UwVT~PJAp$^#32Fb@qq5P9j^&lD)I;WuOPeaW;#}*BVqKi<8OHhlh zKn=J7<==wJ--c?u#|A08pF%AF(V&oe4psjWBtE^?3EGH$1L86;Fo0-KIq((AN2WpU z`vw&U(IEbJs5SrCz~|pEaDyr;Q1WGmCSNF@pB<9S1)zKo4KhlM9dz6y0|SE?RD%>$ z0f+`!Ak7XwhK50loq>UGx~(&#IygbtvO}_uJybb18f3mJ)Lu6z?G9BBqCxV$P(CsZ z3MPN3I2O7dJjWEu4oOK-P=z2Glr3VRd=L#v0EtkGlh`3yvw|HGpVd%*bwT~z2ldbd zsD2O)a>yihNM~UVRNs7dXscj8RO4c(#4@Nw%c0_{p#~w-AP237iX+n?i#9?Xuo)^3 zqCw1EAcBE`0Z!LLE!+#Wa37T34^@axgBm;3oTaNLW15Zul&0OGlQYP(b0Eio_@JZ) znw<mjK{O~Tk!R;X;vhaFXbBVP({zwH2X%%)1|id<vvi=zxzSm=(OEiB&LC~p4Wxtc z^dCqS#9UCO#+aQ0<$MMP23t_IGCE5K3Zl_jI!KZM&EkRD2*{IgAQ>b+q%KAh0G)0) zI!gzhtO3o=fr1M}g9d7dn0$i-ClLxk=F(ucZgiFoGz1B14MJ&9ae!}j4ipa{d62r% zSvqLIjn2{`&(4982#60#BBQf(qqB6NbilyC0Gh2Eouvb1j?r1V(OEj;ru!hXccZg( z3=H7OGf?J{WrZ#;9i62E&CY>>1Vn>6wWG6i$g^{xkOA>WXXzLiK(ltB6at!^1BDBS z2JuH{=|*Sipwmd$X6Haj1tbm{6B(VQ17(=eSvu(4&*&`OV4J1WAa<6ny)ub$du0;S z5o3qz`xdNYPzX*nzg%_r_U}7Z$qAPn`}1V(OnUg$$N5`U-17@8N=qjhefe9t>v);Z z5+>;gJK>1yf2Rg`TU%^&_|P!Db{dn!blYi6-i(dYJEt*)Pq&!P#5?^hNT7MT<#eX- z=`TP6bEh+TGqz5D2@;qwgNb*#?+hky#`ftmXE23N_n67VJN++6pmVzCOs4SZKR^O& zXEJ#+c2EBa5?C>diFbPJEGBQp-svl6F@;Z$n9amHop&~qH)H?w$k|Nc(>dla@lM|h z5|}uha}HDZ^c^69+&N6%jFYGD1PNr!W#XMKJD16uaq9HUxlG~HCFU{lPCpA0m_A){ z9#i=A6Ci=wc}(7nGpC;f2~^By;+?KLpUInX_Vmj6OySct7BKNnzY7wWJ6&@DQ~2~7 zAc5WmOx}$1r{4q#bSz}zoo>63$(wQE^v;E#@K^*250Jp(>6VK?;Q<nuyNJn~aq0Az zAb}Z+LE*8O$(wQc^qGr6;jsi19w330(><4f!UH6*b_tU=<Lc=@K>{n5g2H1dlQ-kq z=_{9l!ebdIJeDzeGp?T=xr`~Cal`hF%b4mJ87EIST)`C1x|xlEfp2@@1*T}G=>^-F zK1@Df%_8^$dQtc^VaP=^ERzLY^|x=h&2)ru`h&Gh9*m2(Yp!F`XJXx^3fdA<xRt3I zq;LA24NM%Y2B3?iw-;_@(q{w<%4}ldVBM|Fz`zf(<}pN2U<(rm>pjqolG6{~Ws>I1 z$}9nIEX<njxP_@%5_WxZa!#gRRxxCH|2F6<<>`rsn3}=H9@xRe!FXwV?pCJzjEutD zeYZ1JGeY>rU@NBWg4+OhU(YTk4yKEK)A!wFlH<&)EXV~_WA~=--Nm$;^JpMA+cuov zUbvfynNhMb6uhbfye$HD>F;IGRk+g&w=&s-op50flL6z>?TmYw{xkBPOMu>$lfb|r zhwv$9kQsRSSA*#EzXzDyIbqk$zTNJ7kcpp>ap&~dLrjkumu`1F%oNVVs#eXwzy-2F zeENqEOe{=0s<-=HV2Wef{@^6j46wg=VfS!8?qXmN0EP2qM$R`=Aot+>nm+e5Q!;PW zH1G-xu-kV|=RL!8oQZwb^lN9B-toe`$vBsRfoFT*K_+fS#%0^@o?}X9<b++lXtv$= z0@GwBM&0cXFEOoW<b_>cmba6EK?LHs2Wy#Fw(q#Y^o5ZZb^)K+a*)#(o@NT4Zg7x^ zgB8Mu2Ufy$CJu-<y_vQbY-eHt`)2x{TTC2G9OtL!ZDra83RF(mbzj@J_ugjGXJYJ_ zzV|MZJa67D@LH*cs#^>U0@DxfVp_g^!aXJ(M#fXq_ugj;XVrehz`zZ1n>HwgvP}1Q z!1RQ%YrF14rq#@>hd?(zf#M{ZY59iROb}x7278g|KChWLSjz+%VR-<Q$ajDfIm`B# z_e>(&rY}fhH00W_3^G(Dv37dZQfAxwfBzu>lzyy1OVAk@7)qdP9$<XX2r%dd8ju<r zs2Y$d&!MZpY@uSHg&500il93QK#d8IlEY9jd*~W-P*V$ZK`{ept+69iGssRys6r>G z7-+E*XkY*&><kqHt$A1tQp~`>-~tunVqjosgNlK+EPyQLW?%qs!2&tnjTy3F8q`hl z1qm=PFvNoO)`OE5!*`H(7#JAhz=Gfu$iM_$a}*C118r6mh3@4_fbI?eEp7%)v4R|! z0#ygv3@{HA6buXusZcQ?(3Ry-u{3BX2s1D+EP$;w2aTYDTrI-Dz_1*uFcY-Z0CEi! z!&Vl^!kiqaPsA7)7<NM)-3+w^G#zyVD%JuO18w|?1{uu2z|aacPm+Ow0k){Mz5}XI z3bYjy8ibutF=++{hCpa=bwR~s7#JAdLoMlsiperCFnofFf%a8^?2`lCDG1fu3soo2 zz`!sCB+0<Q0Nr;{&j4C&eVP@r`xUkc1GKOP)U5@D25dtHXck))l$sbA7(kmdK;|fe zHlIO5YckXl6$S=|VyM^@s2FGqJ!tzDD4M21gC8_Z`xLa-03<ja8Z_z*3=E)s0w6Ka zP7jbJ8lWhEuDG8KH4wD!n-OZs9H^KU0|SFD)W@JrAt1e=J^Ol0kmZW=pz3rO7#Pf; z>gI!X5`h%zGB7ZJ76^kZUI2BW9s>izT2NjAZDxgP25tTaErJ87TMQKg9RR=!HE;=3 z%n-E48Y;FFDh4_jU@yor1_lODDFBkL2VL1cjS;e+Y6VoG2`GqJ85ls(uo5a}3ffQy z4gOV7F*61Rh9;=kYN(hwDDOkX)<DH9K#7k9d_x?=T4>GzoklQ~2|CQR5vtINfq~&I z3;6P1hD}g0YtRNPXi$Up&VW2%!@$5$1Wj<D{WBmjTTsEp1U~nWVJlQG=!gT*Dr->a zg7?=jfDiOxh-3vHrOvROxgN5B&w+t~AsXuH9niD@DvW}m!4Jx6AWJ|Orh(QRf}&v$ z)F+?<3bZ#E6ubwZdR-V87-m7uI}CM<D=5{oLe6D40u^%u%?*Qwwm`vl6dLdD3=9lE zL6O72z;GO@&;wLBv4T$$VmJX618uI4hl-tqih)*rB|{y33MvL#`2|`533B{tsF)7} z19<;(J;?QEpn|>(3=BsY!3SP3oP~;kmWNGZ1s?*-a1JU4S}6wFQwK_f=b>VtLmfaH zpFsv+fQkh&Fff3&#DUabgo=595O!vs+9F)&PDyqj5ey3ZQs7A6IT>6g|pht-#} zGcd%nGcbVm#fCF6FhnphFn|^;27>NDV`pFhEsAtxXJBw<XJBw)XJ7!WQGUS6!0?Eb zf#ESL1H)5R28L&>3=E*!=>;nT!%J2MhS#hN3~yK&7~ZlnFuY@BV0h2U!0>^UfgzLu zd^joS*fIvtMgt>O1}@NvB@7D~7#NmJ-?)}pJaRQ?a~A^x1L#`K4Gatn8yOfFwlXj< zY-eC#*a4dJ0WBkBU|`t8z`y{yf^$D8Xc-t7K(*dc1_p*>pe^4F44`8p8BQ@UFq~#! zU^v6Tz;JH5;yPyapqmT~44?xPK!+<#X8<i5V_*Os7y-IQ8&pYxPPYJE{uj>xKAV*R zblV~58dK2XGElh&DxN^a5h##BF@2G7`mA-#QeHdR85rI(Ffe>zU|{HBXJANSWMBZT zjs&HUXN-_zKR`(wlmI}<6;!9LWoKYm$Iie|!wx#+mw};?9aOJQ|F@1=uKouD0|Th; z1g$akU}s?PWM^RTVrO9RW@ljVVP{}i#l*m{mWhD@v^Et~oq|?z3$rmWh_Ep*h_W#- zh=W#bvoSD8vN147u`w`6voSEpurV;mu`w{nvoSCzvN13yu`w_xvoSEJfYh@yFi5a7 zFi5g9FmSUm_%raZF))A%3eXu2pmpe=jb_p;3=A?X;NxaN_dS3Ppl1NBTlvb!!0>~S zf#EMBWEXfZ69WTi;mbQl28Q>H3=AI_r@vay94B^>i2;0IK?5TLLn9*tLklAV!(GPd zaT}PG>X)!EFf3z%RL3h=7#P;GFfeRnVPM$8!oaYdg@IuQ3j@P076yjBEDQ|$SQr=% zu`n>4Vqsu7$HKsHk%fWb3JU|nRTc(@yDSV0AuJ3Gpj})(EDQ`zEDQ`!86k6ppmGJ2 z5%w}OFzjb$U^vLkzyK;6j)HdK9b;wy=XFrt2Ib|e%nS^m`u!#|1H&z528P?r3=DUf z85lqn3#iTjmHnWy9#o8jifB7V1_paZ1_lR41_nn^wq|5t@L*(Mh+<@50JRD3GcYhb zU|?W)$-uyHn}LA=bb3e)0|P@XXq`H!WG-c3U?>Ca$7Wz)0QG6IpogiXGk_1v2OXx* z0J^ppRLg;iSWtxpI>g{SBcy@h!^*(m%gVsu$I8Iq&&t3MzzSJ#yPKVXVGlb4188+H zsK{4iWMI%@WMI%{WMI%?WMI%`WMI&n{&yp@c0K6)5zwI=Jd6wse2feX{EQ3?Q`s39 zrn56J%w}g`_{+e+@SA~w;THn~c%wb2xdK`h4chkjjv3Na`N#}uo_uCzVEDq!z+lbJ zz@W{}z@W#@z+k}6z+lMEz+lAAz+lYIz+lSGz+lGCzyMlsex8lNj^P3u0|RK8H)s=r zCL05THX8$jDH{WW85;wG1sel{B^v{SH5&ti0BFfL8~ETkhG=Npr*rz#P0Y%kpe7G! zL7z1v1A`4C0|RJ>#z|HNhBK@T4BJ^57<Ph!g_VI}H!A}JXs~)CD+5CjD+5C@D+5Cr zD+5CXD+5CnD+5FI^uW!`()H@BkcpxiCI*IDCI$vpRt5&pPQY{)28K))28Jva28L`F z28J9K28LV~28KKq1_sbhz(N*C!>E#lfuV*4bj2P6Ln8|V18931BWQmIXqO5r0|Tg` zG>M6UVKNf~18Be8GZqGh=PV2iFIX5DyjU3O89@6QtyvftY*`o>3|SZ$j94IzCS4W= z25nI7&BDN-&ceX(mzja#A2S2Pe^5;g+9?Ry8Op-I@SB-|;Q=!P!!u^cZdlOH+4al} z44^&1pjJ7k5e{l}Co)4etzTwhU;u4$2W`;T1?~MdVPaq~WrDP#%$XP%ESMM=ESVS> z<QW+l6d4&9K*!s(GcYi8GB7YSg4!qy3=GW-3=E)ib}AVd7(ff6azLdpBc#z4#>&6| z+O-8*`wcqjMVOI+VL3Yk!wPl=hL!9L3=7y97#6ZKFwA9VVE6~Bu|X$5fDVgLVPaqa zZK`l*gS6Dvu`w`!T4zk`3=E(>1bf&R81}L;FbINnuCOsMa56D4aDk46U}9hZwb=MT zWhNs7!zM-shRuu&3|kl(7`8GpFn~@90kzaXN0=;TWMG)V$iOg@k%0lUr>FiVD+2>) z6VOFg28K(l3=CIT85j<-GBAL48SP_bVA#*fzyR8bG=&v1CsN1CzyR9w*1!sBtu?bU zFto5TFtoBVFxas&Fn~7R>9R5~=&>>|=!4P{D+5D1D+5CYD+7ZjD+5D63j@Oh76yii zEDQ{jSQw^1-^#2gI-7-op^Jrqp^b%sp&hiTl9hpB>2%p`%;NR4m>3vdu`n>aV_{%; z&%(g)frWwLGYbR57ZwJFuPh7<pl!6Et+Sww!SbL@!z>I8+$;<XJS+?hb<7M5peAu1 zGXq0DGXp~bGXp~*Go-Nx+VT8~nSlY+-~%=AW-~G{%wc3;n9In(aE*z9;W`ro!wn{e z>6^DPr`CUBVqn<G1UUl&bbJKp9#_z*Mtuwn4E@j}n?PeGc?=8;5v&XhQLK;#U<@k* z18BpZ80b_RMh1o@><kS585kJUnHa$Pj=b0y7`)jS7<||m7y{TB7=qXs7(k80P&NjJ za5e^p2sQ?WDA4wrXf_6hST+WRI5q}`XP`2KnStRj8v_GqE8A9928PwF3=E*{Y%^IQ zEydZa3=EyD3=Hk83=E(xjajS=4B4y<3^}X}44|!yrmPGMpzXGEnHU)6F)=Xw1Z5-^ z$VOGr#$(X-X%!X*22jVZ9n`D^b>cvsHc)dG)b<7K#1CO+U<hSqU;y=pK}P|ATA85J zFhD0{fDY#<Vq#zb9bT2p%D@0R(FnAG2(&q=k&S_&jg5h!gN=cqlZ}C)i;aPyhmC=u zl8u3(nvH>>hK+%tmW_b{v|9?a`zo`Zje#MHje!Bw6b0?gdBMiOP{G8&u#lC3VKFNM z!xB~ohUKgb44@5s-K-1@J**52pqX7)Rt5$)Rt5%7Rt5&pzHez}1_l{s1_n@T^Dh$v z!++4x7|aX|Eldmypxsd|Yzzz_yFgpKa@iOd^4J&{@<Gu8+6V+X?tulg?H_b@04OoB zF)+LW?QmjdU;rKU@R|+M8vq^D0_yC8I`^P{_7N5a2GG%5pmsQ@_o2$jz%Y${dfHCr zDBFA{28IA828OpFGe9jFCI$v+CI$vsCI$utCI*HMMg|7Zj=WQ>3=E)N?NL?+22fA7 zoRxv0a{Aw$%+d8StPBiREDQ{yEDQ{wzM%mV1A{RW14Ak+1H&qI28LiJ1_o6o1_mW2 z1_mA`$N@>y7#SEYvobJ%TH>JHn|&+{44}=}%a|A#mNPLhfc7!JVS#j>Kqmpnu`n=z zh7?+v7#JFv7#K>J7#Khup-9le0?;llP$vd-Tn^|c9Z=_GKO+MJ=pZG~5iFqHnV>D3 zpni!In*SCuF);jLVPF6qqfpAszyMO8#LB<`+Pezc#~R1VzyRu#l(9i}U43F>VED|& z!0?3)(%(4D=mY6v%!T^Kot1&XgO!2d9}@!u%%Ea61_sa;El_^~v}_w>38)_dI!Fn0 zw8jBYlL^$~zCC^3Ze}IWcm{Y#05p8i4;mn0WMBY|O*Cx3xSRR8Og$)1EQL09R)Lz) zpw=EU#1o*w6VMn4EW5NbGcdF<Lk3GgVjwxtSj8m<1_sbL2B>}j_02%z9FUQ-|NlXD zf!H8%kQxvTk_Xwj3N++9ak}MAW@TGY!)!S-1H%*0$Pj3}g_(f?qz2TK2Q}P4!yTZ* z(m)M4(1-+RbZHSY0|RInWAgNwH<|V8VZyx(3=A`w85lsL86c}c7$g_Tz`!sK+K&Vs zSpgCQje3D-7{44e7{v@3_yP@HfUE_bBnMIl8uS1Sa?D_YoTCR)3*v(YG#-P7>p%ja z1}8`m#MWVEU|7h^zyNB1f(}CiISkbP0S!)o3R}=X1I#}lhn-_!U;rJBv4Dwz0aWRO z#tlG?RnRyCs3CBbiGg7aGXr>>0L1?QYUP4@X-h$40Mn1%Vpak*C#FBY#k|lEbTK;Y z7H=j{sDpZ>;HqAffuUi;Rh!P|P7gJi7~@R!4D^gl7-meLf16p-bRlSPgn^;qVxiI{ z$N2SuOpI~HdIow1kUkzi14Bc9HHZAgmcl}?RwIzizUgmoGfOg_oX&oSxl#Hu17wK( zrCdTZAHRYv6JwkS#Du%k7vEu?&G=%v{at2B#;?;O?=l-RF)>c>yUQ%W#LYN;#a(72 zMzQI)L9#m2zusjwW-OfEJ(I<lv3mM`5OrYs#Cyz=j2EXHK46xVzQf4CAjrVbuy&z~ zSz_&j8BC1EdM0|th71gEr{BNFEGZ2-D@y=$oA5fF!;=K3?LsIhoGvZOA~{{>KC=|m zG{(^BiT9Z$8Pld$gD8j<FgaAgozwr`XEuh(p}2`LY<m3zW=X~k)9t@Ai%;M1fLVrd z@AQd3m?arcO+U}a0&_c50kb&+R90(x;6xUw>6s4^DxpS!ZIfg~v1U5UBW5Ya-0AX< z5X#M`FXUtqXEtScH9Z$3d~$mGBW7Pl<>~eLERxgTJ!013T*3(+N^E#HUHLJyD`!3z z0|O{{Hcl^m%q+>cYkD_`Ix&6eV`gLN`P|@Lm<|5rTJudWuK&lx7-y(wpl89rux|Qi zkb)u}@KA7rNJX8r%7O=Tm>BCo3Je$+?4~<DVU}d{oE{CL!lys%W07P`nBM<{S<*C< z7h>%B&*n#JOv_xriNjFOkb$8BD)W)^U&r=~@8&{fj2IZ&r{8_TEGd1O7h>VZ532hY z8JnGDVvIA=18coGUGOQhB;%&(8#7qMraL}mmIVcRE{m9j5d%Y+00RRk#c%nw#QGlB zj6Y0_P+bh&0^oe!(0sIke@pyrE+$43JyTG6X1Fzd?Neq+>30H<0QwNmy<z8{eYcnx z>rC{_Kq}m(KLptrKK(aHovjc9g9rmd!}@!!L1{0J{spVE0I6FzUH=)gG2^G{$slUY z^ywgK>-5tg>d*B5&zOy+?}<UCJb1-^M1AOaPzw!cGX@5&>AugIB^iyUzkR_h$!IgZ z5ybPHJ{v?q1@BEi|D0J;`n5P@_DNReZ~eqo&rd?lFl1o(GM)JavoRw?9b@A3K#)-= znxO`p7E6M+vp0O$-Z5b&$5RWi8AhO(xgrVi-c^|ccY?PZSpt?Z)H7jVKsQM7C9|>g z3rX;pZo?wJ89PgRcRPTU8|WD^FhH#b`$Tqn%X4NyHbXsQxH!bL=^tJ)OEHE`e>;yw za=OYZW+}$>>GrRfB^e8+N4{d#mZ_G8<oa}Jh^xM*v#y#cb>@}`Bd5&t1+SPT7)7@4 ze8s$;nNelB<3DCeM&0SvAuN)NX4B`sW0qvJpDyUYBFX46{UV4LIQ{iIW=ZKNSxAu; z9xZLZi_@nBoc2sW5tuSv{ynp#X}&CEns9R0=Y-Wif?t6BWT|Ip!cYa3xhE@qan@Ul zqX?Oc({tZ5OG>xOLgKeh<>Ve~hOh^qLdehv<ZZ3#3*R$KGESVn8$|7$9?!!f$vAI% z;a_G+)77$&#O`@=^>@|KZhNq?#(L%q3_E2ZIq2rXRonL6{Iw384NO6?abo)WKg^QS zH)J6JbVr(F;rX!B5=@M726~1d&%B&o_<>oH@%QxZ56qI%d~%QoUzWfV+U%e+6KoJz zo#OQUADAUgz2qRCo~R$ytG3nFQiRb|4w9Eb<sfdz|4{BC))m4m0?CR73=H$8^L}JD zW@1yA{(zN5f>CJt!SBqH(y9uOf+z3MHIJ{Se+7VjV`!jf!eBnV|0A<8qx<ypF)WhP z?|fvIVhot>$ju@-UEmXQ6Gp^{fa(%(#Dq;>`-wSS`kw;CCCgLaPIS5XD-v8?fkT&f zy8dToU&bHPYd<qfGBGPnpYfU5h*5C*X^?3D^u#<CF*!p91|MZe)N{>!c&ml|u`x6h z3>g@%P51r6Y|OZLdgB*nNyeAcXMbUql(q&<g)=ZTXz6?W`4KJhiHR}JTn}753Qj){ zQU^9!WcuGP%$AJy(-(%bNKOy<%G?A=cOq;Cpom{K{q0v~N$G9skm6;(&g@&(p%Px; zPyxIB$8^PS%*KqzrYi=rh)vJ_#w^PSHFy6HW>&`f>5IQH`!X(@{_z{LB%{N0ZcrHa zXhK55THYhBYLb^X)HEXo25@EM3$1ck%ore%BgSmX0Er&PJJbK0u!v3n_?=l68v2Y6 zrfdFS*5>@61xZWLq}o4S8<a+&br!-&;+%7|!P6uS{nPLNU^bTiug$<9&A`yGTSQDK zwtr?53!{mip#`Wgk(#dilUY*QOb4PqaMrtb4ht^+LnsKHp7@hllCgMtHAvkgs5*-e z)&6_}?H3X1HcnsvlUdUAvJL}-G6O@ykGPq2CUZ{xM=1EF!@wZNz|io_QI+GXv&#{L zjL7uAKba+^O?1K2E)A0!Wg_d!zG@&8L`*mQ#VpBKHr@Ldv!rytE(3!s14Dysl|SRt znyU>6b!(>A|6-OjJponFQ8ZiqZigo?LV=kHB;h-Xtj?5LA65-cUEt*6G5svaisb1N zSy?0*uT5wC%`D0IX1ermW=ZLPrr?tU8ZwuK=-&~03`!W#7L>?z|KH5B86g>z5n5y@ zOqc(|EXk-n{k08?)b#&;ETYph{xHiiLLzPYf<MfDjF7Sck_x4!vl_7Qb2Bl<S%BJ0 zmJC+YZT~VGLyDe8Y1mSRLlqBppZ57%3QkC7pz<SnI`2Qc1&7LZ$A8S(j1X%ir%N!h zNKdzoV3C~u>pyb_W9!spmf1*hbEFl_AtlU~pK`Y*G|bxp&P_(3VorPdc}5mVXgMM> z{U0OC8Ll7;NPP`SzY@>{Eo;sYZviPR-5=$+Y8~9Z6Jm^so;gGAbVX(sNyeJ#ismem zjNQ}Mv$04r&Yqsn%pz&J#sU&IuV2iX6|8^Q2N5^>EFi@kL)yM0ZzmMq0n30}x|gT# z1)2A0`gLX&W5)97+$=1Tj1AKZRait>jr5EddZyd6ut=KDvxFqQ*Q-;P&bu^!8^S^B ztRS_4@ucLcgL4<uGBGZ+g7|9J^j;PgN$GP??skczcP?D`_XKRW0jQ?AJ^dgHi!rp- zC){8OF(`k=dH%W%pXmaOuG1A+Sri$Ir@!uEk!0+f9t%oXtEOk0u}CsPliBI%hU_eo zj0)2~n!^KE0vgD08X8*D-Pl-6U~<r~W;SO)2}8!%>9Qc>E2jSi1uWDuh%GR!Fq#n( z7jQ1PR1#-4XMjWpWA1c+4i-tqv(p(lSd69R9U(267c08>uU%s+0N2Rij005%@sact zM@S0t(?7IG^3-7wX!&o*z@RvNF37z3)3<Z57&C64{+a{iW#{Q^oGeB#M@aWMgBL$E z%og4LN~(2FHn^@d)-weS*cFPiNJ{g%Kolf+CUYxwhTa0353VG^?QKcM9n*JnvPd#6 zonFYrBFP9A6raw<#UcZ<0~(z8t>OZ?4O(YH!U<Y+PQSs$B88UUA(bVpq(<a&@#)>% zEV8g#$7ME)D4Q`T+k%@EQq#Y4vq&<^PZtE0;NXJX7*>FQjS!zcfrmwg@zC_OAO#RR zra$0ekz%|%{WlMbG2^rC`n)W%pv(=b)u1KH^aef_DQN0oF@aYt1`OctPC8@uc5{9f zW=6(U)2#(qUc%fK@ReC=dW0a06l3`GhoI)z(&@c|ERxde{UNa#P?xjk&c@Aa!1)GT zW$vARP>@BEao6<QAa%$5A&I{%+(@>!#_trkD+-R4OVjy<SR@(mPuCP;@nzgLy&Ob! zPCqKd(kMOK0#ccIZT<h?Ud)3~u<3?IdWObtrY8!s_%g1UzFwF`64V%(%OW=YzA%d{ z<FV;~K|(*K^UJe{$r&&(Foi<Onp2E|xBOSX_ysN<!Bz`Q_ZDH1lvWLe6do@agm!Vi zQ-2P&1)OrNrq_$GNHWGupDDuPE1d>fWyZkJpit(up-9B*fC#9WW(ley3#K!QvVhvV z(xNOcg)v)UTc(SPu_!VgpKd9}(#R+@eYY5kG2@!)@5NXor8UAJh1xWM21n!Ab*@Z| zbq0E-dPWA2UKywXVgTw<*@6-`fz+>E?-ma6Y)CjHHyZoBSR0|HV~5C%ph-Q@NQ3s( z#YGphH^ne9#zOTx4~Mwq-o5>ER~zlMWMMSWGcp8at)Ebt%$+tXOxSXtA!N8CAbOrp zEBUn0{@ZkE2^MZ?S*YN_rxRBQi@SeEDA%9vD8VAh=r}!Ef<;m~Bm&Z&U9_?;>m7&c zC4{>4>56eIB359_tDvel1nsnUFitsxP}Lg&=}??t518)uBKHtNX5n;3B^D6{u>P%3 zRfibfxvRZoazLm$IbBeaMUwIEbZto%NtusObxC4>IQiv8z9H1HMov$VWRWnHjD*_v ztwFwKN$6yR3f)LZ5}GG%u<P>6<S2xU)AY5HERxa@k&p%guei(0dF#rKBNXIKe+Y6! z%k<wMb+aNNrPsxU0<uRmUiu@{MNHo)#Ud$vI}sAWx1FW`^4aM(GBKJ#TC)r<rzcCX z7)$?5g2cQ$)1$b+cke*uFlac)gn<EK0;A3J(;$N;B|{7f54_?V`|0FEaJB%a`UTVf zOR-2Yu9_|>&0-AeqbEzV$TDV5Z<J<{gi_L*_#k=T!t2yKquEjwETE>op`IB7!<6ag zLF(pDe+e>S`*c|u7D;I~XGpvKV#KNoo?qra1rI-fJEa$=2g<NCLhF<1Z)8~f7_+Ba z%d+^Qw4vLlFP3F-WelDEQkKP9dS)i1@w`5B_0==N`^2ENt|<e<is|-pERu{nr?1Xs zk(^#6$0Egebb2pH2wWyeGB!;=2;%ilzb(fiDZMijQZoI`Vcbxl<N~TMO!UA_2Z(ah zU)hiV4ZZwEr7B+l)M0^kAh1+r&{p5h>9O)Gl8j&z#8?a%7*<Z72ol&ieYHG`G2_nZ z_dz^xKUZeDr~(UUX>p<g%WTHP>3<biKs{h_MV53}*iThtk(I`pJHfR@@AR{ZERxbr z&?FXQcR^c5R&Y5u>3|i0a|6gwX(bj(X-8;&GH{v|znzVr385}xy1x>Oq$$=612zb2 zIRKUcXC)B@FdJ*O2Fv74zo^6_$vA8JYmh_kLNlC}kcKg1_v3{KhqO$WS7wnk#hN3* z2B8%@yAfKUB?nm5=X^+}GZL%~d$=no389J=nv*A6zfsQWoz;Pmk)6I<nMG0>YgPvv zS~dN>GK(Z5xFi!%1PlEygQSoOnam3hJK{iHOk+Jm(D(^Q`E)xK79&W5Q<AZ0dbbLT zq;y9)B+0E`nL7D_=$Cn*tY-ku#Z#v5S7DJfU04q3XP$fi_{P;^5;f2o$&i6zV>!f2 z(L&1trOj%Dp)y7c49BPQs<KE*-!F$Ocm9`JX|C0{3N%IlO|3ttJF2osGV)E22C37i zfEeT(<+Ej5?;+5zGDw{fXfUu}l||AtumWO`&9h%!J~5e~K_QR=0|tid3dnGg!sZ>K z8Z)NegSx?hfuVW&U69!`pbB2BdEe>#gMS}X0k~r;sKz46cyhY78jGaN%L+)JQ)Xl5 zqvt|DWT5H{7#LV8rzfbfNSG>BLafr6<LR~3p&iz|FkoP?s$^hLVqj>vpA!*x^3kC< zgx;9xYt>jJrAsRzMY3M)3fAuttjq`nUDF?e9I<TrZ;-k@m5_k=W~2Y>R2|!Us5(Oi zhD+1+)mbE^Uspn6OQ$EX$86`_O9%zurzfkk7&E3%-)+ERJpGR@ixlIP>HN7YVk}0W z^;QS9StO@RXs|Rfu9-etgGEyM6KD}R=t{}!YBKe&r-Q=96f({OZ6g1f{!)X*m$7!b zq84ZrLX$;`v3+{BCW|qn)%5wA;6bprAPTHNjK!FN!DBjD07`+yeHl+p&(~ssQj&~I zrh^^wL5oESmJa7kSJh@QhVVobz=b|$HwQd=Y{0<qbb7Bgi=_1D21sdNb4_65-$iC} z;1-1`sI>~QfN{$7dOa57=?e^4q)_aHNKZ$$A6bY3HrOsmxI^Lq;v<-sAujTTItIcs zhVqb|BRvP|wWUv4YA&o`uL5@&z@Y**RuWY!<Gksw^<kkW35$J@w;}EUv7n-;?m@Pb zanAH`Ll#umq)*>($O3abNU_9pE+ZBhh#}`L>SWZDhsiaJe?He!*K_U(pLinT_1 z@`r?(mB5`Na6tr3V2HpLWdk>X6{g=cVv%IjnSS1hMU>S<&y2xux}Y(OFJs^IjV3Ih zX^}=#7SZVsOjuZ?PxU}D<9DC__l8fDGr$?a$XL%9(rFiEHP*9a0C(I$-55(~*Fpp= z{Al`bV-`uq*V9E!Sd2}-^guH2hsQPB8O4t(F)<qIfjZ+13}U^Iez?{X8}-y)(=vpN z!t`2@gTQ@HkX5D(m`;RrYe2G=4B#O$P|sP>1>RK?VKve-G~F=0(G=XL2FWl&dHmA@ z%~&L*btgbZxw5}+GqL;R)DH0@Xkfx;`gw$|=}cxUQqaD%^qUC`3^EK14IZ2u-Zmas zs)Eo1F_aO~%Vy%3IDMZviv%O2w{5C75xl&&;hJCEe#x_W%MjY4CW7xjYgqbD@#XBU zrH~@Y2;>OVaR6vX6|LV2<HBe(>!oqq3o#uQA_~(%;WORNg2e>VwH28jpU=Vy8l);@ z(T0y7s!Ts<!Q#spFrD9$C0#mhDkMQFn@l?t@T?a!5Mu~w6YZQn(UPT+F?+hO6-zqf z;px>@EWV7{(@%nUInxcTStJ?PPxl5<U#Hhwvw&MoV3s7K%Jh5}7BLn>0|u4p8y#6B z84aeN1u1lz{@j|ymoa#{sSS%UW6bnS5C!Q6GZs$Y4&s4_*o+zLrpw#1NSb!cgwzSQ zEGJIleQ5pzRPloAU52?cA?|LM=J<K0RWTOaoCHq@K?k?nY*{iGk;mjDr@L8!2FvVN zj2Tx=FSKLvW!y4-za5Jt<MHV?LA(dkCswgYGJcxwXwTBfm^A&cJ&P}7EUl4o#q`Mz zEWU`o^lt|Oed&pyTE(1!fr##Ots|%z;1B6q6@;FTcphF<k0{chLD)L|v?GhJ^vgMr zMtMf@y8plUS7(ZV+VBRTKJDk}#!f88I0yU;7-mjybOLwqXFIV-N<Wy(0NVV}@Gc;{ z?}cDaFgP`XCk()4izFksToGXdcgYS+XLe>W2BoC;%;MAioLNLT8RkLsgR`T^^m=C& zRz^q)L`{z{UeENm&McCQD7g|Q2h|5oHj<FED>;3U3yTzE%=Eo3EWWUKgcOR??Oa)O zq$3wVGV$gGkN~Nfcrc3nfWllR#--C+U0JLdr%ylV$|A|Qa{6r$wQTxVR~BRGWeXv} z>^d=JcV)3T3nD>*lRK!T6YItzDSc%Tq?>HH)jC#*w+l2z2%5w<U|=YiKG6+4__rEF zEt-DRjl~z*6Jne?UDusOQaWiCq%|1!VDF_@7gvMkk3d<<kb%KqdZIf^y6NZTkoITH z&Yt4S66`|Y#0#DX{IeWVX?OVuxK}9M2ep#G+0l>zl9ZX)S4@}iU@>CkpYH9!(#XWK zYWg`376}=rnUH~(jm;uzO$GO?!LbP{=^5BpOlR_B(PB)TuItI7$oOmeLN69cCXUt9 z_js{LOmFgJ(P0#uz8)l%GX0__izJ!~D0jMr7mEp$4bzOuoyAx_J=~kcm@#{Lw>OKg z>6$f=%7;t6Cg7#SvQHwQ*==z1<H#CF)}0b|<M^UG<*T7d*nolI;&fgg7D?&HYaq2^ zZhJGs6R$1Ppb88b7(PvR^kI=?;#@mD#)m~BQ)VrsDX3kz$ol3wk&Pmdr55H43{Gny zo#p9q-TBG^XQqfS8m)yyO2Ar3k<t(!)6c&6f-2ZuhM>XsRH&ZQk`~fGZs@6iWsEHJ zOc;u%-}PaUWUQV3-G>D<q^Ir6BFT7ex~ngXuk^jO5XV;Y{I`|!-vLTd(C+Bl>1%yi zBu)RXg)~RG`IP#i9E175Ne<j!<z5GokygC@(^oEHDk9H|Pyg-9A}NhkE4ZB#I$ht7 z1+?P9(~ku-_gw48l8!VzA<6h+x}-mgFXPwk>HaL{jEphU=LfJDOS5i<Bs^!%-HX_A zL?(jW0&Z7;C&DDBvjwt9K_<l{8QZ2?2eL>?PuvU%N{JW$^t}5^kAagG*b(!m=LfP# zn(o*P>3C@SzI;@-;mS!CMk75FP>IBF2`baX_j$$LN0)XXWZq2Q3o@I13#3CaZQazf zWv?%`AQUJ~{}{+3$!Is7JBUS6I(iGFm2pDl-ijT|PSqjQRZh1LVv#hRu?5l$xNqfW z7V^<KAE99T7Dzc2x#?ABJpb-igv|Bny&$vQc0me~ALqEVX8LWr#snHAGzQJ~CQUyW z#3IR9GW|A4UB@oSNDs5s=8ZO4(?Go_BT$)O!7zV1e=v)r>6TrPvZY%!Z+6Irl-Ep* zab|kpz&*YT;!W$l@(cTn{lHVrrh1@xNXV>|^rKynM9JSg^^PG&3#emdpl1SdgAjOn zm+|}b)xn@_yL<YvV3sY6;DLzq&_V0zDWNQWjKb45hqAnc6w#8?w}pYnWLU#ld>Lh? z2Zys5!^%*|j47ku^xYsi@Vu1Nbma&ZV`;11kTOL4roGafHDU+Br4o2mf%o*n2$rpk zkg5FX4v{Q=5PQU@FN<U`gVd2C(?3SC1WTXU4M|~JRy?ZWH(&P!JZJ<q<m&YJD3+Im z6i6~2oL(EvA}M`l52Pfta7|s5#4H{ST2ul_RoAC)jAlt^ygpqrhQ*li>2%*1mPXKs zatw>4wCzENuI($;Ui4l(bOzk%0k4374k^u_E*r}t$@qV|c`S=D<MZj+u`H4@Scgf# zj^>V-z95!G0{aLlSOsKUfep-doc=Zz*Dxtq0eG-OlCf&KbsUSNG}hrzusZMn5U8VP z#K3@cbO)^JBxpDkG~R5)z;Ji^-Z)$%Fkr=4M^L~rlGC~4K`m))L!w{>PSfo{3a}1| zf)#*=M4=98ncfRhjCEWTtoY*egYhhqjJeZqgVa@@VqoB7U}*UGRcBQj%fg=`jB%Er zDN_c9&guLKERu{y)9)v+h)uUoV3B2Xm>vrf@|j+r#3IQUJ$)jGmp*-U0*j<{;b}-a zAj<HwOnf0*0yy`98%AIgB&D~XhExE3H#JY{=I;)LDllSTfSSiUT{n>>U0U`G#6`O= zJxf|qyam*wFw_GN8|6=5pU5J~7%}~1B8xGj<n+HFYR_~-kYmE9GbXc0GD4RqfK4=J z1XGgJ&m^%(L5BuGLyJ(Qz0;+WS&UJ1NJ{&hhSVmf-?BzHs_i#}=0Q^i2LI`ElUaNj zqo==4W|5T6KLbhUinsOS)Z-MNGcneIMkWjy7-Xl*r?5zxUa5lkVv+GRzxhjlnnUxU zAp-*rtp*GXKc?rVut-XCT!Lib15&DNyW<lcfU6~Nr}XFag()n?(t?*D)$S^uYybW` zUo`>OBH$W9efs+p7H#FiOOP6&+!A8aha<HGbFQDc3{q$S9;>yPZkx&?DUEwf`{MM% zR2E6bd(*p9StK*DjQN7RYsA3Ncm)!xKYmqb9EzB-l!-Cx3Z$I=5dujNvPut?4{$0$ zrmVpUV%Zf)*rY@rJ~WSi0V@;Z#4C{U_t$jZG!{we6IUQD6hp3$ueIDnSeO{MT!G9a zOquSO1|F-92C2hs#j5H3X)KbaxD_;IK_c)?N>u1wn**R#dX|tb_3`O<L1yEas54+- z*gIV?9i0AL(^-s7C9gxmxcOR`+T&6eK~Na$8H2_$Bd<dOpz`eTH)7R+4PY5?03=Ue zo6aK1m_PkE$e^Foe}j0CD4DL8!Q#hwa(ZnBizK8W03I9zFZ`2aygdDM28*OLXwMmF zO6pL(-^2X-yW>D*GdOQE+@JnGgGJIzNC8q69=`7Krtx_-sD}+|0UIzdyuAqt$Ql#f zCm9Zwph^a`rqPsvf$`RKzf6{MjF+d&X0b?0!_G>`_*v7yV!zcLniC8_MO|PPi!r0c z^i~k{WBSf47GFlY>Fn7ov$0R6fLAbPOy8T$0$TKPJ)5P`^yWQC(~Bo=j>0pYFnNUO zPwznzRQe_TZBJSSL2EONAYIO{(|dDRB&Ao~hXlCiYQ2E6O|=TpU^M`hBL{O>jIkFW zU^jpV8?`x?K7d#Oo^6n1+&Vormqk)~{{u*hSiXxfc`n<U^-w1nf+BokE;!MFCP<`D zJ%A+68@x>mCU+-;hBpl%gV)!m-_K={)ctx7k^%ac*PFB$RYO+NfwL!OHhMH&HIGFR zw3hP+vlxpZ0|R))ktCzk^y)koNg4E+Q6@&vHgnK2XU3<~H{`LzDT_XZlm)AwLR^1k zf&DAThks(gt_L@M@~0c-vp{=wkP!)K?`Mz<XuM5v>ISBzzrlk>-~<F&ODi4u4AK+{ zel2DeR+;$~Tm*qTNLkZ2=d-wS7C(dd@yv9_0v1WeThpaM)RXC^1uVwWc`qP^=;53G zhJt)W=fS$cB{-xtHGNJ2ix7M~1S|$|7$h7dL5-V2q!AM#P#X-QLi)i=NbHBUCGur$ z+uRI|eMl_*V3wSoQ^+DE{qiLwd7XUq?f$2pg;&5H1UHGbrY|gH(dPX665{^;=?B|D zYljP2{1|^uw=H6kWP~Kt=><hBI?Av$U&XJ%+u<7oUd`y=CGT<!WS${-Ci~m;{Y9W2 z(VOYFidcN4L6@9!GcYuC+Aj6Ida=MC5e+KS9gA6vr60_MbZj?%jAWlvC7%LzKWI4+ z!;R_v#Vnw)8}NwD+vx`@LCXb;SxgvzP8Td;kz`_hKV7GUMM7HmJtX-yo%nF`oxE!l z*bXB-Ln8*|>G37tF%!`8h3UsiSTY#Rr|Xxpq%$6yKEE6?M5Ho(V=0RyBX~Fix>i(d z`tMQ}b4K&&+2t&fj1Q*!ma#}Of}JDAV#xp+LqgI4am@5{Wh_#VhNsx{|79$JjLOpk zLAoJ^NZ<MZNsd8Jzb%}5eLtv*f=;S}T_S0UTS3@INZhGC{KNlO>rn$D&EKB>wwy&$ z`sYVTx%%==m^PCG^E4*L*B>G2S!KFn1&c3Z)Aalb7D>|!pCCbflfCzOczf>(aL2+3 z)Tqz>3@HRJr<`0YvO5RTB{bACHe+a<zPEx!QhLf~ND!yk{EyqQ_cv&O0G!7S8J0}{ zSOJM8P?+qPZrI5p&TPPNWV(GN$jZ-<ir0ZfGwQK^1gOF_&@%&N!&gu%*9o0Sv<%z~ zT6+wY`8U0{l0{Nl@C&3^(MxDk|K0Rs3)r<_t&pU^C^!9fCAdBIwUWhH+U^S^5F~fZ zTWP;g<0H6N2wo%WG2OX}#aKG%3nT_sH+-plz1DCm*gUZBq2p|;r?0MJk(3T&frJv{ zuD?}rN9vLVK)WG8$3ie%n0_Cm;4ajlS;vLD4p_QwWMTw6+?au3$MlKqETFEgZZ(S} z<Av#oQ&}V#UrkR0@xD)g-_0T^{qHlRBD#2@fb+ccwPu87>FMi1>I|k=Pi2vm_WTNQ z#nX(W4K4R~E=8z|p8gl4u6TNP4-2SIY*+&xRPwID8fGx3otj<`Qt<gJq~BV0#MzId zZNYAYv4YbTC$UH}%1%F9!=lY;_l<!;gMpzTZ8~EuizMT|>Czxd2vqJ!PWP*2k%IPb zKqb?AX36PuYFVW4EX>_9{US&|Bz&f`)Uil0v45YgP{$%++OG|XX1h41Jy+gy+z01> z13gm)2C46mAow<KpKFiH>ol+oXzdPz&h*?m7D+~z>Fsqa#!QU2rthg^k$}u{h_V{$ z85+b*e_zKUX{wtKNwpd8x4aKBDFIDUn(7&v>lrW<e20|C4hwQlO8&?JmFJ)d1VaXf z`sudyEXIu8(+lfaVEYT?3=J7(euu0GweDJU$4K!fsGVS>XACMrw@u$)&mw8MjvJBy z^%*Bmk2{_C1zZXl>KU0c9R3a|qGPY$%Ae!HSP7Of1GR|GOy_N2F=o6m-LZj1lJV{I z=mt;{!MVN}*-@Z@P$Te~H7;<5J3jqx1B;~0neULoqVe)E88&7;kTXFu$%YIJkP1>_ zx>h52I6l6S#h6iL`s79yU&i^<A2zZ`GOnBc8$=zNF51LmERDOWg$yAx&Yxb}#A3{- zIDKOi3#f`Z-NYg(t@RfY3fZ<(Itnk}ISyW?1s+_InjY8!Zo<j7ut>^0{RdgYyEtm< z?*&UAF925{;H4iN|EK#kvq&(?P3LZ7kz_QU-q;KtSeo6;A}JlfzzDj0qe09-vhbH{ zb{9BJfQ|2;e!iJS(iFG33`~sRB+Yfs>~?4z|9*sx$EJgv#CU2t$O=ZNJMT=-Z)K5` z#%<n@>GMJUk(%Dy#v&<g$jrzf&cM)MzT~;a@^$}Kf=vfE5L~9eZDEm=_F!fNFORP2 zp4S`nM}9X#0n|cl)-ys(XM~smbsEWG2ep8pk06#wTd_jI_-94)$H%JkBoXxuq;bFq zrG%z`ZDTQJgl1|cCKeOOJPT-nB)A+TRBAAy6bp>!rzduRtJ`W2^?CZ#4i;@jyXglz zSQMd_FnUd2*bPo=;9V5p%0`k=c)E8d+#OIQ(>HapNHHo*KikP7iDTLkG#hqiIwNS| zEW`_V)Pd&|B&Bh$@dZy&fTlmq8O)~71(^w*LV)Omt<Z(8C5FmDtcCdv!oyQRKs^sp z2lXc-q*{TRG5ygSW+^BeMnQE!stY`(LyRS;fYEb0Z!aRWCr^*=1=s%hE-aGM`+8YS zpleh?dpShe%s}Pi(&^uOS$w54`4|~MEy1wB(|(BpTR<g)8KfUmGCjVJ#g{R2`r1Ag zW6+cqX!F?8>A(AknbI<bO=-c_ZC;vQ+Yeq2I=vt6&goD3k*h4&zB_SdO9p5fga#8N z6wvCsa}!uh7<W%+p2z~*wZaJAy9Xb_gzADAg{SI<sKe5-fz{IBN*I*reJ8P4GlD1D z#F-5l0>Im27~f9c3#y`3rrS?uk(~Zv5{n7rhUo_<gTo&r#JF#I<YX3Km^!drqx2FH zM$pB04XYK;SJ<t~NChuC1s%@BU^hK>3X7z4?OI5Yed`)u)uOOtH6o00pp&c^7#J>3 zpE!j@l5y?y)gX1-MIaHl*!O+oUGtSqpji-5&x?WK(DeHt1s6pa!J7*M+ReLX#Lb$D zFbLYlh6E5SWkTCWkOmK|nFMJC;R!=XLS}@tg75@o+H}Kd;PEd|vu1kAG!`kwrPJ#{ zLfEM3&p--PrZY}wF_vB^&d4Clz|in>q406pJZ4ZGYM=+6cL7gTOHI$54xX#sKApu^ zdW!@j0~Z5B!!}KpXr)`-ph0$MOJd*jg)>+rP0va&g14;Jao>z9l{o4FuKmHi-+K~_ z3_=VH4OdD{(rOQ^e+zDrg1dzursvLJkp!)P1g{HF^7PctKYwu+SSz@;gP6^@W%}+J zERsw@($lZaVA+DQbG8w*7j71dv2?5qq~du{eOEG}#7LQm(azRb4^%bn+ulEmC6JL( zW%|R}ERu{-(|^xqk(B0>g+y~k_v$P63=@OEt^&`KLDq~jn=n8&p)g6xPT#PIMS@9P zc6!|$770_#&AD;Ldf<r*Gg(N8zJK}S*tgdgrJ$qWMhpy|(@)P~k(5rBWd!fH3I8Z_ zZ`bqlunve30|T_pDKVEthvSAUBZDdfL&J1|*(~DIljpKzgPNgp!GpKpodl<*=g()6 z1UX1<9*YE)-NJDopPQINO=S$2o;{Dnm@#$w{CO;rrX_NW44~c46XtG^c(-S7mk4}t zL0uLib35lqkLsc=JWPz1dWPV}A7s-a<DTj4^I43Ugyg5&%x961#;qRWLNnY7gyb0+ zBpDbQk}cWi+q61?wp@e8pA8ro)Mcmdo6lk-&7uIw&^z9#o|ycRBNLn|KwT>6#$st+ z1xRSuez<aIjVH@yumW(pg2dqTumvnKkTqVCObQCq`xdZBFxE|<xR6C;`tAiR!7#S+ zLY83ZL`8^gGp0Bkxw0byw6)L_GMoq2q0PBOk&!_Pv^{S6(S<C&((Pf8(&WjTT~Y@W z{$6BZtTWI9*8|{~gp68DcU#1wW5=Y-2p(!L%FoFuEnr{>$hqyoztnM}2qSEm;h-|4 zDWW;;Md~}vW1w_nsRv$E0Zn_RxC3&J93*$`)t<O--PH>p5pmWx{qG_cNyatP#TT=H zwm^9=X7QC?ufho4(EBPdxjLX*qYj+x4fQM;7|NzgFJX~nygvQxVirlp#_7)&vuJak zQe|Y|VPI&0NOCOzZ^vg~IIv>6-4Ygu`n=S{qMX#q<Qvm=<lO%#nEYE9(%-l>@5_I+ zi}luAB9LbKdq?HG3*VbhiHShEh2JW-<oI|hw`ht$)CWJgSTylbyqtvyWK?U@+Njp$ z!4p>bi9mWb&tEP#65A1;6(<52zS(PYY~#foTcfKz(hv)(zq&{$zS_QOhBU;2z^T*o zF33ikua<^b@aWyo-CA2dmF=2txRgbn@%i*X2vrE8TBlEhP#c%B$Q%CJ3F(i;sLHi$ zstNpICJX7-1eDyg;koT|A6@?bbjD>Y@`eu{L7cYe`c{FBmu2d{gU)khU}%_ld*>{f zIh`U*k0CC5yP89&F!$+i(dmK9SmYV)rx!w~i4bbzG8TD9`?nBZO}o{vlsV_S%05L% z;ahoj{hy|a=cXqVA!TiK?lqSO=|<e>S>@(*!R0LS^~y?+it0qyray-R0+$&pL5z7^ z(v&HX;(6Ov36g=9W=D6YxjV`fmnIh_7N;_7J6ga!+gG&6K?PDo-VUu^624kN(pv?R z7#hVx`TmQT+zVHMn19qVKG?p@>iP%Jd1;{I@IaTAGcZhFzno<TPfB7*s%~0dv3_Yu n^7M`SSVh~TSFmi4Ucov~ObA&{Ul*+6<3d)|?LYRh{^SP$ie47i delta 54076 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�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 WMtjLhmhB}gSvQGok2}EngC78XN<a<( diff --git a/dbrepo-ui/components/dialogs/EditTuple.vue b/dbrepo-ui/components/dialogs/EditTuple.vue index da8000dae2..ea0bfb3c5b 100644 --- a/dbrepo-ui/components/dialogs/EditTuple.vue +++ b/dbrepo-ui/components/dialogs/EditTuple.vue @@ -17,14 +17,35 @@ <v-text-field v-if="isNumber(column)" v-model.number="tuple[column.internal_name]" - :disabled="(!edit && column.auto_generated)" + :disabled="!edit" persistent-hint :variant="inputVariant" :label="column.internal_name" :hint="hint(column)" :rules="rules(column)" :required="required(column)" - type="number" /><v-text-field + type="number"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-text-field> + <v-text-field v-if="isTextField(column)" v-model="tuple[column.internal_name]" :disabled="disabled(column)" @@ -37,7 +58,27 @@ :variant="inputVariant" :label="column.internal_name" :hint="hint(column)" - type="text" /> + type="text"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-text-field> <v-text-field v-if="isFloatingPoint(column)" v-model="tuple[column.internal_name]" @@ -50,7 +91,27 @@ :variant="inputVariant" :label="column.internal_name" :hint="hint(column)" - type="number" /> + type="number"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-text-field> <v-textarea v-if="isTextArea(column)" v-model="tuple[column.internal_name]" @@ -62,7 +123,27 @@ persistent-hint :variant="inputVariant" :label="column.internal_name" - :hint="hint(column)" /> + :hint="hint(column)"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-textarea> <BlobUpload v-if="isFileField(column)" :column="column" @@ -77,7 +158,27 @@ :rules="rules(column)" :required="required(column)" :clearable="!required(column)" - :items="isSet(column) ? column.sets : column.enums" /> + :items="isSet(column) ? column.sets : column.enums"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-select> <v-select v-if="isBoolean(column)" v-model="tuple[column.internal_name]" @@ -88,7 +189,27 @@ :rules="rules(column)" :required="required(column)" :items="bools" - :clearable="!required(column)" /> + :clearable="!required(column)"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-select> <v-text-field v-if="isTimeField(column)" v-model="tuple[column.internal_name]" @@ -97,7 +218,27 @@ persistent-hint :variant="inputVariant" :label="column.internal_name" - :hint="hint(column)" /> + :hint="hint(column)"> + <template + v-slot:append> + {{ column.column_type.toUpperCase() }} + <NuxtLink + target="_blank" + class="ml-2" + :href="documentationLink(column)"> + <v-tooltip + location="bottom"> + <template + v-slot:activator="{ props }"> + <v-icon + v-bind="props" + icon="mdi-help-circle-outline" /> + </template> + {{ $t('navigation.help') }} + </v-tooltip> + </NuxtLink> + </template> + </v-text-field> </v-col> </v-row> </v-card-text> @@ -175,7 +316,8 @@ export default { bools: [ { title: 'true', value: true }, { title: 'false', value: false } - ] + ], + cacheStore: useCacheStore() } }, mounted() { @@ -183,6 +325,15 @@ export default { this.oldTuple = Object.assign({}, this.tuple) }, computed: { + database () { + return this.cacheStore.getDatabase + }, + columnTypes () { + if (!this.database) { + return [] + } + return this.database.container.image.data_types + }, title () { return (this.edit ? this.$t('toolbars.table.data.edit') : this.$t('toolbars.table.data.add')) + ' ' + this.$t('toolbars.table.data.tuple') }, @@ -204,24 +355,35 @@ export default { this.$emit('close', { success: false }) }, hint (column) { - const { is_null_allowed, auto_generated, is_primary_key, column_type, date_format, size, d } = column - let hint = is_null_allowed ? '' : this.$t('pages.table.subpages.data.required.hint') - if (auto_generated) { + const { is_null_allowed, is_primary_key } = column + let hint = '' + if (!is_null_allowed) { + hint += this.$t('pages.table.subpages.data.required.hint') + } + if (column.column_type === 'sequence') { hint += ' ' + this.$t('pages.table.subpages.data.auto.hint') } if (is_primary_key) { hint += ' ' + this.$t('pages.table.subpages.data.primary-key.hint') } - if (['double', 'decimal'].includes(column_type)) { - hint += ' ' + this.$t('pages.table.subpages.data.format.hint') + ' ddd.f' + if (this.formatHint(column)) { + hint += this.$t('pages.table.subpages.data.format.hint') + ' ' + this.formatHint(column) } - if (['date', 'datetime', 'timestamp', 'time'].includes(column_type) && date_format) { - hint += ' ' + this.$t('pages.table.subpages.data.format.hint') + ' ' + date_format.unix_format + return hint + }, + documentationLink ({column_type}) { + const filter = this.columnTypes.filter(t => t.value === column_type) + if (filter.length !== 1) { + return null } - if (['year'].includes(column_type)) { - hint += ' ' + this.$t('pages.table.subpages.data.format.hint') + ' YYYY' + return filter[0].documentation + }, + formatHint ({column_type}) { + const filter = this.columnTypes.filter(t => t.value === column_type) + if (filter.length !== 1) { + return null } - return hint + return filter[0].data_hint }, isTextField (column) { const { column_type } = column @@ -252,7 +414,7 @@ export default { return ['date', 'datetime', 'timestamp', 'time', 'year'].includes(column.column_type) }, rules (column) { - if (column.auto_generated || column.is_null_allowed) { + if (column.is_null_allowed) { return [] } const rules = [] @@ -273,7 +435,7 @@ export default { return column.is_null_allowed === false }, disabled (column) { - return (this.edit && column.is_primary_key) || (!this.edit && column.auto_generated) + return (this.edit && column.is_primary_key) || !this.edit }, updateTuple () { const constraints = {} diff --git a/dbrepo-ui/components/subset/Builder.vue b/dbrepo-ui/components/subset/Builder.vue index d19ec1598f..a6f53c6e4f 100644 --- a/dbrepo-ui/components/subset/Builder.vue +++ b/dbrepo-ui/components/subset/Builder.vue @@ -123,7 +123,23 @@ :rules="[v => !!v || $t('validation.required')]" return-object multiple - @update:model-value="buildQuery" /> + @update:model-value="buildQuery"> + <template + v-slot:prepend-item> + <v-list-item + title="Select All" + :active="select.length === columns.length" + @click="toggleColumns"> + <template + v-slot:prepend> + <v-checkbox-btn + :model-value="select.length === columns.length" /> + </template> + </v-list-item> + <v-divider + class="mt-2" /> + </template> + </v-select> </v-col> </v-row> <v-row v-if="select.length > 0"> @@ -594,6 +610,14 @@ export default { keywordCase: 'upper' }) } + }, + toggleColumns () { + if (this.select.length !== this.columns.length) { + this.select = this.columns + this.buildQuery() + } else { + this.select = [] + } } } } diff --git a/dbrepo-ui/components/table/TableHistory.vue b/dbrepo-ui/components/table/TableHistory.vue index dd3dad66e2..34d45248e7 100644 --- a/dbrepo-ui/components/table/TableHistory.vue +++ b/dbrepo-ui/components/table/TableHistory.vue @@ -28,6 +28,10 @@ :options="chartOptions" :height="200" :width="400" /> + <pre>{{ history }}</pre> + <p> + {{ $t('pages.table.subpages.versioning.chart.legend') }} + </p> </v-card-text> <v-card-actions> <v-spacer /> @@ -52,9 +56,9 @@ </template> <script> +import { UTCDate } from '@date-fns/utc' import { Bar } from 'vue-chartjs' import { format } from 'date-fns' -import { useCacheStore } from '~/stores/cache.js' import { Chart as ChartJS, Title, Tooltip, BarElement, CategoryScale, LinearScale, LogarithmicScale } from 'chart.js' ChartJS.register(Title, Tooltip, BarElement, CategoryScale, LinearScale, LogarithmicScale) @@ -69,6 +73,7 @@ export default { loading: true, datetime: null, history: null, + chartData: null, chartOptions: { responsive: true, onClick: this.handle, @@ -92,7 +97,7 @@ export default { }, }, x: { - display: true, + display: false, ticks: { min: 0, stepSize: 1 @@ -118,15 +123,6 @@ export default { buttonVariant () { const runtimeConfig = useRuntimeConfig() return this.$vuetify.theme.global.name.toLowerCase().endsWith('contrast') ? runtimeConfig.public.variant.button.contrast : runtimeConfig.public.variant.button.normal - }, - chartData () { - return { - labels: this.history ? this.history.map(d => format(new Date(d.timestamp), 'yyyy-MM-dd HH:mm:ss')) : [], - datasets: [ - this.history ? { backgroundColor: this.$vuetify.theme.current.colors.success, data: this.history.filter(d => d.event === 'INSERT').map(d => d.total) } : { data: [] }, - this.history ? { backgroundColor: this.$vuetify.theme.current.colors.error, data: this.history.filter(d => d.event === 'DELETE').map(d => d.total) } : { data: [] }, - ] - } } }, mounted() { @@ -153,13 +149,28 @@ export default { this.datetime = this.chartData.labels[idx] console.debug('date time', this.datetime, 'idx', idx) }, + filterHistoryEventType (history, type) { + return history.map(d => { + if (d.event === type) { + return d.total + } + return null + }) + }, loadHistory () { this.loading = true const tableService = useTableService() tableService.history(this.table.database_id, this.table.id) .then((history) => { this.loading = false - this.history = history + this.chartData = { + // labels: history ? history.map(d => format(new UTCDate(d.timestamp), 'yyyy-MM-dd HH:mm:ss.SSS')) : [], + labels: history ? history.map(d => format(new UTCDate(d.timestamp), 'yyyy-MM-dd HH:mm:ss')) : [], + datasets: [ + { backgroundColor: this.$vuetify.theme.current.colors.success, data: this.filterHistoryEventType(history, 'INSERT') }, + { backgroundColor: this.$vuetify.theme.current.colors.error, data: this.filterHistoryEventType(history, 'DELETE') } + ] + } }) .catch(({message}) => { const toast = useToastInstance() diff --git a/dbrepo-ui/components/table/TableList.vue b/dbrepo-ui/components/table/TableList.vue index 362f4a9366..2fc2c7d791 100644 --- a/dbrepo-ui/components/table/TableList.vue +++ b/dbrepo-ui/components/table/TableList.vue @@ -60,7 +60,6 @@ export default { { value: 'is_primary_key', title: 'Primary Key' }, { value: 'unique', title: 'Unique' }, { value: 'is_null_allowed', title: 'Nullable' }, - { value: 'auto_generated', title: 'Sequence' } ], columnTypes: [ // { value: 'ENUM', text: 'Enumeration' }, // Disabled for now, not implemented, #145 diff --git a/dbrepo-ui/components/table/TableSchema.vue b/dbrepo-ui/components/table/TableSchema.vue index 5e105577d7..57169a95fa 100644 --- a/dbrepo-ui/components/table/TableSchema.vue +++ b/dbrepo-ui/components/table/TableSchema.vue @@ -76,9 +76,10 @@ <v-text-field v-model.number="c.size" type="number" - :min="columnType(c).size_min !== null ? columnType(c).size_min : null" - :max="columnType(c).size_max !== null ? columnType(c).size_max : null" + :min="columnType(c).size_min" + :max="columnType(c).size_max" :step="columnType(c).size_step" + :value="columnType(c).size_required === true ? columnType(c).size_default : null" :hint="sizeHint(c)" :clearable="!columnType(c).size_required" persistent-hint @@ -125,7 +126,7 @@ class="pl-10"> <v-checkbox v-model="c.null_allowed" - :disabled="c.primary_key || disabled" + :disabled="c.primary_key || c.type === 'serial' || disabled" :label="$t('pages.table.subpages.schema.null.label')" /> </v-col> <v-col @@ -133,7 +134,7 @@ class="pl-10"> <v-checkbox v-model="c.unique" - :disabled="disabled" + :disabled="disabled || c.type === 'serial'" :hidden="c.primary_key" :label="$t('pages.table.subpages.schema.unique.label')" /> </v-col> @@ -233,7 +234,11 @@ export default { if (!this.database) { return [] } - return this.database.container.image.data_types + const types = this.database.container.image.data_types + if (this.columns.filter(c => c.type === 'serial').length > 0) { + return types.filter(t => t.value !== 'serial') + } + return types }, dateFormats () { if (!this.database || !('container' in this.database) || !('image' in this.database.container) || !('date_formats' in this.database.container.image)) { @@ -373,21 +378,13 @@ export default { column.d = null } console.debug('for column type', column.type, 'set default size', column.size, '& d', column.d) - }, - hasDate (column) { - return column.type === 'date' || column.type === 'datetime' || column.type === 'timestamp' || column.type === 'time' + if (column.type === 'serial') { + this.setOthers(column) + } }, hasEnumOrSet (column) { return column.type === 'enum' || column.type === 'set' }, - filterDateFormats (column) { - return this.dateFormats.filter((df) => { - if (column.type === 'date') { - return !df.has_time - } - return df.has_time - }) - }, sizeErrorMessages (column) { if (column.size < column.d) { return ['Size needs to be bigger or equal to d'] diff --git a/dbrepo-ui/components/table/TableToolbar.vue b/dbrepo-ui/components/table/TableToolbar.vue index 4c1c86fba6..1c222cc7c6 100644 --- a/dbrepo-ui/components/table/TableToolbar.vue +++ b/dbrepo-ui/components/table/TableToolbar.vue @@ -13,7 +13,7 @@ width="200" /> <span v-if="table && $vuetify.display.lgAndUp"> - {{ table.name}} + {{ table.name }} </span> </v-toolbar-title> <v-spacer /> diff --git a/dbrepo-ui/composables/view-service.ts b/dbrepo-ui/composables/view-service.ts index 642a7c6e51..5b3a25a149 100644 --- a/dbrepo-ui/composables/view-service.ts +++ b/dbrepo-ui/composables/view-service.ts @@ -1,4 +1,5 @@ import {axiosErrorToApiError} from '@/utils' +import type {AxiosRequestConfig} from "axios"; export const useViewService = (): any => { async function remove(databaseId: number, viewId: number): Promise<void> { @@ -66,5 +67,27 @@ export const useViewService = (): any => { }) } - return {remove, create, reExecuteData, reExecuteCount} + async function exportData(databaseId: number, viewId: number): Promise<QueryResultDto> { + const axios = useAxiosInstance() + const config: AxiosRequestConfig = { + responseType: 'blob', + headers: { + Accept: 'text/csv' + } + } + console.debug('export data for view with id', viewId, 'in database with id', databaseId); + return new Promise<QueryResultDto>((resolve, reject) => { + axios.get<QueryResultDto>(`/api/database/${databaseId}/view/${viewId}/export`, config) + .then((response) => { + console.info('Exported data for view with id', viewId, 'in database with id', databaseId) + resolve(response.data) + }) + .catch((error) => { + console.error('Failed to export data', error) + reject(axiosErrorToApiError(error)) + }) + }) + } + + return {remove, create, reExecuteData, reExecuteCount, exportData} } diff --git a/dbrepo-ui/dto/index.ts b/dbrepo-ui/dto/index.ts index 543bd0a391..74b3911764 100644 --- a/dbrepo-ui/dto/index.ts +++ b/dbrepo-ui/dto/index.ts @@ -336,7 +336,6 @@ interface ColumnDto { table_id: number; internal_name: string; date_format: ImageDateDto; - auto_generated: boolean; is_primary_key: boolean; index_length: number; length: number; diff --git a/dbrepo-ui/locales/en-US.json b/dbrepo-ui/locales/en-US.json index db2c41bfd2..3a3846e2ef 100644 --- a/dbrepo-ui/locales/en-US.json +++ b/dbrepo-ui/locales/en-US.json @@ -33,7 +33,8 @@ "mine": "(mine)", "loading": "Loading", "view": "View", - "modify": "Modify" + "modify": "Modify", + "help": "Help" }, "pages": { "identifier": { @@ -544,8 +545,9 @@ "subtitle": "Select a timestamp to view the data for this specific time of day", "chart": { "title": "Data Events", + "legend": "Chart legend: green color marks data insertions, red color marks data deletions (=data updates in some cases)", "ylabel": "# Events", - "xlabel": "Timestamp" + "xlabel": "Data Timestamp (UTC)" }, "timestamp": { "label": "Timestamp", @@ -562,7 +564,7 @@ "hint": "Value is a primary key" }, "format": { - "hint": "Value must be in format" + "hint": "Format hint:" }, "required": { "hint": "Required. " diff --git a/dbrepo-ui/package.json b/dbrepo-ui/package.json index d521b4e61f..5af18adf4d 100644 --- a/dbrepo-ui/package.json +++ b/dbrepo-ui/package.json @@ -12,6 +12,7 @@ }, "dependencies": { "@artmizu/nuxt-prometheus": "^2.4.0", + "@date-fns/utc": "^2.1.0", "@fontsource/open-sans": "^5.0.24", "@mdi/font": "^7.4.47", "@nuxtjs/robots": "^3.0.0", diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue index 85570c5c36..e9173726e9 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/data.vue @@ -50,7 +50,7 @@ :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-update' : null" variant="flat" :text="$t('toolbars.table.data.version')" - class="ml-2" + class="ml-2 mr-2" @click.stop="pick" /> </v-toolbar> <TimeDrift /> @@ -348,6 +348,7 @@ export default { const tableService = useTableService() tableService.exportData(this.$route.params.database_id, this.$route.params.table_id) .then((data) => { + this.downloadLoading = false const url = URL.createObjectURL(data) const link = document.createElement('a') link.href = url diff --git a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue index c9f9882c6c..65b6034348 100644 --- a/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue +++ b/dbrepo-ui/pages/database/[database_id]/table/[table_id]/schema.vue @@ -28,9 +28,6 @@ <template v-slot:item.extra="{ item }"> <pre>{{ extra(item) }}</pre> </template> - <template v-slot:item.auto_generated="{ item }"> - <span v-if="item.auto_generated">●</span> {{ item.auto_generated }} - </template> <template v-slot:item.column_concept="{ item }"> <v-btn v-if="canAssignSemanticInformation && !hasConcept(item)" @@ -167,7 +164,6 @@ export default { { value: 'column_concept', title: this.$t('pages.table.subpages.schema.concept.title') }, { value: 'column_unit', title: this.$t('pages.table.subpages.schema.unit.title') }, { value: 'is_null_allowed', title: this.$t('pages.table.subpages.schema.nullable.title') }, - { value: 'auto_generated', title: this.$t('pages.table.subpages.schema.sequence.title') }, { value: 'description', title: this.$t('pages.table.subpages.schema.description.title') }, ], dateColumns: [], diff --git a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue index 838ef2f0f1..60bfe33a13 100644 --- a/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue +++ b/dbrepo-ui/pages/database/[database_id]/view/[view_id]/data.vue @@ -6,11 +6,19 @@ color="secondary" :title="$t('toolbars.database.current')" flat> + <v-btn + v-if="canDownload" + :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-download' : null" + variant="flat" + :loading="downloadLoading" + :text="$t('toolbars.table.data.download')" + class="mr-2" + @click.stop="download" /> <v-btn :prepend-icon="$vuetify.display.lgAndUp ? 'mdi-refresh' : null" variant="flat" :text="$t('toolbars.table.data.refresh')" - class="mb-1 mr-2" + class="mr-2" :loading="loadingData" @click="reload" /> </v-toolbar> @@ -29,7 +37,6 @@ <script> import TimeDrift from '@/components/TimeDrift.vue' import QueryResults from '@/components/subset/Results.vue' -import { useCacheStore } from '@/stores/cache' export default { components: { @@ -39,6 +46,7 @@ export default { data () { return { loadingData: false, + downloadLoading: false, items: [ { title: this.$t('navigation.databases'), @@ -73,6 +81,21 @@ export default { return null } return this.database.views.filter(v => v.id === Number(this.$route.params.view_id))[0] + }, + access () { + return this.userStore.getAccess + }, + canDownload () { + if (!this.view) { + return false + } + if (this.view.is_public) { + return true + } + if (!this.access) { + return false + } + return this.access.type === 'read' || this.access.type === 'write_own' || this.access.type === 'write_all' } }, mounted () { @@ -82,6 +105,31 @@ export default { reload () { this.$refs.queryResults.reExecute(Number(this.$route.params.view_id)) this.$refs.queryResults.reExecuteCount(Number(this.$route.params.view_id)) + }, + download () { + this.downloadLoading = true + const viewService = useViewService() + viewService.exportData(this.$route.params.database_id, this.$route.params.view_id) + .then((data) => { + this.downloadLoading = false + const url = URL.createObjectURL(data) + const link = document.createElement('a') + link.href = url + link.download = 'view.csv' + document.body.appendChild(link) + link.click() + }) + .catch(({code}) => { + this.downloadLoading = false + const toast = useToastInstance() + if (typeof code !== 'string') { + return + } + toast.error(this.$t(code)) + }) + .finally(() => { + this.downloadLoading = false + }) } } } diff --git a/dbrepo-ui/plugins/vuetify.ts b/dbrepo-ui/plugins/vuetify.ts index 8f48e315dd..e942e529f5 100644 --- a/dbrepo-ui/plugins/vuetify.ts +++ b/dbrepo-ui/plugins/vuetify.ts @@ -4,6 +4,7 @@ import colors from 'vuetify/util/colors' import * as components from 'vuetify/components' import * as directives from 'vuetify/directives' import '@mdi/font/css/materialdesignicons.css' +import {rgbParse} from "@kurkle/color"; const tuwThemeLight: ThemeDefinition = { dark: false, diff --git a/docker-compose.yml b/docker-compose.yml index e8725ed37f..e8cec6aa89 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -89,7 +89,6 @@ services: ports: - "8080:8080" environment: - BITNAMI_DEBUG: "true" KEYCLOAK_ENABLE_HTTPS: "false" KEYCLOAK_ENABLE_STATISTICS: "true" KEYCLOAK_ENABLE_HEALTH_ENDPOINTS: "true" diff --git a/lib/python/dbrepo/api/dto.py b/lib/python/dbrepo/api/dto.py index 72a12bc3d4..9bfb775f0c 100644 --- a/lib/python/dbrepo/api/dto.py +++ b/lib/python/dbrepo/api/dto.py @@ -193,6 +193,7 @@ class ColumnType(str, Enum): LONGTEXT = "longtext" LONGBLOB = "longblob" ENUM = "enum" + SERIAL = "serial" SET = "set" BIT = "bit" TINYINT = "tinyint" @@ -888,7 +889,6 @@ class Column(BaseModel): database_id: int table_id: int internal_name: str - auto_generated: bool column_type: ColumnType is_public: bool is_null_allowed: bool @@ -918,7 +918,6 @@ class ViewColumn(BaseModel): name: str database_id: int internal_name: str - auto_generated: bool column_type: ColumnType is_public: bool is_null_allowed: bool diff --git a/mkdocs.yml b/mkdocs.yml index b2b9bc681d..28f04c8365 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -12,6 +12,7 @@ nav: - Help with DBRepo: help.md - Installation: installation.md - Kubernetes: kubernetes.md + - changelog.md - contributing.md - Concepts: - Overview: concepts/index.md diff --git a/yq.1 b/yq.1 new file mode 100644 index 0000000000..5e4a37a5d0 --- /dev/null +++ b/yq.1 @@ -0,0 +1,17196 @@ +'\" t +.\" Automatically generated by Pandoc 2.14.2 +.\" +.TH "YQ" "1" "" "" "yq (https://github.com/mikefarah/yq/) version v4.44.3" +.hy +.SH NAME +.PP +\f[I]yq\f[R] is a portable command-line data file processor +.SH SYNOPSIS +.PP +yq [eval/eval-all] [expression] files.. +.PP +eval/e - (default) Apply the expression to each document in each yaml +file in sequence +.PP +eval-all/ea - Loads all yaml documents of all yaml files and runs +expression once +.SH DESCRIPTION +.PP +a lightweight and portable command-line data file processor. +\f[C]yq\f[R] uses jq (https://github.com/stedolan/jq) like syntax but +works with yaml, json, xml, csv, properties and TOML files. +It doesn\[cq]t yet support everything \f[C]jq\f[R] does - but it does +support the most common operations and functions, and more is being +added continuously. +.PP +This documentation is also available at https://mikefarah.gitbook.io/yq/ +# QUICK GUIDE +.SS Read a value: +.IP +.nf +\f[C] +yq \[aq].a.b[0].c\[aq] file.yaml +\f[R] +.fi +.SS Pipe from STDIN: +.IP +.nf +\f[C] +cat file.yaml | yq \[aq].a.b[0].c\[aq] +\f[R] +.fi +.SS Update a yaml file, in place +.IP +.nf +\f[C] +yq -i \[aq].a.b[0].c = \[dq]cool\[dq]\[aq] file.yaml +\f[R] +.fi +.SS Update using environment variables +.IP +.nf +\f[C] +NAME=mike yq -i \[aq].a.b[0].c = strenv(NAME)\[aq] file.yaml +\f[R] +.fi +.SS Merge multiple files +.IP +.nf +\f[C] +yq ea \[aq]. as $item ireduce ({}; . * $item )\[aq] path/to/*.yml +\f[R] +.fi +.PP +Note the use of \f[C]ea\f[R] to evaluate all files at once (instead of +in sequence.) +.SS Multiple updates to a yaml file +.IP +.nf +\f[C] +yq -i \[aq] + .a.b[0].c = \[dq]cool\[dq] | + .x.y.z = \[dq]foobar\[dq] | + .person.name = strenv(NAME) +\[aq] file.yaml +\f[R] +.fi +.PP +See the documentation (https://mikefarah.gitbook.io/yq/) for more. +.SH KNOWN ISSUES / MISSING FEATURES +.IP \[bu] 2 +\f[C]yq\f[R] attempts to preserve comment positions and whitespace as +much as possible, but it does not handle all scenarios (see +https://github.com/go-yaml/yaml/tree/v3 for details) +.IP \[bu] 2 +Powershell has its own\&...opinions: +https://mikefarah.gitbook.io/yq/usage/tips-and-tricks#quotes-in-windows-powershell +.SH BUGS / ISSUES / FEATURE REQUESTS +.PP +Please visit the GitHub page https://github.com/mikefarah/yq/. +.SH HOW IT WORKS +.PP +In \f[C]yq\f[R] expressions are made up of operators and pipes. +A context of nodes is passed through the expression and each operation +takes the context as input and returns a new context as output. +That output is piped in as input for the next operation in the +expression. +To begin with, the context is set to the first yaml document of the +first yaml file (if processing in sequence using eval). +.PP +Lets look at a couple of examples. +.SS Simple assignment example +.PP +Given a document like: +.IP +.nf +\f[C] +a: cat +b: dog +\f[R] +.fi +.PP +with an expression: +.IP +.nf +\f[C] +\&.a = .b +\f[R] +.fi +.PP +Like math expressions - operator precedence is important. +.PP +The \f[C]=\f[R] operator takes two arguments, a \f[C]lhs\f[R] +expression, which in this case is \f[C].a\f[R] and \f[C]rhs\f[R] +expression which is \f[C].b\f[R]. +.PP +It pipes the current, lets call it `root' context through the +\f[C]lhs\f[R] expression of \f[C].a\f[R] to return the node +.IP +.nf +\f[C] +cat +\f[R] +.fi +.PP +Side note: this node holds not only its value `cat', but comments and +metadata too, including path and parent information. +.PP +The \f[C]=\f[R] operator then pipes the `root' context through the +\f[C]rhs\f[R] expression of \f[C].b\f[R] to return the node +.IP +.nf +\f[C] +dog +\f[R] +.fi +.PP +Both sides have now been evaluated, so now the operator copies across +the value from the RHS (\f[C].b\f[R]) to the LHS (\f[C].a\f[R]), and it +returns the now updated context: +.IP +.nf +\f[C] +a: dog +b: dog +\f[R] +.fi +.SS Complex assignment, operator precedence rules +.PP +Just like math expressions - \f[C]yq\f[R] expressions have an order of +precedence. +The pipe \f[C]|\f[R] operator has a low order of precedence, so +operators with higher precedence will get evaluated first. +.PP +Most of the time, this is intuitively what you\[cq]d want, for instance +\f[C].a = \[dq]cat\[dq] | .b = \[dq]dog\[dq]\f[R] is effectively: +\f[C](.a = \[dq]cat\[dq]) | (.b = \[dq]dog\[dq])\f[R]. +.PP +However, this is not always the case, particularly if you have a complex +LHS or RHS expression, for instance if you want to select particular +nodes to update. +.PP +Lets say you had: +.IP +.nf +\f[C] +- name: bob + fruit: apple +- name: sally + fruit: orange +\f[R] +.fi +.PP +Lets say you wanted to update the \f[C]sally\f[R] entry to have fruit: +`mango'. +The \f[I]incorrect\f[R] way to do that is: +\f[C].[] | select(.name == \[dq]sally\[dq]) | .fruit = \[dq]mango\[dq]\f[R]. +.PP +Because \f[C]|\f[R] has a low operator precedence, this will be +evaluated (\f[I]incorrectly\f[R]) as : +\f[C](.[]) | (select(.name == \[dq]sally\[dq])) | (.fruit = \[dq]mango\[dq])\f[R]. +What you\[cq]ll see is only the updated segment returned: +.IP +.nf +\f[C] +name: sally +fruit: mango +\f[R] +.fi +.PP +To properly update this yaml, you will need to use brackets (think +BODMAS from maths) and wrap the entire LHS: +\f[C](.[] | select(.name == \[dq]sally\[dq]) | .fruit) = \[dq]mango\[dq]\f[R] +.PP +Now that entire LHS expression is passed to the `assign' (\f[C]=\f[R]) +operator, and the yaml is correctly updated and returned: +.IP +.nf +\f[C] +- name: bob + fruit: apple +- name: sally + fruit: mango +\f[R] +.fi +.SS Relative update (e.g.\ \f[C]|=\f[R]) +.PP +There is another form of the \f[C]=\f[R] operator which we call the +relative form. +It\[cq]s very similar to \f[C]=\f[R] but with one key difference when +evaluating the RHS expression. +.PP +In the plain form, we pass in the `root' level context to the RHS +expression. +In relative form, we pass in \f[I]each result of the LHS\f[R] to the RHS +expression. +Let\[cq]s go through an example. +.PP +Given a document like: +.IP +.nf +\f[C] +a: 1 +b: thing +\f[R] +.fi +.PP +with an expression: +.IP +.nf +\f[C] +\&.a |= . + 1 +\f[R] +.fi +.PP +Similar to the \f[C]=\f[R] operator, \f[C]|=\f[R] takes two operands, +the LHS and RHS. +.PP +It pipes the current context (the whole document) through the LHS +expression of \f[C].a\f[R] to get the node value: +.IP +.nf +\f[C] +1 +\f[R] +.fi +.PP +Now it pipes \f[I]that LHS context\f[R] into the RHS expression +\f[C]. + 1\f[R] (whereas in the \f[C]=\f[R] plain form it piped the +original document context into the RHS) to yield: +.IP +.nf +\f[C] +2 +\f[R] +.fi +.PP +The assignment operator then copies across the value from the RHS to the +value on the LHS, and it returns the now updated `root' context: +.IP +.nf +\f[C] +a: 2 +b: thing +\f[R] +.fi +.SH Add +.PP +Add behaves differently according to the type of the LHS: * arrays: +concatenate * number scalars: arithmetic addition * string scalars: +concatenate * maps: shallow merge (use the multiply operator +(\f[C]*\f[R]) to deeply merge) +.PP +Use \f[C]+=\f[R] as a relative append assign for things like increment. +Note that \f[C].a += .x\f[R] is equivalent to running +\f[C].a = .a + .x\f[R]. +.SS Concatenate arrays +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - 1 + - 2 +b: + - 3 + - 4 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a + .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 1 +- 2 +- 3 +- 4 +\f[R] +.fi +.SS Concatenate to existing array +.PP +Note that the styling of \f[C]a\f[R] is kept. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: [1,2] +b: + - 3 + - 4 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a += .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: [1, 2, 3, 4] +b: + - 3 + - 4 +\f[R] +.fi +.SS Concatenate null to array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - 1 + - 2 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a + null\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 1 +- 2 +\f[R] +.fi +.SS Append to existing array +.PP +Note that the styling is copied from existing array elements +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: [\[aq]dog\[aq]] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a += \[dq]cat\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: [\[aq]dog\[aq], \[aq]cat\[aq]] +\f[R] +.fi +.SS Prepend to existing array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = [\[dq]cat\[dq]] + .a\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + - cat + - dog +\f[R] +.fi +.SS Add new object to array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - dog: woof +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a + {\[dq]cat\[dq]: \[dq]meow\[dq]}\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- dog: woof +- cat: meow +\f[R] +.fi +.SS Relative append +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + a1: + b: + - cat + a2: + b: + - dog + a3: {} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a[].b += [\[dq]mouse\[dq]]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + a1: + b: + - cat + - mouse + a2: + b: + - dog + - mouse + a3: + b: + - mouse +\f[R] +.fi +.SS String concatenation +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: meow +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a += .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: catmeow +b: meow +\f[R] +.fi +.SS Number addition - float +.PP +If the lhs or rhs are floats then the expression will be calculated with +floats. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 3 +b: 4.9 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .a + .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 7.9 +b: 4.9 +\f[R] +.fi +.SS Number addition - int +.PP +If both the lhs and rhs are ints then the expression will be calculated +with ints. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 3 +b: 4 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .a + .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 7 +b: 4 +\f[R] +.fi +.SS Increment numbers +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 3 +b: 5 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] += 1\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 4 +b: 6 +\f[R] +.fi +.SS Date addition +.PP +You can add durations to dates. +Assumes RFC3339 date time format, see date-time +operators (https://mikefarah.gitbook.io/yq/operators/date-time-operators) +for more information. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 2021-01-01T00:00:00Z +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a += \[dq]3h10m\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 2021-01-01T03:10:00Z +\f[R] +.fi +.SS Date addition - custom format +.PP +You can add durations to dates. +See date-time +operators (https://mikefarah.gitbook.io/yq/operators/date-time-operators) +for more information. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 2:59AM GMT +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with_dtf(\[dq]Monday, 02-Jan-06 at 3:04PM MST\[dq], .a += \[dq]3h1m\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 6:00AM GMT +\f[R] +.fi +.SS Add to null +.PP +Adding to null simply returns the rhs +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]null + \[dq]cat\[dq]\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat +\f[R] +.fi +.SS Add maps to shallow merge +.PP +Adding objects together shallow merges them. +Use \f[C]*\f[R] to deeply merge. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + thing: + name: Astuff + value: x + a1: cool +b: + thing: + name: Bstuff + legs: 3 + b1: neat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a += .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + thing: + name: Bstuff + legs: 3 + a1: cool + b1: neat +b: + thing: + name: Bstuff + legs: 3 + b1: neat +\f[R] +.fi +.SS Custom types: that are really strings +.PP +When custom tags are encountered, yq will try to decode the underlying +type. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: !horse cat +b: !goat _meow +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a += .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !horse cat_meow +b: !goat _meow +\f[R] +.fi +.SS Custom types: that are really numbers +.PP +When custom tags are encountered, yq will try to decode the underlying +type. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: !horse 1.2 +b: !goat 2.3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a += .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !horse 3.5 +b: !goat 2.3 +\f[R] +.fi +.SH Alternative (Default value) +.PP +This operator is used to provide alternative (or default) values when a +particular expression is either null or false. +.SS LHS is defined +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: bridge +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a // \[dq]hello\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +bridge +\f[R] +.fi +.SS LHS is not defined +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +{} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a // \[dq]hello\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +hello +\f[R] +.fi +.SS LHS is null +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: \[ti] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a // \[dq]hello\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +hello +\f[R] +.fi +.SS LHS is false +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: false +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a // \[dq]hello\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +hello +\f[R] +.fi +.SS RHS is an expression +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: false +b: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a // .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat +\f[R] +.fi +.SS Update or create - entity exists +.PP +This initialises \f[C]a\f[R] if it\[cq]s not present +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 1 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.a // (.a = 0)) += 1\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 2 +\f[R] +.fi +.SS Update or create - entity does not exist +.PP +This initialises \f[C]a\f[R] if it\[cq]s not present +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +b: camel +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.a // (.a = 0)) += 1\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +b: camel +a: 1 +\f[R] +.fi +.SH Anchor and Alias Operators +.PP +Use the \f[C]alias\f[R] and \f[C]anchor\f[R] operators to read and write +yaml aliases and anchors. +The \f[C]explode\f[R] operator normalises a yaml file (dereference (or +expands) aliases and remove anchor names). +.PP +\f[C]yq\f[R] supports merge aliases (like \f[C]<<: *blah\f[R]) however +this is no longer in the standard yaml spec (1.2) and so \f[C]yq\f[R] +will automatically add the \f[C]!!merge\f[R] tag to these nodes as it is +effectively a custom tag. +.SS Merge one map +.PP +see https://yaml.org/type/merge.html +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- &CENTER + x: 1 + y: 2 +- &LEFT + x: 0 + y: 2 +- &BIG + r: 10 +- &SMALL + r: 1 +- !!merge <<: *CENTER + r: 10 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[4] | explode(.)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +x: 1 +y: 2 +r: 10 +\f[R] +.fi +.SS Merge multiple maps +.PP +see https://yaml.org/type/merge.html +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- &CENTER + x: 1 + y: 2 +- &LEFT + x: 0 + y: 2 +- &BIG + r: 10 +- &SMALL + r: 1 +- !!merge <<: + - *CENTER + - *BIG +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[4] | explode(.)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +r: 10 +x: 1 +y: 2 +\f[R] +.fi +.SS Override +.PP +see https://yaml.org/type/merge.html +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- &CENTER + x: 1 + y: 2 +- &LEFT + x: 0 + y: 2 +- &BIG + r: 10 +- &SMALL + r: 1 +- !!merge <<: + - *BIG + - *LEFT + - *SMALL + x: 1 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[4] | explode(.)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +r: 10 +x: 1 +y: 2 +\f[R] +.fi +.SS Get anchor +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: &billyBob cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | anchor\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +billyBob +\f[R] +.fi +.SS Set anchor +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a anchor = \[dq]foobar\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: &foobar cat +\f[R] +.fi +.SS Set anchor relatively using assign-update +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a anchor |= .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: &cat + b: cat +\f[R] +.fi +.SS Get alias +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +b: &billyBob meow +a: *billyBob +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | alias\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +billyBob +\f[R] +.fi +.SS Set alias +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +b: &meow purr +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a alias = \[dq]meow\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +b: &meow purr +a: *meow +\f[R] +.fi +.SS Set alias to blank does nothing +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +b: &meow purr +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a alias = \[dq]\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +b: &meow purr +a: cat +\f[R] +.fi +.SS Set alias relatively using assign-update +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +b: &meow purr +a: + f: meow +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a alias |= .f\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +b: &meow purr +a: *meow +\f[R] +.fi +.SS Explode alias and anchor +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +f: + a: &a cat + b: *a +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]explode(.f)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +f: + a: cat + b: cat +\f[R] +.fi +.SS Explode with no aliases or anchors +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: mike +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]explode(.a)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: mike +\f[R] +.fi +.SS Explode with alias keys +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +f: + a: &a cat + *a: b +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]explode(.f)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +f: + a: cat + cat: b +\f[R] +.fi +.SS Explode with merge anchors +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foo: &foo + a: foo_a + thing: foo_thing + c: foo_c +bar: &bar + b: bar_b + thing: bar_thing + c: bar_c +foobarList: + b: foobarList_b + !!merge <<: + - *foo + - *bar + c: foobarList_c +foobar: + c: foobar_c + !!merge <<: *foo + thing: foobar_thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]explode(.)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +foo: + a: foo_a + thing: foo_thing + c: foo_c +bar: + b: bar_b + thing: bar_thing + c: bar_c +foobarList: + b: bar_b + thing: foo_thing + c: foobarList_c + a: foo_a +foobar: + c: foo_c + a: foo_a + thing: foobar_thing +\f[R] +.fi +.SS Dereference and update a field +.PP +Use explode with multiply to dereference an object +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +item_value: &item_value + value: true +thingOne: + name: item_1 + !!merge <<: *item_value +thingTwo: + name: item_2 + !!merge <<: *item_value +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].thingOne |= explode(.) * {\[dq]value\[dq]: false}\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +item_value: &item_value + value: true +thingOne: + name: item_1 + value: false +thingTwo: + name: item_2 + !!merge <<: *item_value +\f[R] +.fi +.SH Array to Map +.PP +Use this operator to convert an array to..a map. +The indices are used as map keys, null values in the array are skipped +over. +.PP +Behind the scenes, this is implemented using reduce: +.IP +.nf +\f[C] +(.[] | select(. != null) ) as $i ireduce({}; .[$i | key] = $i) +\f[R] +.fi +.SS Simple example +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cool: + - null + - null + - hello +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].cool |= array_to_map\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cool: + 2: hello +\f[R] +.fi +.SH Assign (Update) +.PP +This operator is used to update node values. +It can be used in either the: +.SS plain form: \f[C]=\f[R] +.PP +Which will set the LHS node values equal to the RHS node values. +The RHS expression is run against the matching nodes in the pipeline. +.SS relative form: \f[C]|=\f[R] +.PP +This will do a similar thing to the plain form, but the RHS expression +is run with \f[I]each LHS node as context\f[R]. +This is useful for updating values based on old values, e.g.\ increment. +.SS Flags +.IP \[bu] 2 +\f[C]c\f[R] clobber custom tags +.SS Create yaml file +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq].a.b = \[dq]cat\[dq] | .x = \[dq]frog\[dq]\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: cat +x: frog +\f[R] +.fi +.SS Update node to be the child value +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: + g: foof +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a |= .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + g: foof +\f[R] +.fi +.SS Double elements in an array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 1 +- 2 +- 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] |= . * 2\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 2 +- 4 +- 6 +\f[R] +.fi +.SS Update node from another file +.PP +Note this will also work when the second file is a scalar +(string/number) +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: apples +\f[R] +.fi +.PP +And another sample another.yml file of: +.IP +.nf +\f[C] +b: bob +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq eval-all \[aq]select(fileIndex==0).a = select(fileIndex==1) | select(fileIndex==0)\[aq] sample.yml another.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: bob +\f[R] +.fi +.SS Update node to be the sibling value +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: child +b: sibling +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: sibling +b: sibling +\f[R] +.fi +.SS Updated multiple paths +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: fieldA +b: fieldB +c: fieldC +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.a, .c) = \[dq]potato\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: potato +b: fieldB +c: potato +\f[R] +.fi +.SS Update string value +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.b = \[dq]frog\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: frog +\f[R] +.fi +.SS Update string value via |= +.PP +Note there is no difference between \f[C]=\f[R] and \f[C]|=\f[R] when +the RHS is a scalar +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.b |= \[dq]frog\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: frog +\f[R] +.fi +.SS Update deeply selected results +.PP +Note that the LHS is wrapped in brackets! This is to ensure we don\[cq]t +first filter out the yaml and then update the snippet. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: apple + c: cactus +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.a[] | select(. == \[dq]apple\[dq])) = \[dq]frog\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: frog + c: cactus +\f[R] +.fi +.SS Update array values +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- candy +- apple +- sandy +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.[] | select(. == \[dq]*andy\[dq])) = \[dq]bogs\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- bogs +- apple +- bogs +\f[R] +.fi +.SS Update empty object +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +{} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.b |= \[dq]bogs\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: bogs +\f[R] +.fi +.SS Update node value that has an anchor +.PP +Anchor will remain +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: &cool cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = \[dq]dog\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: &cool dog +\f[R] +.fi +.SS Update empty object and array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +{} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.b.[0] |= \[dq]bogs\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: + - bogs +\f[R] +.fi +.SS Custom types are maintained by default +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: !cat meow +b: !dog woof +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !cat woof +b: !dog woof +\f[R] +.fi +.SS Custom types: clobber +.PP +Use the \f[C]c\f[R] option to clobber custom tags +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: !cat meow +b: !dog woof +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a =c .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !dog woof +b: !dog woof +\f[R] +.fi +.SH Boolean Operators +.PP +The \f[C]or\f[R] and \f[C]and\f[R] operators take two parameters and +return a boolean result. +.PP +\f[C]not\f[R] flips a boolean from true to false, or vice versa. +.PP +\f[C]any\f[R] will return \f[C]true\f[R] if there are any \f[C]true\f[R] +values in an array sequence, and \f[C]all\f[R] will return true if +\f[I]all\f[R] elements in an array are true. +.PP +\f[C]any_c(condition)\f[R] and \f[C]all_c(condition)\f[R] are like +\f[C]any\f[R] and \f[C]all\f[R] but they take a condition expression +that is used against each element to determine if it\[cq]s +\f[C]true\f[R]. +Note: in \f[C]jq\f[R] you can simply pass a condition to \f[C]any\f[R] +or \f[C]all\f[R] and it simply works - \f[C]yq\f[R] isn\[cq]t that +clever..yet +.PP +These are most commonly used with the \f[C]select\f[R] operator to +filter particular nodes. +.SS Related Operators +.IP \[bu] 2 +equals / not equals (\f[C]==\f[R], \f[C]!=\f[R]) operators +here (https://mikefarah.gitbook.io/yq/operators/equals) +.IP \[bu] 2 +comparison (\f[C]>=\f[R], \f[C]<\f[R] etc) operators +here (https://mikefarah.gitbook.io/yq/operators/compare) +.IP \[bu] 2 +select operator here (https://mikefarah.gitbook.io/yq/operators/select) +.SS \f[C]or\f[R] example +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]true or false\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS \[lq]yes\[rq] and \[lq]no\[rq] are strings +.PP +In the yaml 1.2 standard, support for yes/no as booleans was dropped - +they are now considered strings. +See `10.2.1.2. Boolean' in https://yaml.org/spec/1.2.2/ +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- yes +- no +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | tag\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +!!str +!!str +\f[R] +.fi +.SS \f[C]and\f[R] example +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]true and false\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +\f[R] +.fi +.SS Matching nodes with select, equals and or +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: bird + b: dog +- a: frog + b: bird +- a: cat + b: fly +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][.[] | select(.a == \[dq]cat\[dq] or .b == \[dq]dog\[dq])]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- a: bird + b: dog +- a: cat + b: fly +\f[R] +.fi +.SS \f[C]any\f[R] returns true if any boolean in a given array is true +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- false +- true +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]any\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS \f[C]any\f[R] returns false for an empty array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +[] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]any\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +\f[R] +.fi +.SS \f[C]any_c\f[R] returns true if any element in the array is true for the given condition. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - rad + - awesome +b: + - meh + - whatever +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] |= any_c(. == \[dq]awesome\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: true +b: false +\f[R] +.fi +.SS \f[C]all\f[R] returns true if all booleans in a given array are true +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- true +- true +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]all\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS \f[C]all\f[R] returns true for an empty array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +[] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]all\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS \f[C]all_c\f[R] returns true if all elements in the array are true for the given condition. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - rad + - awesome +b: + - meh + - 12 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] |= all_c(tag == \[dq]!!str\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: true +b: false +\f[R] +.fi +.SS Not true is false +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]true | not\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +\f[R] +.fi +.SS Not false is true +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]false | not\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS String values considered to be true +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]\[dq]cat\[dq] | not\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +\f[R] +.fi +.SS Empty string value considered to be true +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]\[dq]\[dq] | not\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +\f[R] +.fi +.SS Numbers are considered to be true +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]1 | not\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +\f[R] +.fi +.SS Zero is considered to be true +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]0 | not\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +\f[R] +.fi +.SS Null is considered to be false +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]\[ti] | not\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SH Collect into Array +.PP +This creates an array using the expression between the square brackets. +.SS Collect empty +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq][]\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +[] +\f[R] +.fi +.SS Collect single +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq][\[dq]cat\[dq]]\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- cat +\f[R] +.fi +.SS Collect many +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][.a, .b]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- cat +- dog +\f[R] +.fi +.SH Column +.PP +Returns the column of the matching node. +Starts from 1, 0 indicates there was no column data. +.PP +Column is the number of characters that precede that node on the line it +starts. +.SS Returns column of \f[I]value\f[R] node +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: bob +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b | column\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +4 +\f[R] +.fi +.SS Returns column of \f[I]key\f[R] node +.PP +Pipe through the key operator to get the column of the key +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: bob +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b | key | column\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +1 +\f[R] +.fi +.SS First column is 1 +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | key | column\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +1 +\f[R] +.fi +.SS No column data is 0 +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]{\[dq]a\[dq]: \[dq]new entry\[dq]} | column\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +0 +\f[R] +.fi +.SH Comment Operators +.PP +Use these comment operators to set or retrieve comments. +Note that line comments on maps/arrays are actually set on the +\f[I]key\f[R] node as opposed to the \f[I]value\f[R] (map/array). +See below for examples. +.PP +Like the \f[C]=\f[R] and \f[C]|=\f[R] assign operators, the same syntax +applies when updating comments: +.SS plain form: \f[C]=\f[R] +.PP +This will set the LHS nodes\[cq] comments equal to the expression on the +RHS. +The RHS is run against the matching nodes in the pipeline +.SS relative form: \f[C]|=\f[R] +.PP +This is similar to the plain form, but it evaluates the RHS with +\f[I]each matching LHS node as context\f[R]. +This is useful if you want to set the comments as a relative expression +of the node, for instance its value or path. +.SS Set line comment +.PP +Set the comment on the key node for more reliability (see below). +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a line_comment=\[dq]single\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat # single +\f[R] +.fi +.SS Set line comment of a maps/arrays +.PP +For maps and arrays, you need to set the line comment on the +\f[I]key\f[R] node. +This will also work for scalars. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: things +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.a | key) line_comment=\[dq]single\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: # single + b: things +\f[R] +.fi +.SS Use update assign to perform relative updates +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. line_comment |= .\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat # cat +b: dog # dog +\f[R] +.fi +.SS Where is the comment - map key example +.PP +The underlying yaml parser can assign comments in a document to +surprising nodes. +Use an expression like this to find where you comment is. +`p' indicates the path, `isKey' is if the node is a map key (as opposed +to a map value). +From this, you can see the `hello-world-comment' is actually on the +`hello' key +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +hello: # hello-world-comment + message: world +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][... | {\[dq]p\[dq]: path | join(\[dq].\[dq]), \[dq]isKey\[dq]: is_key, \[dq]hc\[dq]: headComment, \[dq]lc\[dq]: lineComment, \[dq]fc\[dq]: footComment}]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- p: \[dq]\[dq] + isKey: false + hc: \[dq]\[dq] + lc: \[dq]\[dq] + fc: \[dq]\[dq] +- p: hello + isKey: true + hc: \[dq]\[dq] + lc: hello-world-comment + fc: \[dq]\[dq] +- p: hello + isKey: false + hc: \[dq]\[dq] + lc: \[dq]\[dq] + fc: \[dq]\[dq] +- p: hello.message + isKey: true + hc: \[dq]\[dq] + lc: \[dq]\[dq] + fc: \[dq]\[dq] +- p: hello.message + isKey: false + hc: \[dq]\[dq] + lc: \[dq]\[dq] + fc: \[dq]\[dq] +\f[R] +.fi +.SS Retrieve comment - map key example +.PP +From the previous example, we know that the comment is on the `hello' +\f[I]key\f[R] as a lineComment +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +hello: # hello-world-comment + message: world +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].hello | key | line_comment\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +hello-world-comment +\f[R] +.fi +.SS Where is the comment - array example +.PP +The underlying yaml parser can assign comments in a document to +surprising nodes. +Use an expression like this to find where you comment is. +`p' indicates the path, `isKey' is if the node is a map key (as opposed +to a map value). +From this, you can see the `under-name-comment' is actually on the first +child +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +name: + # under-name-comment + - first-array-child +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][... | {\[dq]p\[dq]: path | join(\[dq].\[dq]), \[dq]isKey\[dq]: is_key, \[dq]hc\[dq]: headComment, \[dq]lc\[dq]: lineComment, \[dq]fc\[dq]: footComment}]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- p: \[dq]\[dq] + isKey: false + hc: \[dq]\[dq] + lc: \[dq]\[dq] + fc: \[dq]\[dq] +- p: name + isKey: true + hc: \[dq]\[dq] + lc: \[dq]\[dq] + fc: \[dq]\[dq] +- p: name + isKey: false + hc: \[dq]\[dq] + lc: \[dq]\[dq] + fc: \[dq]\[dq] +- p: name.0 + isKey: false + hc: under-name-comment + lc: \[dq]\[dq] + fc: \[dq]\[dq] +\f[R] +.fi +.SS Retrieve comment - array example +.PP +From the previous example, we know that the comment is on the first +child as a headComment +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +name: + # under-name-comment + - first-array-child +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].name[0] | headComment\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +under-name-comment +\f[R] +.fi +.SS Set head comment +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]. head_comment=\[dq]single\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +# single +a: cat +\f[R] +.fi +.SS Set head comment of a map entry +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +f: foo +a: + b: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.a | key) head_comment=\[dq]single\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +f: foo +# single +a: + b: cat +\f[R] +.fi +.SS Set foot comment, using an expression +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]. foot_comment=.a\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat +# cat +\f[R] +.fi +.SS Remove comment +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat # comment +b: dog # leave this +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a line_comment=\[dq]\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat +b: dog # leave this +\f[R] +.fi +.SS Remove (strip) all comments +.PP +Note the use of \f[C]...\f[R] to ensure key nodes are included. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# hi + +a: cat # comment +# great +b: # key comment +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]... comments=\[dq]\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat +b: +\f[R] +.fi +.SS Get line comment +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# welcome! + +a: cat # meow +# have a great day +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | line_comment\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +meow +\f[R] +.fi +.SS Get head comment +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# welcome! + +a: cat # meow + +# have a great day +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]. | head_comment\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +welcome! +\f[R] +.fi +.SS Head comment with document split +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# welcome! +--- +# bob +a: cat # meow + +# have a great day +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]head_comment\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +welcome! +bob +\f[R] +.fi +.SS Get foot comment +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# welcome! + +a: cat # meow + +# have a great day +# no really +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]. | foot_comment\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +have a great day +no really +\f[R] +.fi +.SH Compare Operators +.PP +Comparison operators (\f[C]>\f[R], \f[C]>=\f[R], \f[C]<\f[R], +\f[C]<=\f[R]) can be used for comparing scalar values of the same time. +.PP +The following types are currently supported: +.IP \[bu] 2 +numbers +.IP \[bu] 2 +strings +.IP \[bu] 2 +datetimes +.SS Related Operators +.IP \[bu] 2 +equals / not equals (\f[C]==\f[R], \f[C]!=\f[R]) operators +here (https://mikefarah.gitbook.io/yq/operators/equals) +.IP \[bu] 2 +boolean operators (\f[C]and\f[R], \f[C]or\f[R], \f[C]any\f[R] etc) +here (https://mikefarah.gitbook.io/yq/operators/boolean-operators) +.IP \[bu] 2 +select operator here (https://mikefarah.gitbook.io/yq/operators/select) +.SS Compare numbers (>) +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 5 +b: 4 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a > .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS Compare equal numbers (>=) +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 5 +b: 5 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a >= .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS Compare strings +.PP +Compares strings by their bytecode. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: zoo +b: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a > .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS Compare date times +.PP +You can compare date times. +Assumes RFC3339 date time format, see date-time +operators (https://mikefarah.gitbook.io/yq/operators/date-time-operators) +for more information. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 2021-01-01T03:10:00Z +b: 2020-01-01T03:10:00Z +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a > .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS Both sides are null: > is false +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq].a > .b\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +\f[R] +.fi +.SS Both sides are null: >= is true +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq].a >= .b\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SH Contains +.PP +This returns \f[C]true\f[R] if the context contains the passed in +parameter, and false otherwise. +For arrays, this will return true if the passed in array is contained +within the array. +For strings, it will return true if the string is a substring. +.PP +{% hint style=\[lq]warning\[rq] %} +.PP +\f[I]Note\f[R] that, just like jq, when checking if an array of strings +\f[C]contains\f[R] another, this will use \f[C]contains\f[R] and +\f[I]not\f[R] equals to check each string. +This means an expression like \f[C]contains([\[dq]cat\[dq]])\f[R] will +return true for an array \f[C][\[dq]cats\[dq]]\f[R]. +.PP +See the \[lq]Array has a subset array\[rq] example below on how to check +for a subset. +.PP +{% endhint %} +.SS Array contains array +.PP +Array is equal or subset of +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- foobar +- foobaz +- blarp +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]contains([\[dq]baz\[dq], \[dq]bar\[dq]])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS Array has a subset array +.PP +Subtract the superset array from the subset, if there\[cq]s anything +left, it\[cq]s not a subset +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- foobar +- foobaz +- blarp +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][\[dq]baz\[dq], \[dq]bar\[dq]] - . | length == 0\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +\f[R] +.fi +.SS Object included in array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +\[dq]foo\[dq]: 12 +\[dq]bar\[dq]: + - 1 + - 2 + - \[dq]barp\[dq]: 12 + \[dq]blip\[dq]: 13 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]contains({\[dq]bar\[dq]: [{\[dq]barp\[dq]: 12}]})\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS Object not included in array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +\[dq]foo\[dq]: 12 +\[dq]bar\[dq]: + - 1 + - 2 + - \[dq]barp\[dq]: 12 + \[dq]blip\[dq]: 13 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]contains({\[dq]foo\[dq]: 12, \[dq]bar\[dq]: [{\[dq]barp\[dq]: 15}]})\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +\f[R] +.fi +.SS String contains substring +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foobar +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]contains(\[dq]bar\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS String equals string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +meow +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]contains(\[dq]meow\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SH Create, Collect into Object +.PP +This is used to construct objects (or maps). +This can be used against existing yaml, or to create fresh yaml +documents. +.SS Collect empty object +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]{}\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +{} +\f[R] +.fi +.SS Wrap (prefix) existing object +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +name: Mike +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]{\[dq]wrap\[dq]: .}\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +wrap: + name: Mike +\f[R] +.fi +.SS Using splat to create multiple objects +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +name: Mike +pets: + - cat + - dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]{.name: .pets.[]}\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Mike: cat +Mike: dog +\f[R] +.fi +.SS Working with multiple documents +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +name: Mike +pets: + - cat + - dog +--- +name: Rosey +pets: + - monkey + - sheep +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]{.name: .pets.[]}\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Mike: cat +Mike: dog +--- +Rosey: monkey +Rosey: sheep +\f[R] +.fi +.SS Creating yaml from scratch +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]{\[dq]wrap\[dq]: \[dq]frog\[dq]}\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +wrap: frog +\f[R] +.fi +.SS Creating yaml from scratch with multiple objects +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq](.a.b = \[dq]foo\[dq]) | (.d.e = \[dq]bar\[dq])\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: foo +d: + e: bar +\f[R] +.fi +.SH Date Time +.PP +Various operators for parsing and manipulating dates. +.SS Date time formattings +.PP +This uses Golang\[cq]s built in time library for parsing and formatting +date times. +.PP +When not specified, the RFC3339 standard is assumed +\f[C]2006-01-02T15:04:05Z07:00\f[R] for parsing. +.PP +To specify a custom parsing format, use the \f[C]with_dtf\f[R] operator. +The first parameter sets the datetime parsing format for the expression +in the second parameter. +The expression can be any valid \f[C]yq\f[R] expression tree. +.IP +.nf +\f[C] +yq \[aq]with_dtf(\[dq]myformat\[dq]; .a + \[dq]3h\[dq] | tz(\[dq]Australia/Melbourne\[dq]))\[aq] +\f[R] +.fi +.PP +See the library docs (https://pkg.go.dev/time#pkg-constants) for +examples of formatting options. +.SS Timezones +.PP +This uses Golang\[cq]s built in LoadLocation function to parse timezones +strings. +See the library docs (https://pkg.go.dev/time#LoadLocation) for more +details. +.SS Durations +.PP +Durations are parsed using Golang\[cq]s built in +ParseDuration (https://pkg.go.dev/time#ParseDuration) function. +.PP +You can add durations to time using the \f[C]+\f[R] operator. +.SS Format: from standard RFC3339 format +.PP +Providing a single parameter assumes a standard RFC3339 datetime format. +If the target format is not a valid yaml datetime format, the result +will be a string tagged node. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 2001-12-15T02:59:43.1Z +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a |= format_datetime(\[dq]Monday, 02-Jan-06 at 3:04PM\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 2:59AM +\f[R] +.fi +.SS Format: from custom date time +.PP +Use with_dtf to set a custom datetime format for parsing. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 2:59AM +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a |= with_dtf(\[dq]Monday, 02-Jan-06 at 3:04PM\[dq]; format_datetime(\[dq]2006-01-02\[dq]))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 2001-12-15 +\f[R] +.fi +.SS Format: get the day of the week +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 2001-12-15 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | format_datetime(\[dq]Monday\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Saturday +\f[R] +.fi +.SS Now +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cool +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].updated = now\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cool +updated: 2021-05-19T01:02:03Z +\f[R] +.fi +.SS From Unix +.PP +Converts from unix time. +Note, you don\[cq]t have to pipe through the tz operator :) +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]1675301929 | from_unix | tz(\[dq]UTC\[dq])\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +2023-02-02T01:38:49Z +\f[R] +.fi +.SS To Unix +.PP +Converts to unix time +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]now | to_unix\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +1621386123 +\f[R] +.fi +.SS Timezone: from standard RFC3339 format +.PP +Returns a new datetime in the specified timezone. +Specify standard IANA Time Zone format or `utc', `local'. +When given a single parameter, this assumes the datetime is in RFC3339 +format. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cool +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].updated = (now | tz(\[dq]Australia/Sydney\[dq]))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cool +updated: 2021-05-19T11:02:03+10:00 +\f[R] +.fi +.SS Timezone: with custom format +.PP +Specify standard IANA Time Zone format or `utc', `local' +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 2:59AM GMT +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a |= with_dtf(\[dq]Monday, 02-Jan-06 at 3:04PM MST\[dq]; tz(\[dq]Australia/Sydney\[dq]))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 1:59PM AEDT +\f[R] +.fi +.SS Add and tz custom format +.PP +Specify standard IANA Time Zone format or `utc', `local' +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 2:59AM GMT +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a |= with_dtf(\[dq]Monday, 02-Jan-06 at 3:04PM MST\[dq]; tz(\[dq]Australia/Sydney\[dq]))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 1:59PM AEDT +\f[R] +.fi +.SS Date addition +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 2021-01-01T00:00:00Z +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a += \[dq]3h10m\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 2021-01-01T03:10:00Z +\f[R] +.fi +.SS Date subtraction +.PP +You can subtract durations from dates. +Assumes RFC3339 date time format, see date-time +operators (https://mikefarah.gitbook.io/yq/operators/datetime#date-time-formattings) +for more information. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 2021-01-01T03:10:00Z +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a -= \[dq]3h10m\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 2021-01-01T00:00:00Z +\f[R] +.fi +.SS Date addition - custom format +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 2:59AM GMT +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with_dtf(\[dq]Monday, 02-Jan-06 at 3:04PM MST\[dq]; .a += \[dq]3h1m\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 6:00AM GMT +\f[R] +.fi +.SS Date script with custom format +.PP +You can embed full expressions in with_dtf if needed. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 2:59AM GMT +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with_dtf(\[dq]Monday, 02-Jan-06 at 3:04PM MST\[dq]; .a = (.a + \[dq]3h1m\[dq] | tz(\[dq]Australia/Perth\[dq])))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 2:00PM AWST +\f[R] +.fi +.SH Delete +.PP +Deletes matching entries in maps or arrays. +.SS Delete entry in map +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]del(.b)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.SS Delete nested entry in map +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + a1: fred + a2: frood +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]del(.a.a1)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + a2: frood +\f[R] +.fi +.SS Delete entry in array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 1 +- 2 +- 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]del(.[1])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 1 +- 3 +\f[R] +.fi +.SS Delete nested entry in array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: cat + b: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]del(.[0].a)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- b: dog +\f[R] +.fi +.SS Delete no matches +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]del(.c)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat +b: dog +\f[R] +.fi +.SS Delete matching entries +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: dog +c: bat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]del( .[] | select(. == \[dq]*at\[dq]) )\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +b: dog +\f[R] +.fi +.SS Recursively delete matching keys +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + name: frog + b: + name: blog + age: 12 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]del(.. | select(has(\[dq]name\[dq])).name)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: + age: 12 +\f[R] +.fi +.SH Divide +.PP +Divide behaves differently according to the type of the LHS: * strings: +split by the divider * number: arithmetic division +.SS String split +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat_meow +b: _ +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].c = .a / .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat_meow +b: _ +c: + - cat + - meow +\f[R] +.fi +.SS Number division +.PP +The result during division is calculated as a float +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 12 +b: 2.5 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .a / .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 4.8 +b: 2.5 +\f[R] +.fi +.SS Number division by zero +.PP +Dividing by zero results in +Inf or -Inf +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 1 +b: -1 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .a / 0 | .b = .b / 0\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !!float +Inf +b: !!float -Inf +\f[R] +.fi +.SH Document Index +.PP +Use the \f[C]documentIndex\f[R] operator (or the \f[C]di\f[R] shorthand) +to select nodes of a particular document. +.SS Retrieve a document index +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +--- +a: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | document_index\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +0 +--- +1 +\f[R] +.fi +.SS Retrieve a document index, shorthand +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +--- +a: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | di\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +0 +--- +1 +\f[R] +.fi +.SS Filter by document index +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +--- +a: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]select(document_index == 1)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: frog +\f[R] +.fi +.SS Filter by document index shorthand +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +--- +a: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]select(di == 1)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: frog +\f[R] +.fi +.SS Print Document Index with matches +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +--- +a: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | ({\[dq]match\[dq]: ., \[dq]doc\[dq]: document_index})\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +match: cat +doc: 0 +--- +match: frog +doc: 1 +\f[R] +.fi +.SH Encoder / Decoder +.PP +Encode operators will take the piped in object structure and encode it +as a string in the desired format. +The decode operators do the opposite, they take a formatted string and +decode it into the relevant object structure. +.PP +Note that you can optionally pass an indent value to the encode +functions (see below). +.PP +These operators are useful to process yaml documents that have +stringified embedded yaml/json/props in them. +.PP +.TS +tab(@); +l l l. +T{ +Format +T}@T{ +Decode (from string) +T}@T{ +Encode (to string) +T} +_ +T{ +Yaml +T}@T{ +from_yaml/\[at]yamld +T}@T{ +to_yaml(i)/\[at]yaml +T} +T{ +JSON +T}@T{ +from_json/\[at]jsond +T}@T{ +to_json(i)/\[at]json +T} +T{ +Properties +T}@T{ +from_props/\[at]propsd +T}@T{ +to_props/\[at]props +T} +T{ +CSV +T}@T{ +from_csv/\[at]csvd +T}@T{ +to_csv/\[at]csv +T} +T{ +TSV +T}@T{ +from_tsv/\[at]tsvd +T}@T{ +to_tsv/\[at]tsv +T} +T{ +XML +T}@T{ +from_xml/\[at]xmld +T}@T{ +to_xml(i)/\[at]xml +T} +T{ +Base64 +T}@T{ +\[at]base64d +T}@T{ +\[at]base64 +T} +T{ +URI +T}@T{ +\[at]urid +T}@T{ +\[at]uri +T} +T{ +Shell +T}@T{ +T}@T{ +\[at]sh +T} +.TE +.PP +See CSV and TSV +documentation (https://mikefarah.gitbook.io/yq/usage/csv-tsv) for +accepted formats. +.PP +XML uses the \f[C]--xml-attribute-prefix\f[R] and +\f[C]xml-content-name\f[R] flags to identify attributes and content +fields. +.PP +Base64 assumes rfc4648 (https://rfc-editor.org/rfc/rfc4648.html) +encoding. +Encoding and decoding both assume that the content is a utf-8 string and +not binary content. +.SS Encode value as json string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + cool: thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b = (.a | to_json)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + cool: thing +b: | + { + \[dq]cool\[dq]: \[dq]thing\[dq] + } +\f[R] +.fi +.SS Encode value as json string, on one line +.PP +Pass in a 0 indent to print json on a single line. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + cool: thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b = (.a | to_json(0))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + cool: thing +b: \[aq]{\[dq]cool\[dq]:\[dq]thing\[dq]}\[aq] +\f[R] +.fi +.SS Encode value as json string, on one line shorthand +.PP +Pass in a 0 indent to print json on a single line. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + cool: thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b = (.a | \[at]json)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + cool: thing +b: \[aq]{\[dq]cool\[dq]:\[dq]thing\[dq]}\[aq] +\f[R] +.fi +.SS Decode a json encoded string +.PP +Keep in mind JSON is a subset of YAML. +If you want idiomatic yaml, pipe through the style operator to clear out +the JSON styling. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: \[aq]{\[dq]cool\[dq]:\[dq]thing\[dq]}\[aq] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | from_json | ... style=\[dq]\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cool: thing +\f[R] +.fi +.SS Encode value as props string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + cool: thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b = (.a | \[at]props)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + cool: thing +b: | + cool = thing +\f[R] +.fi +.SS Decode props encoded string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: |- + cats=great + dogs=cool as well +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a |= \[at]propsd\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + cats: great + dogs: cool as well +\f[R] +.fi +.SS Decode csv encoded string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: |- + cats,dogs + great,cool as well +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a |= \[at]csvd\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + - cats: great + dogs: cool as well +\f[R] +.fi +.SS Decode tsv encoded string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: |- + cats dogs + great cool as well +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a |= \[at]tsvd\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + - cats: great + dogs: cool as well +\f[R] +.fi +.SS Encode value as yaml string +.PP +Indent defaults to 2 +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + cool: + bob: dylan +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b = (.a | to_yaml)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + cool: + bob: dylan +b: | + cool: + bob: dylan +\f[R] +.fi +.SS Encode value as yaml string, with custom indentation +.PP +You can specify the indentation level as the first parameter. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + cool: + bob: dylan +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b = (.a | to_yaml(8))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + cool: + bob: dylan +b: | + cool: + bob: dylan +\f[R] +.fi +.SS Decode a yaml encoded string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: \[aq]foo: bar\[aq] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b = (.a | from_yaml)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: \[aq]foo: bar\[aq] +b: + foo: bar +\f[R] +.fi +.SS Update a multiline encoded yaml string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: | + foo: bar + baz: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a |= (from_yaml | .foo = \[dq]cat\[dq] | to_yaml)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: | + foo: cat + baz: dog +\f[R] +.fi +.SS Update a single line encoded yaml string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: \[aq]foo: bar\[aq] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a |= (from_yaml | .foo = \[dq]cat\[dq] | to_yaml)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: \[aq]foo: cat\[aq] +\f[R] +.fi +.SS Encode array of scalars as csv string +.PP +Scalars are strings, numbers and booleans. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- thing1,thing2 +- true +- 3.40 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]\[at]csv\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat,\[dq]thing1,thing2\[dq],true,3.40 +\f[R] +.fi +.SS Encode array of arrays as csv string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- - cat + - thing1,thing2 + - true + - 3.40 +- - dog + - thing3 + - false + - 12 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]\[at]csv\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat,\[dq]thing1,thing2\[dq],true,3.40 +dog,thing3,false,12 +\f[R] +.fi +.SS Encode array of arrays as tsv string +.PP +Scalars are strings, numbers and booleans. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- - cat + - thing1,thing2 + - true + - 3.40 +- - dog + - thing3 + - false + - 12 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]\[at]tsv\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat thing1,thing2 true 3.40 +dog thing3 false 12 +\f[R] +.fi +.SS Encode value as xml string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + cool: + foo: bar + +\[at]id: hi +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | to_xml\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<cool id=\[dq]hi\[dq]> + <foo>bar</foo> +</cool> +\f[R] +.fi +.SS Encode value as xml string on a single line +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + cool: + foo: bar + +\[at]id: hi +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | \[at]xml\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<cool id=\[dq]hi\[dq]><foo>bar</foo></cool> +\f[R] +.fi +.SS Encode value as xml string with custom indentation +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + cool: + foo: bar + +\[at]id: hi +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]{\[dq]cat\[dq]: .a | to_xml(1)}\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat: | + <cool id=\[dq]hi\[dq]> + <foo>bar</foo> + </cool> +\f[R] +.fi +.SS Decode a xml encoded string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: <foo>bar</foo> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b = (.a | from_xml)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: <foo>bar</foo> +b: + foo: bar +\f[R] +.fi +.SS Encode a string to base64 +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +coolData: a special string +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].coolData | \[at]base64\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +YSBzcGVjaWFsIHN0cmluZw== +\f[R] +.fi +.SS Encode a yaml document to base64 +.PP +Pipe through \[at]yaml first to convert to a string, then use +\[at]base64 to encode it. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]\[at]yaml | \[at]base64\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +YTogYXBwbGUK +\f[R] +.fi +.SS Encode a string to uri +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +coolData: this has & special () characters * +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].coolData | \[at]uri\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +this+has+%26+special+%28%29+characters+%2A +\f[R] +.fi +.SS Decode a URI to a string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +this+has+%26+special+%28%29+characters+%2A +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]\[at]urid\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +this has & special () characters * +\f[R] +.fi +.SS Encode a string to sh +.PP +Sh/Bash friendly string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +coolData: strings with spaces and a \[aq]quote\[aq] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].coolData | \[at]sh\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +strings\[aq] with spaces and a \[aq]\[rs]\[aq]quote\[rs]\[aq] +\f[R] +.fi +.SS Decode a base64 encoded string +.PP +Decoded data is assumed to be a string. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +coolData: V29ya3Mgd2l0aCBVVEYtMTYg8J+Yig== +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].coolData | \[at]base64d\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Works with UTF-16 \[u1F60A] +\f[R] +.fi +.SS Decode a base64 encoded yaml document +.PP +Pipe through \f[C]from_yaml\f[R] to parse the decoded base64 string as a +yaml document. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +coolData: YTogYXBwbGUK +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].coolData |= (\[at]base64d | from_yaml)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +coolData: + a: apple +\f[R] +.fi +.SH Entries +.PP +Similar to the same named functions in \f[C]jq\f[R] these functions +convert to/from an object and an array of key-value pairs. +This is most useful for performing operations on keys of maps. +.SS to_entries Map +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 1 +b: 2 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]to_entries\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- key: a + value: 1 +- key: b + value: 2 +\f[R] +.fi +.SS to_entries Array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a +- b +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]to_entries\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- key: 0 + value: a +- key: 1 + value: b +\f[R] +.fi +.SS to_entries null +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +null +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]to_entries\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +\f[R] +.fi +.SS from_entries map +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 1 +b: 2 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]to_entries | from_entries\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 1 +b: 2 +\f[R] +.fi +.SS from_entries with numeric key indices +.PP +from_entries always creates a map, even for numeric keys +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a +- b +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]to_entries | from_entries\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +0: a +1: b +\f[R] +.fi +.SS Use with_entries to update keys +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 1 +b: 2 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with_entries(.key |= \[dq]KEY_\[dq] + .)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +KEY_a: 1 +KEY_b: 2 +\f[R] +.fi +.SS Custom sort map keys +.PP +Use to_entries to convert to an array of key/value pairs, sort the array +using sort/sort_by/etc, and convert it back. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 1 +c: 3 +b: 2 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]to_entries | sort_by(.key) | reverse | from_entries\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +c: 3 +b: 2 +a: 1 +\f[R] +.fi +.SS Use with_entries to filter the map +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: bird +c: + d: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with_entries(select(.value | has(\[dq]b\[dq])))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: bird +\f[R] +.fi +.SH Env Variable Operators +.PP +These operators are used to handle environment variables usage in +expressions and documents. +While environment variables can, of course, be passed in via your CLI +with string interpolation, this often comes with complex quote escaping +and can be tricky to write and read. +.PP +There are three operators: +.IP \[bu] 2 +\f[C]env\f[R] which takes a single environment variable name and parse +the variable as a yaml node (be it a map, array, string, number of +boolean) +.IP \[bu] 2 +\f[C]strenv\f[R] which also takes a single environment variable name, +and always parses the variable as a string. +.IP \[bu] 2 +\f[C]envsubst\f[R] which you pipe strings into and it interpolates +environment variables in strings using +envsubst (https://github.com/a8m/envsubst). +.SS EnvSubst Options +.PP +You can optionally pass envsubst any of the following options: +.IP \[bu] 2 +nu: NoUnset, this will fail if there are any referenced variables that +are not set +.IP \[bu] 2 +ne: NoEmpty, this will fail if there are any referenced variables that +are empty +.IP \[bu] 2 +ff: FailFast, this will abort on the first failure (rather than collect +all the errors) +.PP +E.g: \f[C]envsubst(ne, ff)\f[R] will fail on the first empty variable. +.PP +See Imposing +Restrictions (https://github.com/a8m/envsubst#imposing-restrictions) in +the \f[C]envsubst\f[R] documentation for more information, and below for +examples. +.SS Tip +.PP +To replace environment variables across all values in a document, +\f[C]envsubst\f[R] can be used with the recursive descent operator as +follows: +.IP +.nf +\f[C] +yq \[aq](.. | select(tag == \[dq]!!str\[dq])) |= envsubst\[aq] file.yaml +\f[R] +.fi +.SS Read string environment variable +.PP +Running +.IP +.nf +\f[C] +myenv=\[dq]cat meow\[dq] yq --null-input \[aq].a = env(myenv)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat meow +\f[R] +.fi +.SS Read boolean environment variable +.PP +Running +.IP +.nf +\f[C] +myenv=\[dq]true\[dq] yq --null-input \[aq].a = env(myenv)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: true +\f[R] +.fi +.SS Read numeric environment variable +.PP +Running +.IP +.nf +\f[C] +myenv=\[dq]12\[dq] yq --null-input \[aq].a = env(myenv)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 12 +\f[R] +.fi +.SS Read yaml environment variable +.PP +Running +.IP +.nf +\f[C] +myenv=\[dq]{b: fish}\[dq] yq --null-input \[aq].a = env(myenv)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: {b: fish} +\f[R] +.fi +.SS Read boolean environment variable as a string +.PP +Running +.IP +.nf +\f[C] +myenv=\[dq]true\[dq] yq --null-input \[aq].a = strenv(myenv)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: \[dq]true\[dq] +\f[R] +.fi +.SS Read numeric environment variable as a string +.PP +Running +.IP +.nf +\f[C] +myenv=\[dq]12\[dq] yq --null-input \[aq].a = strenv(myenv)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: \[dq]12\[dq] +\f[R] +.fi +.SS Dynamically update a path from an environment variable +.PP +The env variable can be any valid yq expression. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: + - name: dog + - name: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +pathEnv=\[dq].a.b[0].name\[dq] valueEnv=\[dq]moo\[dq] yq \[aq]eval(strenv(pathEnv)) = strenv(valueEnv)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: + - name: moo + - name: cat +\f[R] +.fi +.SS Dynamic key lookup with environment variable +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cat: meow +dog: woof +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +myenv=\[dq]cat\[dq] yq \[aq].[env(myenv)]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +meow +\f[R] +.fi +.SS Replace strings with envsubst +.PP +Running +.IP +.nf +\f[C] +myenv=\[dq]cat\[dq] yq --null-input \[aq]\[dq]the ${myenv} meows\[dq] | envsubst\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +the cat meows +\f[R] +.fi +.SS Replace strings with envsubst, missing variables +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]\[dq]the ${myenvnonexisting} meows\[dq] | envsubst\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +the meows +\f[R] +.fi +.SS Replace strings with envsubst(nu), missing variables +.PP +(nu) not unset, will fail if there are unset (missing) variables +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]\[dq]the ${myenvnonexisting} meows\[dq] | envsubst(nu)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Error: variable ${myenvnonexisting} not set +\f[R] +.fi +.SS Replace strings with envsubst(ne), missing variables +.PP +(ne) not empty, only validates set variables +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]\[dq]the ${myenvnonexisting} meows\[dq] | envsubst(ne)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +the meows +\f[R] +.fi +.SS Replace strings with envsubst(ne), empty variable +.PP +(ne) not empty, will fail if a references variable is empty +.PP +Running +.IP +.nf +\f[C] +myenv=\[dq]\[dq] yq --null-input \[aq]\[dq]the ${myenv} meows\[dq] | envsubst(ne)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Error: variable ${myenv} set but empty +\f[R] +.fi +.SS Replace strings with envsubst, missing variables with defaults +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]\[dq]the ${myenvnonexisting-dog} meows\[dq] | envsubst\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +the dog meows +\f[R] +.fi +.SS Replace strings with envsubst(nu), missing variables with defaults +.PP +Having a default specified skips over the missing variable. +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]\[dq]the ${myenvnonexisting-dog} meows\[dq] | envsubst(nu)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +the dog meows +\f[R] +.fi +.SS Replace strings with envsubst(ne), missing variables with defaults +.PP +Fails, because the variable is explicitly set to blank. +.PP +Running +.IP +.nf +\f[C] +myEmptyEnv=\[dq]\[dq] yq --null-input \[aq]\[dq]the ${myEmptyEnv-dog} meows\[dq] | envsubst(ne)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Error: variable ${myEmptyEnv} set but empty +\f[R] +.fi +.SS Replace string environment variable in document +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +v: ${myenv} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +myenv=\[dq]cat meow\[dq] yq \[aq].v |= envsubst\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +v: cat meow +\f[R] +.fi +.SS (Default) Return all envsubst errors +.PP +By default, all errors are returned at once. +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]\[dq]the ${notThere} ${alsoNotThere}\[dq] | envsubst(nu)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Error: variable ${notThere} not set +variable ${alsoNotThere} not set +\f[R] +.fi +.SS Fail fast, return the first envsubst error (and abort) +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]\[dq]the ${notThere} ${alsoNotThere}\[dq] | envsubst(nu,ff)\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Error: variable ${notThere} not set +\f[R] +.fi +.SH Equals / Not Equals +.PP +This is a boolean operator that will return \f[C]true\f[R] if the LHS is +equal to the RHS and \f[C]false\f[R] otherwise. +.IP +.nf +\f[C] +\&.a == .b +\f[R] +.fi +.PP +It is most often used with the select operator to find particular nodes: +.IP +.nf +\f[C] +select(.a == .b) +\f[R] +.fi +.PP +The not equals \f[C]!=\f[R] operator returns \f[C]false\f[R] if the LHS +is equal to the RHS. +.SS Related Operators +.IP \[bu] 2 +comparison (\f[C]>=\f[R], \f[C]<\f[R] etc) operators +here (https://mikefarah.gitbook.io/yq/operators/compare) +.IP \[bu] 2 +boolean operators (\f[C]and\f[R], \f[C]or\f[R], \f[C]any\f[R] etc) +here (https://mikefarah.gitbook.io/yq/operators/boolean-operators) +.IP \[bu] 2 +select operator here (https://mikefarah.gitbook.io/yq/operators/select) +.SS Match string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- goat +- dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | (. == \[dq]*at\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +true +false +\f[R] +.fi +.SS Don\[cq]t match string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- goat +- dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | (. != \[dq]*at\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +false +true +\f[R] +.fi +.SS Match number +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 3 +- 4 +- 5 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | (. == 4)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +true +false +\f[R] +.fi +.SS Don\[cq]t match number +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 3 +- 4 +- 5 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | (. != 4)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +false +true +\f[R] +.fi +.SS Match nulls +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]null == \[ti]\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +\f[R] +.fi +.SS Non existent key doesn\[cq]t equal a value +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]select(.b != \[dq]thing\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: frog +\f[R] +.fi +.SS Two non existent keys are equal +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]select(.b == .c)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: frog +\f[R] +.fi +.SH Error +.PP +Use this operation to short-circuit expressions. +Useful for validation. +.SS Validate a particular value +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: hello +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]select(.a == \[dq]howdy\[dq]) or error(\[dq].a [\[dq] + .a + \[dq]] is not howdy!\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Error: .a [hello] is not howdy! +\f[R] +.fi +.SS Validate the environment variable is a number - invalid +.PP +Running +.IP +.nf +\f[C] +numberOfCats=\[dq]please\[dq] yq --null-input \[aq]env(numberOfCats) | select(tag == \[dq]!!int\[dq]) or error(\[dq]numberOfCats is not a number :(\[dq])\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Error: numberOfCats is not a number :( +\f[R] +.fi +.SS Validate the environment variable is a number - valid +.PP +\f[C]with\f[R] can be a convenient way of encapsulating validation. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +name: Bob +favouriteAnimal: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +numberOfCats=\[dq]3\[dq] yq \[aq] + with(env(numberOfCats); select(tag == \[dq]!!int\[dq]) or error(\[dq]numberOfCats is not a number :(\[dq])) | + .numPets = env(numberOfCats) +\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +name: Bob +favouriteAnimal: cat +numPets: 3 +\f[R] +.fi +.SH Eval +.PP +Use \f[C]eval\f[R] to dynamically process an expression - for instance +from an environment variable. +.PP +\f[C]eval\f[R] takes a single argument, and evaluates that as a +\f[C]yq\f[R] expression. +Any valid expression can be used, be it a path +\f[C].a.b.c | select(. == \[dq]cat\[dq])\f[R], or an update +\f[C].a.b.c = \[dq]gogo\[dq]\f[R]. +.PP +Tip: This can be a useful way to parameterise complex scripts. +.SS Dynamically evaluate a path +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +pathExp: .a.b[] | select(.name == \[dq]cat\[dq]) +a: + b: + - name: dog + - name: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]eval(.pathExp)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +name: cat +\f[R] +.fi +.SS Dynamically update a path from an environment variable +.PP +The env variable can be any valid yq expression. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: + - name: dog + - name: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +pathEnv=\[dq].a.b[0].name\[dq] valueEnv=\[dq]moo\[dq] yq \[aq]eval(strenv(pathEnv)) = strenv(valueEnv)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: + - name: moo + - name: cat +\f[R] +.fi +.SH File Operators +.PP +File operators are most often used with merge when needing to merge +specific files together. +Note that when doing this, you will need to use \f[C]eval-all\f[R] to +ensure all yaml documents are loaded into memory before performing the +merge (as opposed to \f[C]eval\f[R] which runs the expression once per +document). +.PP +Note that the \f[C]fileIndex\f[R] operator has a short alias of +\f[C]fi\f[R]. +.SS Merging files +.PP +Note the use of eval-all to ensure all documents are loaded into memory. +.IP +.nf +\f[C] +yq eval-all \[aq]select(fi == 0) * select(filename == \[dq]file2.yaml\[dq])\[aq] file1.yaml file2.yaml +\f[R] +.fi +.SS Get filename +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]filename\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +sample.yml +\f[R] +.fi +.SS Get file index +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]file_index\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +0 +\f[R] +.fi +.SS Get file indices of multiple documents +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +And another sample another.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq eval-all \[aq]file_index\[aq] sample.yml another.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +0 +1 +\f[R] +.fi +.SS Get file index alias +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]fi\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +0 +\f[R] +.fi +.SH Filter +.PP +Filters an array (or map values) by the expression given. +Equivalent to doing \f[C]map(select(exp))\f[R]. +.SS Filter array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 1 +- 2 +- 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]filter(. < 3)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 1 +- 2 +\f[R] +.fi +.SS Filter map values +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +c: + things: cool + frog: yes +d: + things: hot + frog: false +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]filter(.things == \[dq]cool\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- things: cool + frog: yes +\f[R] +.fi +.SH Flatten +.PP +This recursively flattens arrays. +.SS Flatten +.PP +Recursively flattens all arrays +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 1 +- - 2 +- - - 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]flatten\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 1 +- 2 +- 3 +\f[R] +.fi +.SS Flatten with depth of one +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 1 +- - 2 +- - - 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]flatten(1)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 1 +- 2 +- - 3 +\f[R] +.fi +.SS Flatten empty array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- [] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]flatten\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +[] +\f[R] +.fi +.SS Flatten array of objects +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- foo: bar +- - foo: baz +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]flatten\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- foo: bar +- foo: baz +\f[R] +.fi +.SH Group By +.PP +This is used to group items in an array by an expression. +.SS Group by field +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- foo: 1 + bar: 10 +- foo: 3 + bar: 100 +- foo: 1 + bar: 1 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]group_by(.foo)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- - foo: 1 + bar: 10 + - foo: 1 + bar: 1 +- - foo: 3 + bar: 100 +\f[R] +.fi +.SS Group by field, with nulls +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat: dog +- foo: 1 + bar: 10 +- foo: 3 + bar: 100 +- no: foo for you +- foo: 1 + bar: 1 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]group_by(.foo)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- - cat: dog + - no: foo for you +- - foo: 1 + bar: 10 + - foo: 1 + bar: 1 +- - foo: 3 + bar: 100 +\f[R] +.fi +.SH Has +.PP +This operation returns true if the key exists in a map (or index in an +array), false otherwise. +.SS Has map key +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: yes +- a: \[ti] +- a: +- b: nope +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | has(\[dq]a\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +true +true +false +\f[R] +.fi +.SS Select, checking for existence of deep paths +.PP +Simply pipe in parent expressions into \f[C]has\f[R] +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: + b: + c: cat +- a: + b: + d: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | select(.a.b | has(\[dq]c\[dq]))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: + c: cat +\f[R] +.fi +.SS Has array index +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- [] +- [1] +- [1, 2] +- [1, null] +- [1, 2, 3] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | has(1)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +false +false +true +true +true +\f[R] +.fi +.SH Keys +.PP +Use the \f[C]keys\f[R] operator to return map keys or array indices. +.SS Map keys +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +dog: woof +cat: meow +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]keys\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- dog +- cat +\f[R] +.fi +.SS Array keys +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- apple +- banana +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]keys\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 0 +- 1 +\f[R] +.fi +.SS Retrieve array key +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 1 +- 2 +- 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[1] | key\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +1 +\f[R] +.fi +.SS Retrieve map key +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | key\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a +\f[R] +.fi +.SS No key +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +{} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]key\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +\f[R] +.fi +.SS Update map key +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + x: 3 + y: 4 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.a.x | key) = \[dq]meow\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + meow: 3 + y: 4 +\f[R] +.fi +.SS Get comment from map key +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + # comment on key + x: 3 + y: 4 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.x | key | headComment\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +comment on key +\f[R] +.fi +.SS Check node is a key +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: + - cat + c: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][... | { \[dq]p\[dq]: path | join(\[dq].\[dq]), \[dq]isKey\[dq]: is_key, \[dq]tag\[dq]: tag }]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- p: \[dq]\[dq] + isKey: false + tag: \[aq]!!map\[aq] +- p: a + isKey: true + tag: \[aq]!!str\[aq] +- p: a + isKey: false + tag: \[aq]!!map\[aq] +- p: a.b + isKey: true + tag: \[aq]!!str\[aq] +- p: a.b + isKey: false + tag: \[aq]!!seq\[aq] +- p: a.b.0 + isKey: false + tag: \[aq]!!str\[aq] +- p: a.c + isKey: true + tag: \[aq]!!str\[aq] +- p: a.c + isKey: false + tag: \[aq]!!str\[aq] +\f[R] +.fi +.SS Get kind +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: 5 +c: 3.2 +e: true +f: [] +g: {} +h: null +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. | kind\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +map +scalar +scalar +scalar +scalar +seq +map +scalar +\f[R] +.fi +.SS Get kind, ignores custom tags +.PP +Unlike tag, kind is not affected by custom tags. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: !!thing cat +b: !!foo {} +c: !!bar [] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. | kind\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +map +scalar +map +seq +\f[R] +.fi +.SS Add comments only to scalars +.PP +An example of how you can use kind +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: 5 + c: 3.2 +e: true +f: [] +g: {} +h: null +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.. | select(kind == \[dq]scalar\[dq])) line_comment = \[dq]this is a scalar\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: 5 # this is a scalar + c: 3.2 # this is a scalar +e: true # this is a scalar +f: [] +g: {} +h: null # this is a scalar +\f[R] +.fi +.SH Length +.PP +Returns the lengths of the nodes. +Length is defined according to the type of the node. +.SS String length +.PP +returns length of string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | length\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +3 +\f[R] +.fi +.SS null length +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: null +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | length\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +0 +\f[R] +.fi +.SS Map length +.PP +returns number of entries +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +c: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]length\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +2 +\f[R] +.fi +.SS Array length +.PP +returns number of elements +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 2 +- 4 +- 6 +- 8 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]length\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +4 +\f[R] +.fi +.SH Line +.PP +Returns the line of the matching node. +Starts from 1, 0 indicates there was no line data. +.SS Returns line of \f[I]value\f[R] node +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: + c: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b | line\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +3 +\f[R] +.fi +.SS Returns line of \f[I]key\f[R] node +.PP +Pipe through the key operator to get the line of the key +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: + c: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b | key | line\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +2 +\f[R] +.fi +.SS First line is 1 +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | line\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +1 +\f[R] +.fi +.SS No line data is 0 +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]{\[dq]a\[dq]: \[dq]new entry\[dq]} | line\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +0 +\f[R] +.fi +.SH Load +.PP +The load operators allows you to load in content from another file. +.PP +Note that you can use string operators like \f[C]+\f[R] and +\f[C]sub\f[R] to modify the value in the yaml file to a path that exists +in your system. +.PP +You can load files of the following supported types: +.PP +.TS +tab(@); +l l. +T{ +Format +T}@T{ +Load Operator +T} +_ +T{ +Yaml +T}@T{ +load +T} +T{ +XML +T}@T{ +load_xml +T} +T{ +Properties +T}@T{ +load_props +T} +T{ +Plain String +T}@T{ +load_str +T} +T{ +Base64 +T}@T{ +load_base64 +T} +.TE +.PP +Note that load_base64 only works for base64 encoded utf-8 strings. +.SS Samples files for tests: +.SS yaml +.PP +\f[C]../../examples/thing.yml\f[R]: +.IP +.nf +\f[C] +a: apple is included +b: cool +\f[R] +.fi +.SS xml +.PP +\f[C]small.xml\f[R]: +.IP +.nf +\f[C] +<this>is some xml</this> +\f[R] +.fi +.SS properties +.PP +\f[C]small.properties\f[R]: +.IP +.nf +\f[C] +this.is = a properties file +\f[R] +.fi +.SS base64 +.PP +\f[C]base64.txt\f[R]: +.IP +.nf +\f[C] +bXkgc2VjcmV0IGNoaWxsaSByZWNpcGUgaXMuLi4u +\f[R] +.fi +.SS Simple example +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +myFile: ../../examples/thing.yml +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]load(.myFile)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: apple is included +b: cool. +\f[R] +.fi +.SS Replace node with referenced file +.PP +Note that you can modify the filename in the load operator if needed. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +something: + file: thing.yml +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].something |= load(\[dq]../../examples/\[dq] + .file)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +something: + a: apple is included + b: cool. +\f[R] +.fi +.SS Replace \f[I]all\f[R] nodes with referenced file +.PP +Recursively match all the nodes (\f[C]..\f[R]) and then filter the ones +that have a `file' attribute. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +something: + file: thing.yml +over: + here: + - file: thing.yml +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.. | select(has(\[dq]file\[dq]))) |= load(\[dq]../../examples/\[dq] + .file)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +something: + a: apple is included + b: cool. +over: + here: + - a: apple is included + b: cool. +\f[R] +.fi +.SS Replace node with referenced file as string +.PP +This will work for any text based file +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +something: + file: thing.yml +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].something |= load_str(\[dq]../../examples/\[dq] + .file)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +something: |- + a: apple is included + b: cool. +\f[R] +.fi +.SS Load from XML +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cool: things +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].more_stuff = load_xml(\[dq]../../examples/small.xml\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cool: things +more_stuff: + this: is some xml +\f[R] +.fi +.SS Load from Properties +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cool: things +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].more_stuff = load_props(\[dq]../../examples/small.properties\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cool: things +more_stuff: + this: + is: a properties file +\f[R] +.fi +.SS Merge from properties +.PP +This can be used as a convenient way to update a yaml document +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +this: + is: from yaml + cool: ay +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]. *= load_props(\[dq]../../examples/small.properties\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +this: + is: a properties file + cool: ay +\f[R] +.fi +.SS Load from base64 encoded file +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cool: things +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].more_stuff = load_base64(\[dq]../../examples/base64.txt\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cool: things +more_stuff: my secret chilli recipe is.... +\f[R] +.fi +.SH Map +.PP +Maps values of an array. +Use \f[C]map_values\f[R] to map values of an object. +.SS Map array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 1 +- 2 +- 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]map(. + 1)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 2 +- 3 +- 4 +\f[R] +.fi +.SS Map object values +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 1 +b: 2 +c: 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]map_values(. + 1)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 2 +b: 3 +c: 4 +\f[R] +.fi +.SH Max +.PP +Computes the maximum among an incoming sequence of scalar values. +.SS Maximum int +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 99 +- 16 +- 12 +- 6 +- 66 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]max\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +99 +\f[R] +.fi +.SS Maximum string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- foo +- bar +- baz +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]max\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +foo +\f[R] +.fi +.SS Maximum of empty +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +[] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]max\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +\f[R] +.fi +.SH Min +.PP +Computes the minimum among an incoming sequence of scalar values. +.SS Minimum int +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 99 +- 16 +- 12 +- 6 +- 66 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]min\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +6 +\f[R] +.fi +.SS Minimum string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- foo +- bar +- baz +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]min\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +bar +\f[R] +.fi +.SS Minimum of empty +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +[] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]min\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +\f[R] +.fi +.SH Modulo +.PP +Arithmetic modulo operator, returns the remainder from dividing two +numbers. +.SS Number modulo - int +.PP +If the lhs and rhs are ints then the expression will be calculated with +ints. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 13 +b: 2 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .a % .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 1 +b: 2 +\f[R] +.fi +.SS Number modulo - float +.PP +If the lhs or rhs are floats then the expression will be calculated with +floats. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 12 +b: 2.5 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .a % .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !!float 2 +b: 2.5 +\f[R] +.fi +.SS Number modulo - int by zero +.PP +If the lhs is an int and rhs is a 0 the result is an error. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 1 +b: 0 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .a % .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Error: cannot modulo by 0 +\f[R] +.fi +.SS Number modulo - float by zero +.PP +If the lhs is a float and rhs is a 0 the result is NaN. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 1.1 +b: 0 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .a % .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !!float NaN +b: 0 +\f[R] +.fi +.SH Multiply (Merge) +.PP +Like the multiple operator in jq, depending on the operands, this +multiply operator will do different things. +Currently numbers, arrays and objects are supported. +.SS Objects and arrays - merging +.PP +Objects are merged \f[I]deeply\f[R] matching on matching keys. +By default, array values override and are not deeply merged. +.PP +You can use the add operator \f[C]+\f[R], to shallow merge objects, see +more info here (https://mikefarah.gitbook.io/yq/operators/add). +.PP +Note that when merging objects, this operator returns the merged object +(not the parent). +This will be clearer in the examples below. +.SS Merge Flags +.PP +You can control how objects are merged by using one or more of the +following flags. +Multiple flags can be used together, e.g.\ \f[C].a *+? .b\f[R]. +See examples below +.IP \[bu] 2 +\f[C]+\f[R] append arrays +.IP \[bu] 2 +\f[C]d\f[R] deeply merge arrays +.IP \[bu] 2 +\f[C]?\f[R] only merge \f[I]existing\f[R] fields +.IP \[bu] 2 +\f[C]n\f[R] only merge \f[I]new\f[R] fields +.IP \[bu] 2 +\f[C]c\f[R] clobber custom tags +.PP +To perform a shallow merge only, use the add operator \f[C]+\f[R], see +more info here (https://mikefarah.gitbook.io/yq/operators/add). +.SS Merge two files together +.PP +This uses the load operator to merge file2 into file1. +.IP +.nf +\f[C] +yq \[aq]. *= load(\[dq]file2.yml\[dq])\[aq] file1.yml +\f[R] +.fi +.SS Merging all files +.PP +Note the use of \f[C]eval-all\f[R] to ensure all documents are loaded +into memory. +.IP +.nf +\f[C] +yq eval-all \[aq]. as $item ireduce ({}; . * $item )\[aq] *.yml +\f[R] +.fi +.SH Merging complex arrays together by a key field +.PP +By default - \f[C]yq\f[R] merge is naive. +It merges maps when they match the key name, and arrays are merged +either by appending them together, or merging the entries by their +position in the array. +.PP +For more complex array merging (e.g.\ merging items that match on a +certain key) please see the example +here (https://mikefarah.gitbook.io/yq/operators/multiply-merge#merge-arrays-of-objects-together-matching-on-a-key) +.SS Multiply integers +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 3 +b: 4 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a *= .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 12 +b: 4 +\f[R] +.fi +.SS Multiply string node X int +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +b: banana +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b * 4\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +bananabananabananabanana +\f[R] +.fi +.SS Multiply int X string node +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +b: banana +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]4 * .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +bananabananabananabanana +\f[R] +.fi +.SS Multiply string X int node +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +n: 4 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]\[dq]banana\[dq] * .n\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +bananabananabananabanana +\f[R] +.fi +.SS Multiply int node X string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +n: 4 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].n * \[dq]banana\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +bananabananabananabanana +\f[R] +.fi +.SS Merge objects together, returning merged result only +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + field: me + fieldA: cat +b: + field: + g: wizz + fieldB: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a * .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +field: + g: wizz +fieldA: cat +fieldB: dog +\f[R] +.fi +.SS Merge objects together, returning parent object +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + field: me + fieldA: cat +b: + field: + g: wizz + fieldB: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]. * {\[dq]a\[dq]:.b}\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + field: + g: wizz + fieldA: cat + fieldB: dog +b: + field: + g: wizz + fieldB: dog +\f[R] +.fi +.SS Merge keeps style of LHS +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: {things: great} +b: + also: \[dq]me\[dq] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]. * {\[dq]a\[dq]:.b}\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: {things: great, also: \[dq]me\[dq]} +b: + also: \[dq]me\[dq] +\f[R] +.fi +.SS Merge arrays +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - 1 + - 2 + - 3 +b: + - 3 + - 4 + - 5 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]. * {\[dq]a\[dq]:.b}\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + - 3 + - 4 + - 5 +b: + - 3 + - 4 + - 5 +\f[R] +.fi +.SS Merge, only existing fields +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + thing: one + cat: frog +b: + missing: two + thing: two +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a *? .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +thing: two +cat: frog +\f[R] +.fi +.SS Merge, only new fields +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + thing: one + cat: frog +b: + missing: two + thing: two +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a *n .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +thing: one +cat: frog +missing: two +\f[R] +.fi +.SS Merge, appending arrays +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + array: + - 1 + - 2 + - animal: dog + value: coconut +b: + array: + - 3 + - 4 + - animal: cat + value: banana +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a *+ .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +array: + - 1 + - 2 + - animal: dog + - 3 + - 4 + - animal: cat +value: banana +\f[R] +.fi +.SS Merge, only existing fields, appending arrays +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + thing: + - 1 + - 2 +b: + thing: + - 3 + - 4 + another: + - 1 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a *?+ .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +thing: + - 1 + - 2 + - 3 + - 4 +\f[R] +.fi +.SS Merge, deeply merging arrays +.PP +Merging arrays deeply means arrays are merged like objects, with indices +as their key. +In this case, we merge the first item in the array and do nothing with +the second. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - name: fred + age: 12 + - name: bob + age: 32 +b: + - name: fred + age: 34 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a *d .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- name: fred + age: 34 +- name: bob + age: 32 +\f[R] +.fi +.SS Merge arrays of objects together, matching on a key +.PP +This is a fairly complex expression - you can use it as is by providing +the environment variables as seen in the example below. +.PP +It merges in the array provided in the second file into the first - +matching on equal keys. +.PP +Explanation: +.PP +The approach, at a high level, is to reduce into a merged map (keyed by +the unique key) and then convert that back into an array. +.PP +First the expression will create a map from the arrays keyed by the +idPath, the unique field we want to merge by. +The reduce operator is merging `({}; . * $item )', so array elements +with the matching key will be merged together. +.PP +Next, we convert the map back to an array, using reduce again, +concatenating all the map values together. +.PP +Finally, we set the result of the merged array back into the first doc. +.PP +Thanks Kev from +stackoverflow (https://stackoverflow.com/a/70109529/1168223) +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +myArray: + - a: apple + b: appleB + - a: kiwi + b: kiwiB + - a: banana + b: bananaB +something: else +\f[R] +.fi +.PP +And another sample another.yml file of: +.IP +.nf +\f[C] +newArray: + - a: banana + c: bananaC + - a: apple + b: appleB2 + - a: dingo + c: dingoC +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +idPath=\[dq].a\[dq] originalPath=\[dq].myArray\[dq] otherPath=\[dq].newArray\[dq] yq eval-all \[aq] +( + (( (eval(strenv(originalPath)) + eval(strenv(otherPath))) | .[] | {(eval(strenv(idPath))): .}) as $item ireduce ({}; . * $item )) as $uniqueMap + | ( $uniqueMap | to_entries | .[]) as $item ireduce([]; . + $item.value) +) as $mergedArray +| select(fi == 0) | (eval(strenv(originalPath))) = $mergedArray +\[aq] sample.yml another.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +myArray: + - a: apple + b: appleB2 + - a: kiwi + b: kiwiB + - a: banana + b: bananaB + c: bananaC + - a: dingo + c: dingoC +something: else +\f[R] +.fi +.SS Merge to prefix an element +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]. * {\[dq]a\[dq]: {\[dq]c\[dq]: .a}}\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + c: cat +b: dog +\f[R] +.fi +.SS Merge with simple aliases +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: &cat + c: frog +b: + f: *cat +c: + g: thongs +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].c * .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +g: thongs +f: *cat +\f[R] +.fi +.SS Merge copies anchor names +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + c: &cat frog +b: + f: *cat +c: + g: thongs +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].c * .a\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +g: thongs +c: &cat frog +\f[R] +.fi +.SS Merge with merge anchors +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foo: &foo + a: foo_a + thing: foo_thing + c: foo_c +bar: &bar + b: bar_b + thing: bar_thing + c: bar_c +foobarList: + b: foobarList_b + !!merge <<: + - *foo + - *bar + c: foobarList_c +foobar: + c: foobar_c + !!merge <<: *foo + thing: foobar_thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].foobar * .foobarList\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +c: foobarList_c +!!merge <<: + - *foo + - *bar +thing: foobar_thing +b: foobarList_b +\f[R] +.fi +.SS Custom types: that are really numbers +.PP +When custom tags are encountered, yq will try to decode the underlying +type. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: !horse 2 +b: !goat 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .a * .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !horse 6 +b: !goat 3 +\f[R] +.fi +.SS Custom types: that are really maps +.PP +Custom tags will be maintained. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: !horse + cat: meow +b: !goat + dog: woof +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .a * .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !horse + cat: meow + dog: woof +b: !goat + dog: woof +\f[R] +.fi +.SS Custom types: clobber tags +.PP +Use the \f[C]c\f[R] option to clobber custom tags. +Note that the second tag is now used. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: !horse + cat: meow +b: !goat + dog: woof +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a *=c .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !goat + cat: meow + dog: woof +b: !goat + dog: woof +\f[R] +.fi +.SS Merging a null with a map +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]null * {\[dq]some\[dq]: \[dq]thing\[dq]}\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +some: thing +\f[R] +.fi +.SS Merging a map with null +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]{\[dq]some\[dq]: \[dq]thing\[dq]} * null\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +some: thing +\f[R] +.fi +.SS Merging a null with an array +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]null * [\[dq]some\[dq]]\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- some +\f[R] +.fi +.SS Merging an array with null +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq][\[dq]some\[dq]] * null\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- some +\f[R] +.fi +.SH Omit +.PP +Works like \f[C]pick\f[R], but instead you specify the keys/indices that +you \f[I]don\[cq]t\f[R] want included. +.SS Omit keys from map +.PP +Note that non existent keys are skipped. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +myMap: + cat: meow + dog: bark + thing: hamster + hamster: squeak +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].myMap |= omit([\[dq]hamster\[dq], \[dq]cat\[dq], \[dq]goat\[dq]])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +myMap: + dog: bark + thing: hamster +\f[R] +.fi +.SS Omit indices from array +.PP +Note that non existent indices are skipped. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- leopard +- lion +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]omit([2, 0, 734, -5])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- leopard +\f[R] +.fi +.SH Parent +.PP +Parent simply returns the parent nodes of the matching nodes. +.SS Simple example +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + nested: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.nested | parent\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +nested: cat +\f[R] +.fi +.SS Parent of nested matches +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + fruit: apple + name: bob +b: + fruit: banana + name: sam +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. | select(. == \[dq]banana\[dq]) | parent\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +fruit: banana +name: sam +\f[R] +.fi +.SS N-th parent +.PP +You can optionally supply the number of levels to go up for the parent, +the default being 1. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: + c: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.b.c | parent(2)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +b: + c: cat +\f[R] +.fi +.SS N-th parent - another level +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: + c: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.b.c | parent(3)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: + c: cat +\f[R] +.fi +.SS No parent +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +{} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]parent\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +\f[R] +.fi +.SH Path +.PP +The \f[C]path\f[R] operator can be used to get the traversal paths of +matching nodes in an expression. +The path is returned as an array, which if traversed in order will lead +to the matching node. +.PP +You can get the key/index of matching nodes by using the \f[C]path\f[R] +operator to return the path array then piping that through +\f[C].[-1]\f[R] to get the last element of that array, the key. +.PP +Use \f[C]setpath\f[R] to set a value to the path array returned by +\f[C]path\f[R], and similarly \f[C]delpaths\f[R] for an array of path +arrays. +.SS Map path +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.b | path\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- a +- b +\f[R] +.fi +.SS Get map key +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.b | path | .[-1]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +b +\f[R] +.fi +.SS Array path +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - cat + - dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.[] | select(. == \[dq]dog\[dq]) | path\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- a +- 1 +\f[R] +.fi +.SS Get array index +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - cat + - dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.[] | select(. == \[dq]dog\[dq]) | path | .[-1]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +1 +\f[R] +.fi +.SS Print path and value +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - cat + - dog + - frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a[] | select(. == \[dq]*og\[dq]) | [{\[dq]path\[dq]:path, \[dq]value\[dq]:.}]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- path: + - a + - 1 + value: dog +- path: + - a + - 2 + value: frog +\f[R] +.fi +.SS Set path +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]setpath([\[dq]a\[dq], \[dq]b\[dq]]; \[dq]things\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: things +\f[R] +.fi +.SS Set on empty document +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]setpath([\[dq]a\[dq], \[dq]b\[dq]]; \[dq]things\[dq])\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: things +\f[R] +.fi +.SS Set path to prune deep paths +.PP +Like pick but recursive. +This uses \f[C]ireduce\f[R] to deeply set the selected paths into an +empty object. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +parentA: bob +parentB: + child1: i am child1 + child2: i am child2 +parentC: + child1: me child1 + child2: me child2 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.parentB.child2, .parentC.child1) as $i + ireduce({}; setpath($i | path; $i))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +parentB: + child2: i am child2 +parentC: + child1: me child1 +\f[R] +.fi +.SS Set array path +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - cat + - frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]setpath([\[dq]a\[dq], 0]; \[dq]things\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + - things + - frog +\f[R] +.fi +.SS Set array path empty +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]setpath([\[dq]a\[dq], 0]; \[dq]things\[dq])\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + - things +\f[R] +.fi +.SS Delete path +.PP +Notice delpaths takes an \f[I]array\f[R] of paths. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: cat + c: dog + d: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]delpaths([[\[dq]a\[dq], \[dq]c\[dq]], [\[dq]a\[dq], \[dq]d\[dq]]])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: cat +\f[R] +.fi +.SS Delete array path +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - cat + - frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]delpaths([[\[dq]a\[dq], 0]])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + - frog +\f[R] +.fi +.SS Delete - wrong parameter +.PP +delpaths does not work with a single path array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - cat + - frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]delpaths([\[dq]a\[dq], 0])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Error: DELPATHS: expected entry [0] to be a sequence, but its a !!str. Note that delpaths takes an array of path arrays, e.g. [[\[dq]a\[dq], \[dq]b\[dq]]] +\f[R] +.fi +.SH Pick +.PP +Filter a map by the specified list of keys. +Map is returned with the key in the order of the pick list. +.PP +Similarly, filter an array by the specified list of indices. +.SS Pick keys from map +.PP +Note that the order of the keys matches the pick order and non existent +keys are skipped. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +myMap: + cat: meow + dog: bark + thing: hamster + hamster: squeak +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].myMap |= pick([\[dq]hamster\[dq], \[dq]cat\[dq], \[dq]goat\[dq]])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +myMap: + hamster: squeak + cat: meow +\f[R] +.fi +.SS Pick indices from array +.PP +Note that the order of the indices matches the pick order and non +existent indices are skipped. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- leopard +- lion +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]pick([2, 0, 734, -5])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- lion +- cat +\f[R] +.fi +.SH Pipe +.PP +Pipe the results of an expression into another. +Like the bash operator. +.SS Simple Pipe +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a | .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat +\f[R] +.fi +.SS Multiple updates +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cow +b: sheep +c: same +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = \[dq]cat\[dq] | .b = \[dq]dog\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat +b: dog +c: same +\f[R] +.fi +.SH Pivot +.PP +Emulates the \f[C]PIVOT\f[R] function supported by several popular RDBMS +systems. +.SS Pivot a sequence of sequences +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- - foo + - bar + - baz +- - sis + - boom + - bah +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]pivot\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- - foo + - sis +- - bar + - boom +- - baz + - bah +\f[R] +.fi +.SS Pivot sequence of heterogeneous sequences +.PP +Missing values are \[lq]padded\[rq] to null. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- - foo + - bar + - baz +- - sis + - boom + - bah + - blah +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]pivot\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- - foo + - sis +- - bar + - boom +- - baz + - bah +- - + - blah +\f[R] +.fi +.SS Pivot sequence of maps +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- foo: a + bar: b + baz: c +- foo: x + bar: y + baz: z +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]pivot\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +foo: + - a + - x +bar: + - b + - y +baz: + - c + - z +\f[R] +.fi +.SS Pivot sequence of heterogeneous maps +.PP +Missing values are \[lq]padded\[rq] to null. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- foo: a + bar: b + baz: c +- foo: x + bar: y + baz: z + what: ever +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]pivot\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +foo: + - a + - x +bar: + - b + - y +baz: + - c + - z +what: + - + - ever +\f[R] +.fi +.SH Recursive Descent (Glob) +.PP +This operator recursively matches (or globs) all children nodes given of +a particular element, including that node itself. +This is most often used to apply a filter recursively against all +matches. +.SS match values form \f[C]..\f[R] +.PP +This will, like the \f[C]jq\f[R] equivalent, recursively match all +\f[I]value\f[R] nodes. +Use it to find/manipulate particular values. +.PP +For instance to set the \f[C]style\f[R] of all \f[I]value\f[R] nodes in +a yaml doc, excluding map keys: +.IP +.nf +\f[C] +yq \[aq].. style= \[dq]flow\[dq]\[aq] file.yaml +\f[R] +.fi +.SS match values and map keys form \f[C]...\f[R] +.PP +The also includes map keys in the results set. +This is particularly useful in YAML as unlike JSON, map keys can have +their own styling and tags and also use anchors and aliases. +.PP +For instance to set the \f[C]style\f[R] of all nodes in a yaml doc, +including the map keys: +.IP +.nf +\f[C] +yq \[aq]... style= \[dq]flow\[dq]\[aq] file.yaml +\f[R] +.fi +.SS Recurse map (values only) +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]..\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: frog +frog +\f[R] +.fi +.SS Recursively find nodes with keys +.PP +Note that this example has wrapped the expression in \f[C][]\f[R] to +show that there are two matches returned. +You do not have to wrap in \f[C][]\f[R] in your path expression. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + name: frog + b: + name: blog + age: 12 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][.. | select(has(\[dq]name\[dq]))]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- name: frog + b: + name: blog + age: 12 +- name: blog + age: 12 +\f[R] +.fi +.SS Recursively find nodes with values +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + nameA: frog + b: + nameB: frog + age: 12 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. | select(. == \[dq]frog\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +frog +frog +\f[R] +.fi +.SS Recurse map (values and keys) +.PP +Note that the map key appears in the results +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]...\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: frog +a +frog +\f[R] +.fi +.SS Aliases are not traversed +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: &cat + c: frog +b: *cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][..]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- a: &cat + c: frog + b: *cat +- &cat + c: frog +- frog +- *cat +\f[R] +.fi +.SS Merge docs are not traversed +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foo: &foo + a: foo_a + thing: foo_thing + c: foo_c +bar: &bar + b: bar_b + thing: bar_thing + c: bar_c +foobarList: + b: foobarList_b + !!merge <<: + - *foo + - *bar + c: foobarList_c +foobar: + c: foobar_c + !!merge <<: *foo + thing: foobar_thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].foobar | [..]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- c: foobar_c + !!merge <<: *foo + thing: foobar_thing +- foobar_c +- *foo +- foobar_thing +\f[R] +.fi +.SH Reduce +.PP +Reduce is a powerful way to process a collection of data into a new +form. +.IP +.nf +\f[C] +<exp> as $<name> ireduce (<init>; <block>) +\f[R] +.fi +.PP +e.g. +.IP +.nf +\f[C] +\&.[] as $item ireduce (0; . + $item) +\f[R] +.fi +.PP +On the LHS we are configuring the collection of items that will be +reduced \f[C]<exp>\f[R] as well as what each element will be called +\f[C]$<name>\f[R]. +Note that the array has been splatted into its individual elements. +.PP +On the RHS there is \f[C]<init>\f[R], the starting value of the +accumulator and \f[C]<block>\f[R], the expression that will update the +accumulator for each element in the collection. +Note that within the block expression, \f[C].\f[R] will evaluate to the +current value of the accumulator. +.SS yq vs jq syntax +.PP +Reduce syntax in \f[C]yq\f[R] is a little different from \f[C]jq\f[R] - +as \f[C]yq\f[R] (currently) isn\[cq]t as sophisticated as \f[C]jq\f[R] +and its only supports infix notation (e.g.\ a + b, where the operator is +in the middle of the two parameters) - where as \f[C]jq\f[R] uses a mix +of infix notation with \f[I]prefix\f[R] notation +(e.g.\ \f[C]reduce a b\f[R] is like writing \f[C]+ a b\f[R]). +.PP +To that end, the reduce operator is called \f[C]ireduce\f[R] for +backwards compatibility if a \f[C]jq\f[R] like prefix version of +\f[C]reduce\f[R] is ever added. +.SS Sum numbers +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 10 +- 2 +- 5 +- 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] as $item ireduce (0; . + $item)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +20 +\f[R] +.fi +.SS Merge all yaml files together +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +And another sample another.yml file of: +.IP +.nf +\f[C] +b: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq eval-all \[aq]. as $item ireduce ({}; . * $item )\[aq] sample.yml another.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat +b: dog +\f[R] +.fi +.SS Convert an array to an object +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- name: Cathy + has: apples +- name: Bob + has: bananas +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] as $item ireduce ({}; .[$item | .name] = ($item | .has) )\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Cathy: apples +Bob: bananas +\f[R] +.fi +.SH Reverse +.PP +Reverses the order of the items in an array +.SS Reverse +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 1 +- 2 +- 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]reverse\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 3 +- 2 +- 1 +\f[R] +.fi +.SS Sort descending by string field +.PP +Use sort with reverse to sort in descending order. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: banana +- a: cat +- a: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]sort_by(.a) | reverse\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- a: cat +- a: banana +- a: apple +\f[R] +.fi +.SH Select +.PP +Select is used to filter arrays and maps by a boolean expression. +.SS Related Operators +.IP \[bu] 2 +equals / not equals (\f[C]==\f[R], \f[C]!=\f[R]) operators +here (https://mikefarah.gitbook.io/yq/operators/equals) +.IP \[bu] 2 +comparison (\f[C]>=\f[R], \f[C]<\f[R] etc) operators +here (https://mikefarah.gitbook.io/yq/operators/compare) +.IP \[bu] 2 +boolean operators (\f[C]and\f[R], \f[C]or\f[R], \f[C]any\f[R] etc) +here (https://mikefarah.gitbook.io/yq/operators/boolean-operators) +.SS Select elements from array using wildcard prefix +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- goat +- dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | select(. == \[dq]*at\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat +goat +\f[R] +.fi +.SS Select elements from array using wildcard suffix +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- go-kart +- goat +- dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | select(. == \[dq]go*\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +go-kart +goat +\f[R] +.fi +.SS Select elements from array using wildcard prefix and suffix +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- ago +- go +- meow +- going +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | select(. == \[dq]*go*\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +ago +go +going +\f[R] +.fi +.SS Select elements from array with regular expression +.PP +See more regular expression examples under the \f[C]string\f[R] operator +docs (https://mikefarah.gitbook.io/yq/operators/string-operators). +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- this_0 +- not_this +- nor_0_this +- thisTo_4 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | select(test(\[dq][a-zA-Z]+_[0-9]$\[dq]))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +this_0 +thisTo_4 +\f[R] +.fi +.SS Select items from a map +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +things: cat +bob: goat +horse: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | select(. == \[dq]cat\[dq] or test(\[dq]og$\[dq]))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat +dog +\f[R] +.fi +.SS Use select and with_entries to filter map keys +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +name: bob +legs: 2 +game: poker +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with_entries(select(.key | test(\[dq]ame$\[dq])))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +name: bob +game: poker +\f[R] +.fi +.SS Select multiple items in a map and update +.PP +Note the brackets around the entire LHS. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + things: cat + bob: goat + horse: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.a.[] | select(. == \[dq]cat\[dq] or . == \[dq]goat\[dq])) |= \[dq]rabbit\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + things: rabbit + bob: rabbit + horse: dog +\f[R] +.fi +.SH Shuffle +.PP +Shuffles an array. +Note that this command does \f[I]not\f[R] use a cryptographically secure +random number generator to randomise the array order. +.SS Shuffle array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 1 +- 2 +- 3 +- 4 +- 5 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]shuffle\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 5 +- 2 +- 4 +- 1 +- 3 +\f[R] +.fi +.SS Shuffle array in place +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cool: + - 1 + - 2 + - 3 + - 4 + - 5 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].cool |= shuffle\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cool: + - 5 + - 2 + - 4 + - 1 + - 3 +\f[R] +.fi +.SH Slice/Splice Array +.PP +The slice array operator takes an array as input and returns a subarray. +Like the \f[C]jq\f[R] equivalent, \f[C].[10:15]\f[R] will return an +array of length 5, starting from index 10 inclusive, up to index 15 +exclusive. +Negative numbers count backwards from the end of the array. +.PP +You may leave out the first or second number, which will refer to the +start or end of the array respectively. +.SS Slicing arrays +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- dog +- frog +- cow +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[1:3]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- dog +- frog +\f[R] +.fi +.SS Slicing arrays - without the first number +.PP +Starts from the start of the array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- dog +- frog +- cow +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[:2]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- cat +- dog +\f[R] +.fi +.SS Slicing arrays - without the second number +.PP +Finishes at the end of the array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- dog +- frog +- cow +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[2:]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- frog +- cow +\f[R] +.fi +.SS Slicing arrays - use negative numbers to count backwards from the end +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- dog +- frog +- cow +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[1:-1]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- dog +- frog +\f[R] +.fi +.SS Inserting into the middle of an array +.PP +using an expression to find the index +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- dog +- frog +- cow +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.[] | select(. == \[dq]dog\[dq]) | key + 1) as $pos | .[0:($pos)] + [\[dq]rabbit\[dq]] + .[$pos:]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- cat +- dog +- rabbit +- frog +- cow +\f[R] +.fi +.SH Sort Keys +.PP +The Sort Keys operator sorts maps by their keys (based on their string +value). +This operator does not do anything to arrays or scalars (so you can +easily recursively apply it to all maps). +.PP +Sort is particularly useful for diffing two different yaml documents: +.IP +.nf +\f[C] +yq -i -P \[aq]sort_keys(..)\[aq] file1.yml +yq -i -P \[aq]sort_keys(..)\[aq] file2.yml +diff file1.yml file2.yml +\f[R] +.fi +.PP +Note that \f[C]yq\f[R] does not yet consider anchors when sorting by +keys - this may result in invalid yaml documents if you are using merge +anchors. +.PP +For more advanced sorting, using \f[C]to_entries\f[R] to convert the map +to an array, then sort/process the array as you like (e.g.\ using +\f[C]sort_by\f[R]) and convert back to a map using +\f[C]from_entries\f[R]. +See +here (https://mikefarah.gitbook.io/yq/operators/entries#custom-sort-map-keys) +for an example. +.SS Sort keys of map +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +c: frog +a: blah +b: bing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]sort_keys(.)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: blah +b: bing +c: frog +\f[R] +.fi +.SS Sort keys recursively +.PP +Note the array elements are left unsorted, but maps inside arrays are +sorted +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +bParent: + c: dog + array: + - 3 + - 1 + - 2 +aParent: + z: donkey + x: + - c: yum + b: delish + - b: ew + a: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]sort_keys(..)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +aParent: + x: + - b: delish + c: yum + - a: apple + b: ew + z: donkey +bParent: + array: + - 3 + - 1 + - 2 + c: dog +\f[R] +.fi +.SH Sort +.PP +Sorts an array. +Use \f[C]sort\f[R] to sort an array as is, or \f[C]sort_by(exp)\f[R] to +sort by a particular expression (e.g.\ subfield). +.PP +To sort by descending order, pipe the results through the +\f[C]reverse\f[R] operator after sorting. +.PP +Note that at this stage, \f[C]yq\f[R] only sorts scalar fields. +.SS Sort by string field +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: banana +- a: cat +- a: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]sort_by(.a)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- a: apple +- a: banana +- a: cat +\f[R] +.fi +.SS Sort by multiple fields +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: dog +- a: cat + b: banana +- a: cat + b: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]sort_by(.a, .b)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- a: cat + b: apple +- a: cat + b: banana +- a: dog +\f[R] +.fi +.SS Sort descending by string field +.PP +Use sort with reverse to sort in descending order. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: banana +- a: cat +- a: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]sort_by(.a) | reverse\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- a: cat +- a: banana +- a: apple +\f[R] +.fi +.SS Sort array in place +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cool: + - a: banana + - a: cat + - a: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].cool |= sort_by(.a)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cool: + - a: apple + - a: banana + - a: cat +\f[R] +.fi +.SS Sort array of objects by key +.PP +Note that you can give sort_by complex expressions, not just paths +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cool: + - b: banana + - a: banana + - c: banana +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].cool |= sort_by(keys | .[0])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cool: + - a: banana + - b: banana + - c: banana +\f[R] +.fi +.SS Sort is stable +.PP +Note the order of the elements in unchanged when equal in sorting. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: banana + b: 1 +- a: banana + b: 2 +- a: banana + b: 3 +- a: banana + b: 4 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]sort_by(.a)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- a: banana + b: 1 +- a: banana + b: 2 +- a: banana + b: 3 +- a: banana + b: 4 +\f[R] +.fi +.SS Sort by numeric field +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: 10 +- a: 100 +- a: 1 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]sort_by(.a)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- a: 1 +- a: 10 +- a: 100 +\f[R] +.fi +.SS Sort by custom date field +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: 12-Jun-2011 +- a: 23-Dec-2010 +- a: 10-Aug-2011 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with_dtf(\[dq]02-Jan-2006\[dq]; sort_by(.a))\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- a: 23-Dec-2010 +- a: 12-Jun-2011 +- a: 10-Aug-2011 +\f[R] +.fi +.SS Sort, nulls come first +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 8 +- 3 +- null +- 6 +- true +- false +- cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]sort\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- null +- false +- true +- 3 +- 6 +- 8 +- cat +\f[R] +.fi +.SH Split into Documents +.PP +This operator splits all matches into separate documents +.SS Split empty +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]split_doc\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +\f[R] +.fi +.SS Split array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: cat +- b: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | split_doc\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat +--- +b: dog +\f[R] +.fi +.SH String Operators +.SS RegEx +.PP +This uses Golang\[cq]s native regex functions under the hood - See their +docs (https://github.com/google/re2/wiki/Syntax) for the supported +syntax. +.PP +Case insensitive tip: prefix the regex with \f[C](?i)\f[R] - +e.g.\ \f[C]test(\[dq](?i)cats)\[dq]\f[R]. +.SS match(regEx) +.PP +This operator returns the substring match details of the given regEx. +.SS capture(regEx) +.PP +Capture returns named RegEx capture groups in a map. +Can be more convenient than \f[C]match\f[R] depending on what you are +doing. +.SS test(regEx) +.PP +Returns true if the string matches the RegEx, false otherwise. +.SS sub(regEx, replacement) +.PP +Substitutes matched substrings. +The first parameter is the regEx to match substrings within the original +string. +The second parameter specifies what to replace those matches with. +This can refer to capture groups from the first RegEx. +.SS String blocks, bash and newlines +.PP +Bash is notorious for chomping on precious trailing newline characters, +making it tricky to set strings with newlines properly. +In particular, the \f[C]$( exp )\f[R] \f[I]will trim trailing +newlines\f[R]. +.PP +For instance to get this yaml: +.IP +.nf +\f[C] +a: | + cat +\f[R] +.fi +.PP +Using \f[C]$( exp )\f[R] wont work, as it will trim the trailing +newline. +.IP +.nf +\f[C] +m=$(echo \[dq]cat\[rs]n\[dq]) yq -n \[aq].a = strenv(m)\[aq] +a: cat +\f[R] +.fi +.PP +However, using printf works: +.IP +.nf +\f[C] +printf -v m \[dq]cat\[rs]n\[dq] ; m=\[dq]$m\[dq] yq -n \[aq].a = strenv(m)\[aq] +a: | + cat +\f[R] +.fi +.PP +As well as having multiline expressions: +.IP +.nf +\f[C] +m=\[dq]cat +\[dq] yq -n \[aq].a = strenv(m)\[aq] +a: | + cat +\f[R] +.fi +.PP +Similarly, if you\[cq]re trying to set the content from a file, and want +a trailing newline: +.IP +.nf +\f[C] +IFS= read -rd \[aq]\[aq] output < <(cat my_file) +output=$output ./yq \[aq].data.values = strenv(output)\[aq] first.yml +\f[R] +.fi +.SS Interpolation +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +value: things +another: stuff +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].message = \[dq]I like \[rs](.value) and \[rs](.another)\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +value: things +another: stuff +message: I like things and stuff +\f[R] +.fi +.SS Interpolation - not a string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +value: + an: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].message = \[dq]I like \[rs](.value)\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +value: + an: apple +message: \[aq]I like an: apple\[aq] +\f[R] +.fi +.SS To up (upper) case +.PP +Works with unicode characters +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +\['a]gua +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]upcase\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +\['A]GUA +\f[R] +.fi +.SS To down (lower) case +.PP +Works with unicode characters +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +\['A]gUA +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]downcase\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +\['a]gua +\f[R] +.fi +.SS Join strings +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- meow +- 1 +- null +- true +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]join(\[dq]; \[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat; meow; 1; ; true +\f[R] +.fi +.SS Trim strings +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- \[aq] cat\[aq] +- \[aq]dog \[aq] +- \[aq] cow cow \[aq] +- horse +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | trim\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat +dog +cow cow +horse +\f[R] +.fi +.SS Match string +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foo bar foo +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]match(\[dq]foo\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +string: foo +offset: 0 +length: 3 +captures: [] +\f[R] +.fi +.SS Match string, case insensitive +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foo bar FOO +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][match(\[dq](?i)foo\[dq]; \[dq]g\[dq])]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- string: foo + offset: 0 + length: 3 + captures: [] +- string: FOO + offset: 8 + length: 3 + captures: [] +\f[R] +.fi +.SS Match with global capture group +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +abc abc +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][match(\[dq](ab)(c)\[dq]; \[dq]g\[dq])]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- string: abc + offset: 0 + length: 3 + captures: + - string: ab + offset: 0 + length: 2 + - string: c + offset: 2 + length: 1 +- string: abc + offset: 4 + length: 3 + captures: + - string: ab + offset: 4 + length: 2 + - string: c + offset: 6 + length: 1 +\f[R] +.fi +.SS Match with named capture groups +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foo bar foo foo foo +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][match(\[dq]foo (?P<bar123>bar)? foo\[dq]; \[dq]g\[dq])]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- string: foo bar foo + offset: 0 + length: 11 + captures: + - string: bar + offset: 4 + length: 3 + name: bar123 +- string: foo foo + offset: 12 + length: 8 + captures: + - string: null + offset: -1 + length: 0 + name: bar123 +\f[R] +.fi +.SS Capture named groups into a map +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +xyzzy-14 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]capture(\[dq](?P<a>[a-z]+)-(?P<n>[0-9]+)\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: xyzzy +n: \[dq]14\[dq] +\f[R] +.fi +.SS Match without global flag +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cat cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]match(\[dq]cat\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +string: cat +offset: 0 +length: 3 +captures: [] +\f[R] +.fi +.SS Match with global flag +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cat cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][match(\[dq]cat\[dq]; \[dq]g\[dq])]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- string: cat + offset: 0 + length: 3 + captures: [] +- string: cat + offset: 4 + length: 3 + captures: [] +\f[R] +.fi +.SS Test using regex +.PP +Like jq\[cq]s equivalent, this works like match but only returns +true/false instead of full match details +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | test(\[dq]at\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +true +false +\f[R] +.fi +.SS Substitute / Replace string +.PP +This uses Golang\[cq]s regex, described +here (https://github.com/google/re2/wiki/Syntax). +Note the use of \f[C]|=\f[R] to run in context of the current string +value. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: dogs are great +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a |= sub(\[dq]dogs\[dq], \[dq]cats\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cats are great +\f[R] +.fi +.SS Substitute / Replace string with regex +.PP +This uses Golang\[cq]s regex, described +here (https://github.com/google/re2/wiki/Syntax). +Note the use of \f[C]|=\f[R] to run in context of the current string +value. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: heat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] |= sub(\[dq](a)\[dq], \[dq]${1}r\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cart +b: heart +\f[R] +.fi +.SS Custom types: that are really strings +.PP +When custom tags are encountered, yq will try to decode the underlying +type. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: !horse cat +b: !goat heat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] |= sub(\[dq](a)\[dq], \[dq]${1}r\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !horse cart +b: !goat heart +\f[R] +.fi +.SS Split strings +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cat; meow; 1; ; true +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]split(\[dq]; \[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- cat +- meow +- \[dq]1\[dq] +- \[dq]\[dq] +- \[dq]true\[dq] +\f[R] +.fi +.SS Split strings one match +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +word +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]split(\[dq]; \[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- word +\f[R] +.fi +.SS To string +.PP +Note that you may want to force \f[C]yq\f[R] to leave scalar values +wrapped by passing in \f[C]--unwrapScalar=false\f[R] or \f[C]-r=f\f[R] +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 1 +- true +- null +- \[ti] +- cat +- an: object +- - array + - 2 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] |= to_string\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- \[dq]1\[dq] +- \[dq]true\[dq] +- \[dq]null\[dq] +- \[dq]\[ti]\[dq] +- cat +- \[dq]an: object\[dq] +- \[dq]- array\[rs]n- 2\[dq] +\f[R] +.fi +.SH Style +.PP +The style operator can be used to get or set the style of nodes +(e.g.\ string style, yaml style). +Use this to control the formatting of the document in yaml. +.SS Update and set style of a particular node (simple) +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: thing + c: something +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.b = \[dq]new\[dq] | .a.b style=\[dq]double\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: \[dq]new\[dq] + c: something +\f[R] +.fi +.SS Update and set style of a particular node using path variables +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: thing + c: something +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with(.a.b ; . = \[dq]new\[dq] | . style=\[dq]double\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: \[dq]new\[dq] + c: something +\f[R] +.fi +.SS Set tagged style +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: 5 +c: 3.2 +e: true +f: + - 1 + - 2 + - 3 +g: + something: cool +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. style=\[dq]tagged\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +!!map +a: !!str cat +b: !!int 5 +c: !!float 3.2 +e: !!bool true +f: !!seq + - !!int 1 + - !!int 2 + - !!int 3 +g: !!map + something: !!str cool +\f[R] +.fi +.SS Set double quote style +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: 5 +c: 3.2 +e: true +f: + - 1 + - 2 + - 3 +g: + something: cool +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. style=\[dq]double\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: \[dq]cat\[dq] +b: \[dq]5\[dq] +c: \[dq]3.2\[dq] +e: \[dq]true\[dq] +f: + - \[dq]1\[dq] + - \[dq]2\[dq] + - \[dq]3\[dq] +g: + something: \[dq]cool\[dq] +\f[R] +.fi +.SS Set double quote style on map keys too +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: 5 +c: 3.2 +e: true +f: + - 1 + - 2 + - 3 +g: + something: cool +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]... style=\[dq]double\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +\[dq]a\[dq]: \[dq]cat\[dq] +\[dq]b\[dq]: \[dq]5\[dq] +\[dq]c\[dq]: \[dq]3.2\[dq] +\[dq]e\[dq]: \[dq]true\[dq] +\[dq]f\[dq]: + - \[dq]1\[dq] + - \[dq]2\[dq] + - \[dq]3\[dq] +\[dq]g\[dq]: + \[dq]something\[dq]: \[dq]cool\[dq] +\f[R] +.fi +.SS Set single quote style +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: 5 +c: 3.2 +e: true +f: + - 1 + - 2 + - 3 +g: + something: cool +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. style=\[dq]single\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: \[aq]cat\[aq] +b: \[aq]5\[aq] +c: \[aq]3.2\[aq] +e: \[aq]true\[aq] +f: + - \[aq]1\[aq] + - \[aq]2\[aq] + - \[aq]3\[aq] +g: + something: \[aq]cool\[aq] +\f[R] +.fi +.SS Set literal quote style +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: 5 +c: 3.2 +e: true +f: + - 1 + - 2 + - 3 +g: + something: cool +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. style=\[dq]literal\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: |- + cat +b: |- + 5 +c: |- + 3.2 +e: |- + true +f: + - |- + 1 + - |- + 2 + - |- + 3 +g: + something: |- + cool +\f[R] +.fi +.SS Set folded quote style +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: 5 +c: 3.2 +e: true +f: + - 1 + - 2 + - 3 +g: + something: cool +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. style=\[dq]folded\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: >- + cat +b: >- + 5 +c: >- + 3.2 +e: >- + true +f: + - >- + 1 + - >- + 2 + - >- + 3 +g: + something: >- + cool +\f[R] +.fi +.SS Set flow quote style +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: 5 +c: 3.2 +e: true +f: + - 1 + - 2 + - 3 +g: + something: cool +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. style=\[dq]flow\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +{a: cat, b: 5, c: 3.2, e: true, f: [1, 2, 3], g: {something: cool}} +\f[R] +.fi +.SS Reset style - or pretty print +.PP +Set empty (default) quote style, note the usage of \f[C]...\f[R] to +match keys too. +Note that there is a \f[C]--prettyPrint/-P\f[R] short flag for this. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +{a: cat, \[dq]b\[dq]: 5, \[aq]c\[aq]: 3.2, \[dq]e\[dq]: true, f: [1,2,3], \[dq]g\[dq]: { something: \[dq]cool\[dq]} } +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]... style=\[dq]\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat +b: 5 +c: 3.2 +e: true +f: + - 1 + - 2 + - 3 +g: + something: cool +\f[R] +.fi +.SS Set style relatively with assign-update +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: single +b: double +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] style |= .\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: \[aq]single\[aq] +b: \[dq]double\[dq] +\f[R] +.fi +.SS Read style +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +{a: \[dq]cat\[dq], b: \[aq]thing\[aq]} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. | style\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +flow +double +single +\f[R] +.fi +.SH Subtract +.PP +You can use subtract to subtract numbers as well as remove elements from +an array. +.SS Array subtraction +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq][1,2] - [2,3]\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 1 +\f[R] +.fi +.SS Array subtraction with nested array +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq][[1], 1, 2] - [[1], 3]\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 1 +- 2 +\f[R] +.fi +.SS Array subtraction with nested object +.PP +Note that order of the keys does not matter +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- a: b + c: d +- a: b +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]. - [{\[dq]c\[dq]: \[dq]d\[dq], \[dq]a\[dq]: \[dq]b\[dq]}]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- a: b +\f[R] +.fi +.SS Number subtraction - float +.PP +If the lhs or rhs are floats then the expression will be calculated with +floats. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 3 +b: 4.5 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .a - .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: -1.5 +b: 4.5 +\f[R] +.fi +.SS Number subtraction - int +.PP +If both the lhs and rhs are ints then the expression will be calculated +with ints. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 3 +b: 4 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a = .a - .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: -1 +b: 4 +\f[R] +.fi +.SS Decrement numbers +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 3 +b: 5 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] -= 1\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 2 +b: 4 +\f[R] +.fi +.SS Date subtraction +.PP +You can subtract durations from dates. +Assumes RFC3339 date time format, see date-time +operators (https://mikefarah.gitbook.io/yq/operators/date-time-operators) +for more information. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: 2021-01-01T03:10:00Z +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a -= \[dq]3h10m\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: 2021-01-01T00:00:00Z +\f[R] +.fi +.SS Date subtraction - custom format +.PP +Use with_dtf to specify your datetime format. +See date-time +operators (https://mikefarah.gitbook.io/yq/operators/date-time-operators) +for more information. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 6:00AM GMT +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with_dtf(\[dq]Monday, 02-Jan-06 at 3:04PM MST\[dq], .a -= \[dq]3h1m\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: Saturday, 15-Dec-01 at 2:59AM GMT +\f[R] +.fi +.SS Custom types: that are really numbers +.PP +When custom tags are encountered, yq will try to decode the underlying +type. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: !horse 2 +b: !goat 1 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a -= .b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !horse 1 +b: !goat 1 +\f[R] +.fi +.SH Tag +.PP +The tag operator can be used to get or set the tag of nodes +(e.g.\ \f[C]!!str\f[R], \f[C]!!int\f[R], \f[C]!!bool\f[R]). +.SS Get tag +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: 5 +c: 3.2 +e: true +f: [] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. | tag\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +!!map +!!str +!!int +!!float +!!bool +!!seq +\f[R] +.fi +.SS type is an alias for tag +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: 5 +c: 3.2 +e: true +f: [] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. | type\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +!!map +!!str +!!int +!!float +!!bool +!!seq +\f[R] +.fi +.SS Set custom tag +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: str +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a tag = \[dq]!!mikefarah\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: !!mikefarah str +\f[R] +.fi +.SS Find numbers and convert them to strings +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +b: 5 +c: 3.2 +e: true +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.. | select(tag == \[dq]!!int\[dq])) tag= \[dq]!!str\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: cat +b: \[dq]5\[dq] +c: 3.2 +e: true +\f[R] +.fi +.SH To Number +.PP +Parses the input as a number. +yq will try to parse values as an int first, failing that it will try +float. +Values that already ints or floats will be left alone. +.SS Converts strings to numbers +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- \[dq]3\[dq] +- \[dq]3.1\[dq] +- \[dq]-1e3\[dq] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | to_number\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +3 +3.1 +-1e3 +\f[R] +.fi +.SS Doesn\[cq]t change numbers +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 3 +- 3.1 +- -1e3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | to_number\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +3 +3.1 +-1e3 +\f[R] +.fi +.SS Cannot convert null +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq].a.b | to_number\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Error: cannot convert node value [null] at path a.b of tag !!null to number +\f[R] +.fi +.SH Traverse (Read) +.PP +This is the simplest (and perhaps most used) operator. +It is used to navigate deeply into yaml structures. +.SS Simple map navigation +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +b: apple +\f[R] +.fi +.SS Splat +.PP +Often used to pipe children into other operators +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- b: apple +- c: banana +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +b: apple +c: banana +\f[R] +.fi +.SS Optional Splat +.PP +Just like splat, but won\[cq]t error if you run it against scalars +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +\f[R] +.fi +.SS Special characters +.PP +Use quotes with square brackets around path elements with special +characters +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +\[dq]{}\[dq]: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[\[dq]{}\[dq]]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +frog +\f[R] +.fi +.SS Nested special characters +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + \[dq]key.withdots\[dq]: + \[dq]another.key\[dq]: apple +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a[\[dq]key.withdots\[dq]][\[dq]another.key\[dq]]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +apple +\f[R] +.fi +.SS Keys with spaces +.PP +Use quotes with square brackets around path elements with special +characters +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +\[dq]red rabbit\[dq]: frog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[\[dq]red rabbit\[dq]]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +frog +\f[R] +.fi +.SS Dynamic keys +.PP +Expressions within [] can be used to dynamically lookup / calculate keys +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +b: apple +apple: crispy yum +banana: soft yum +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[.b]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +crispy yum +\f[R] +.fi +.SS Children don\[cq]t exist +.PP +Nodes are added dynamically while traversing +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +c: banana +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +null +\f[R] +.fi +.SS Optional identifier +.PP +Like jq, does not output an error when the yaml is not an array or +object as expected +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 1 +- 2 +- 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a?\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +\f[R] +.fi +.SS Wildcard matching +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + cat: apple + mad: things +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.\[dq]*a*\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +apple +things +\f[R] +.fi +.SS Aliases +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: &cat + c: frog +b: *cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +*cat +\f[R] +.fi +.SS Traversing aliases with splat +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: &cat + c: frog +b: *cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b[]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +frog +\f[R] +.fi +.SS Traversing aliases explicitly +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: &cat + c: frog +b: *cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].b.c\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +frog +\f[R] +.fi +.SS Traversing arrays by index +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 1 +- 2 +- 3 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[0]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +1 +\f[R] +.fi +.SS Traversing nested arrays by index +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +[[], [cat]] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[1][0]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat +\f[R] +.fi +.SS Maps with numeric keys +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +2: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[2]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat +\f[R] +.fi +.SS Maps with non existing numeric keys +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: b +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[0]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +null +\f[R] +.fi +.SS Traversing merge anchors +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foo: &foo + a: foo_a + thing: foo_thing + c: foo_c +bar: &bar + b: bar_b + thing: bar_thing + c: bar_c +foobarList: + b: foobarList_b + !!merge <<: + - *foo + - *bar + c: foobarList_c +foobar: + c: foobar_c + !!merge <<: *foo + thing: foobar_thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].foobar.a\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +foo_a +\f[R] +.fi +.SS Traversing merge anchors with override +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foo: &foo + a: foo_a + thing: foo_thing + c: foo_c +bar: &bar + b: bar_b + thing: bar_thing + c: bar_c +foobarList: + b: foobarList_b + !!merge <<: + - *foo + - *bar + c: foobarList_c +foobar: + c: foobar_c + !!merge <<: *foo + thing: foobar_thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].foobar.c\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +foo_c +\f[R] +.fi +.SS Traversing merge anchors with local override +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foo: &foo + a: foo_a + thing: foo_thing + c: foo_c +bar: &bar + b: bar_b + thing: bar_thing + c: bar_c +foobarList: + b: foobarList_b + !!merge <<: + - *foo + - *bar + c: foobarList_c +foobar: + c: foobar_c + !!merge <<: *foo + thing: foobar_thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].foobar.thing\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +foobar_thing +\f[R] +.fi +.SS Splatting merge anchors +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foo: &foo + a: foo_a + thing: foo_thing + c: foo_c +bar: &bar + b: bar_b + thing: bar_thing + c: bar_c +foobarList: + b: foobarList_b + !!merge <<: + - *foo + - *bar + c: foobarList_c +foobar: + c: foobar_c + !!merge <<: *foo + thing: foobar_thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].foobar[]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +foo_c +foo_a +foobar_thing +\f[R] +.fi +.SS Traversing merge anchor lists +.PP +Note that the later merge anchors override previous +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foo: &foo + a: foo_a + thing: foo_thing + c: foo_c +bar: &bar + b: bar_b + thing: bar_thing + c: bar_c +foobarList: + b: foobarList_b + !!merge <<: + - *foo + - *bar + c: foobarList_c +foobar: + c: foobar_c + !!merge <<: *foo + thing: foobar_thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].foobarList.thing\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +bar_thing +\f[R] +.fi +.SS Splatting merge anchor lists +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +foo: &foo + a: foo_a + thing: foo_thing + c: foo_c +bar: &bar + b: bar_b + thing: bar_thing + c: bar_c +foobarList: + b: foobarList_b + !!merge <<: + - *foo + - *bar + c: foobarList_c +foobar: + c: foobar_c + !!merge <<: *foo + thing: foobar_thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].foobarList[]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +bar_b +foo_a +bar_thing +foobarList_c +\f[R] +.fi +.SS Select multiple indices +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + - a + - b + - c +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a[0, 2]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a +c +\f[R] +.fi +.SH Union +.PP +This operator is used to combine different results together. +.SS Combine scalars +.PP +Running +.IP +.nf +\f[C] +yq --null-input \[aq]1, true, \[dq]cat\[dq]\[aq] +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +1 +true +cat +\f[R] +.fi +.SS Combine selected paths +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: fieldA +b: fieldB +c: fieldC +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a, .c\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +fieldA +fieldC +\f[R] +.fi +.SH Unique +.PP +This is used to filter out duplicated items in an array. +Note that the original order of the array is maintained. +.SS Unique array of scalars (string/numbers) +.PP +Note that unique maintains the original order of the array. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- 2 +- 1 +- 3 +- 2 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]unique\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- 2 +- 1 +- 3 +\f[R] +.fi +.SS Unique nulls +.PP +Unique works on the node value, so it considers different +representations of nulls to be different +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- \[ti] +- null +- \[ti] +- null +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]unique\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- \[ti] +- null +\f[R] +.fi +.SS Unique all nulls +.PP +Run against the node tag to unique all the nulls +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- \[ti] +- null +- \[ti] +- null +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]unique_by(tag)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- \[ti] +\f[R] +.fi +.SS Unique array objects +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- name: harry + pet: cat +- name: billy + pet: dog +- name: harry + pet: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]unique\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- name: harry + pet: cat +- name: billy + pet: dog +\f[R] +.fi +.SS Unique array of objects by a field +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- name: harry + pet: cat +- name: billy + pet: dog +- name: harry + pet: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]unique_by(.name)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- name: harry + pet: cat +- name: billy + pet: dog +\f[R] +.fi +.SS Unique array of arrays +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- - cat + - dog +- - cat + - sheep +- - cat + - dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]unique\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- - cat + - dog +- - cat + - sheep +\f[R] +.fi +.SH Variable Operators +.PP +Like the \f[C]jq\f[R] equivalents, variables are sometimes required for +the more complex expressions (or swapping values between fields). +.PP +Note that there is also an additional \f[C]ref\f[R] operator that holds +a reference (instead of a copy) of the path, allowing you to make +multiple changes to the same path. +.SS Single value variable +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a as $foo | $foo\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat +\f[R] +.fi +.SS Multi value variable +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- cat +- dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] as $foo | $foo\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat +dog +\f[R] +.fi +.SS Using variables as a lookup +.PP +Example taken from +jq (https://stedolan.github.io/jq/manual/#Variable/SymbolicBindingOperator:...as$identifier%7C...) +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +\[dq]posts\[dq]: + - \[dq]title\[dq]: First post + \[dq]author\[dq]: anon + - \[dq]title\[dq]: A well-written article + \[dq]author\[dq]: person1 +\[dq]realnames\[dq]: + \[dq]anon\[dq]: Anonymous Coward + \[dq]person1\[dq]: Person McPherson +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].realnames as $names | .posts[] | {\[dq]title\[dq]:.title, \[dq]author\[dq]: $names[.author]}\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +title: First post +author: Anonymous Coward +title: A well-written article +author: Person McPherson +\f[R] +.fi +.SS Using variables to swap values +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: a_value +b: b_value +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a as $x | .b as $y | .b = $x | .a = $y\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: b_value +b: a_value +\f[R] +.fi +.SS Use ref to reference a path repeatedly +.PP +Note: You may find the \f[C]with\f[R] operator more useful. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + b: thing + c: something +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].a.b ref $x | $x = \[dq]new\[dq] | $x style=\[dq]double\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: \[dq]new\[dq] + c: something +\f[R] +.fi +.SH With +.PP +Use the \f[C]with\f[R] operator to conveniently make multiple updates to +a deeply nested path, or to update array elements relatively to each +other. +The first argument expression sets the root context, and the second +expression runs against that root context. +.SS Update and style +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + deeply: + nested: value +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with(.a.deeply.nested; . = \[dq]newValue\[dq] | . style=\[dq]single\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + deeply: + nested: \[aq]newValue\[aq] +\f[R] +.fi +.SS Update multiple deeply nested properties +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +a: + deeply: + nested: value + other: thing +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with(.a.deeply; .nested = \[dq]newValue\[dq] | .other= \[dq]newThing\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + deeply: + nested: newValue + other: newThing +\f[R] +.fi +.SS Update array elements relatively +.PP +The second expression runs with each element of the array as it\[cq]s +contextual root. +This allows you to make updates relative to the element. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +myArray: + - a: apple + - a: banana +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with(.myArray[]; .b = .a + \[dq] yum\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +myArray: + - a: apple + b: apple yum + - a: banana + b: banana yum +\f[R] +.fi +.SH JSON +.PP +Encode and decode to and from JSON. +Supports multiple JSON documents in a single file (e.g.\ NDJSON). +.PP +Note that YAML is a superset of (single document) JSON - so you +don\[cq]t have to use the JSON parser to read JSON when there is only +one JSON document in the input. +You will probably want to pretty print the result in this case, to get +idiomatic YAML styling. +.SS Parse json: simple +.PP +JSON is a subset of yaml, so all you need to do is prettify the output +.PP +Given a sample.json file of: +.IP +.nf +\f[C] +{\[dq]cat\[dq]: \[dq]meow\[dq]} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=json sample.json +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +cat: meow +\f[R] +.fi +.SS Parse json: complex +.PP +JSON is a subset of yaml, so all you need to do is prettify the output +.PP +Given a sample.json file of: +.IP +.nf +\f[C] +{\[dq]a\[dq]:\[dq]Easy! as one two three\[dq],\[dq]b\[dq]:{\[dq]c\[dq]:2,\[dq]d\[dq]:[3,4]}} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=json sample.json +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: Easy! as one two three +b: + c: 2 + d: + - 3 + - 4 +\f[R] +.fi +.SS Encode json: simple +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cat: meow +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=json \[aq].\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +{ + \[dq]cat\[dq]: \[dq]meow\[dq] +} +\f[R] +.fi +.SS Encode json: simple - in one line +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cat: meow # this is a comment, and it will be dropped. +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=json -I=0 \[aq].\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +{\[dq]cat\[dq]:\[dq]meow\[dq]} +\f[R] +.fi +.SS Encode json: comments +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cat: meow # this is a comment, and it will be dropped. +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=json \[aq].\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +{ + \[dq]cat\[dq]: \[dq]meow\[dq] +} +\f[R] +.fi +.SS Encode json: anchors +.PP +Anchors are dereferenced +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cat: &ref meow +anotherCat: *ref +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=json \[aq].\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +{ + \[dq]cat\[dq]: \[dq]meow\[dq], + \[dq]anotherCat\[dq]: \[dq]meow\[dq] +} +\f[R] +.fi +.SS Encode json: multiple results +.PP +Each matching node is converted into a json doc. +This is best used with 0 indent (json document per line) +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +things: [{stuff: cool}, {whatever: cat}] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=json -I=0 \[aq].things[]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +{\[dq]stuff\[dq]:\[dq]cool\[dq]} +{\[dq]whatever\[dq]:\[dq]cat\[dq]} +\f[R] +.fi +.SS Roundtrip JSON Lines / NDJSON +.PP +Given a sample.json file of: +.IP +.nf +\f[C] +{\[dq]this\[dq]: \[dq]is a multidoc json file\[dq]} +{\[dq]each\[dq]: [\[dq]line is a valid json document\[dq]]} +{\[dq]a number\[dq]: 4} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=json -o=json -I=0 sample.json +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +{\[dq]this\[dq]:\[dq]is a multidoc json file\[dq]} +{\[dq]each\[dq]:[\[dq]line is a valid json document\[dq]]} +{\[dq]a number\[dq]:4} +\f[R] +.fi +.SS Roundtrip multi-document JSON +.PP +The parser can also handle multiple multi-line json documents in a +single file (despite this not being in the JSON Lines / NDJSON spec). +Typically you would have one entire JSON document per line, but the +parser also supports multiple multi-line json documents +.PP +Given a sample.json file of: +.IP +.nf +\f[C] +{ + \[dq]this\[dq]: \[dq]is a multidoc json file\[dq] +} +{ + \[dq]it\[dq]: [ + \[dq]has\[dq], + \[dq]consecutive\[dq], + \[dq]json documents\[dq] + ] +} +{ + \[dq]a number\[dq]: 4 +} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=json -o=json -I=2 sample.json +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +{ + \[dq]this\[dq]: \[dq]is a multidoc json file\[dq] +} +{ + \[dq]it\[dq]: [ + \[dq]has\[dq], + \[dq]consecutive\[dq], + \[dq]json documents\[dq] + ] +} +{ + \[dq]a number\[dq]: 4 +} +\f[R] +.fi +.SS Update a specific document in a multi-document json +.PP +Documents are indexed by the \f[C]documentIndex\f[R] or \f[C]di\f[R] +operator. +.PP +Given a sample.json file of: +.IP +.nf +\f[C] +{\[dq]this\[dq]: \[dq]is a multidoc json file\[dq]} +{\[dq]each\[dq]: [\[dq]line is a valid json document\[dq]]} +{\[dq]a number\[dq]: 4} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=json -o=json -I=0 \[aq](select(di == 1) | .each ) += \[dq]cool\[dq]\[aq] sample.json +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +{\[dq]this\[dq]:\[dq]is a multidoc json file\[dq]} +{\[dq]each\[dq]:[\[dq]line is a valid json document\[dq],\[dq]cool\[dq]]} +{\[dq]a number\[dq]:4} +\f[R] +.fi +.SS Find and update a specific document in a multi-document json +.PP +Use expressions as you normally would. +.PP +Given a sample.json file of: +.IP +.nf +\f[C] +{\[dq]this\[dq]: \[dq]is a multidoc json file\[dq]} +{\[dq]each\[dq]: [\[dq]line is a valid json document\[dq]]} +{\[dq]a number\[dq]: 4} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=json -o=json -I=0 \[aq](select(has(\[dq]each\[dq])) | .each ) += \[dq]cool\[dq]\[aq] sample.json +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +{\[dq]this\[dq]:\[dq]is a multidoc json file\[dq]} +{\[dq]each\[dq]:[\[dq]line is a valid json document\[dq],\[dq]cool\[dq]]} +{\[dq]a number\[dq]:4} +\f[R] +.fi +.SS Decode JSON Lines / NDJSON +.PP +Given a sample.json file of: +.IP +.nf +\f[C] +{\[dq]this\[dq]: \[dq]is a multidoc json file\[dq]} +{\[dq]each\[dq]: [\[dq]line is a valid json document\[dq]]} +{\[dq]a number\[dq]: 4} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=json sample.json +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +this: is a multidoc json file +--- +each: + - line is a valid json document +--- +a number: 4 +\f[R] +.fi +.SH CSV +.PP +Encode/Decode/Roundtrip CSV and TSV files. +.SS Encode +.PP +Currently supports arrays of homogeneous flat objects, that is: no +nesting and it assumes the \f[I]first\f[R] object has all the keys +required: +.IP +.nf +\f[C] +- name: Bobo + type: dog +- name: Fifi + type: cat +\f[R] +.fi +.PP +As well as arrays of arrays of scalars (strings/numbers/booleans): +.IP +.nf +\f[C] +- [Bobo, dog] +- [Fifi, cat] +\f[R] +.fi +.SS Decode +.PP +Decode assumes the first CSV/TSV row is the header row, and all rows +beneath are the entries. +The data will be coded into an array of objects, using the header rows +as keys. +.IP +.nf +\f[C] +name,type +Bobo,dog +Fifi,cat +\f[R] +.fi +.SS Encode CSV simple +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- [i, like, csv] +- [because, excel, is, cool] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=csv sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +i,like,csv +because,excel,is,cool +\f[R] +.fi +.SS Encode TSV simple +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- [i, like, csv] +- [because, excel, is, cool] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=tsv sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +i like csv +because excel is cool +\f[R] +.fi +.SS Encode array of objects to csv +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- name: Gary + numberOfCats: 1 + likesApples: true + height: 168.8 +- name: Samantha\[aq]s Rabbit + numberOfCats: 2 + likesApples: false + height: -188.8 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=csv sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +name,numberOfCats,likesApples,height +Gary,1,true,168.8 +Samantha\[aq]s Rabbit,2,false,-188.8 +\f[R] +.fi +.SS Encode array of objects to custom csv format +.PP +Add the header row manually, then the we convert each object into an +array of values - resulting in an array of arrays. +Pick the columns and call the header whatever you like. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- name: Gary + numberOfCats: 1 + likesApples: true + height: 168.8 +- name: Samantha\[aq]s Rabbit + numberOfCats: 2 + likesApples: false + height: -188.8 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=csv \[aq][[\[dq]Name\[dq], \[dq]Number of Cats\[dq]]] + [.[] | [.name, .numberOfCats ]]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +Name,Number of Cats +Gary,1 +Samantha\[aq]s Rabbit,2 +\f[R] +.fi +.SS Encode array of objects to csv - missing fields behaviour +.PP +First entry is used to determine the headers, and it is missing +`likesApples', so it is not included in the csv. +Second entry does not have `numberOfCats' so that is blank +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- name: Gary + numberOfCats: 1 + height: 168.8 +- name: Samantha\[aq]s Rabbit + height: -188.8 + likesApples: false +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=csv sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +name,numberOfCats,height +Gary,1,168.8 +Samantha\[aq]s Rabbit,,-188.8 +\f[R] +.fi +.SS Parse CSV into an array of objects +.PP +First row is assumed to be the header row. +By default, entries with YAML/JSON formatting will be parsed! +.PP +Given a sample.csv file of: +.IP +.nf +\f[C] +name,numberOfCats,likesApples,height,facts +Gary,1,true,168.8,cool: true +Samantha\[aq]s Rabbit,2,false,-188.8,tall: indeed +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=csv sample.csv +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- name: Gary + numberOfCats: 1 + likesApples: true + height: 168.8 + facts: + cool: true +- name: Samantha\[aq]s Rabbit + numberOfCats: 2 + likesApples: false + height: -188.8 + facts: + tall: indeed +\f[R] +.fi +.SS Parse CSV into an array of objects, no auto-parsing +.PP +First row is assumed to be the header row. +Entries with YAML/JSON will be left as strings. +.PP +Given a sample.csv file of: +.IP +.nf +\f[C] +name,numberOfCats,likesApples,height,facts +Gary,1,true,168.8,cool: true +Samantha\[aq]s Rabbit,2,false,-188.8,tall: indeed +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=csv --csv-auto-parse=f sample.csv +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- name: Gary + numberOfCats: 1 + likesApples: true + height: 168.8 + facts: \[aq]cool: true\[aq] +- name: Samantha\[aq]s Rabbit + numberOfCats: 2 + likesApples: false + height: -188.8 + facts: \[aq]tall: indeed\[aq] +\f[R] +.fi +.SS Parse TSV into an array of objects +.PP +First row is assumed to be the header row. +.PP +Given a sample.tsv file of: +.IP +.nf +\f[C] +name numberOfCats likesApples height +Gary 1 true 168.8 +Samantha\[aq]s Rabbit 2 false -188.8 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=tsv sample.tsv +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- name: Gary + numberOfCats: 1 + likesApples: true + height: 168.8 +- name: Samantha\[aq]s Rabbit + numberOfCats: 2 + likesApples: false + height: -188.8 +\f[R] +.fi +.SS Round trip +.PP +Given a sample.csv file of: +.IP +.nf +\f[C] +name,numberOfCats,likesApples,height +Gary,1,true,168.8 +Samantha\[aq]s Rabbit,2,false,-188.8 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=csv -o=csv \[aq](.[] | select(.name == \[dq]Gary\[dq]) | .numberOfCats) = 3\[aq] sample.csv +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +name,numberOfCats,likesApples,height +Gary,3,true,168.8 +Samantha\[aq]s Rabbit,2,false,-188.8 +\f[R] +.fi +.SH Formatting Expressions +.PP +\f[C]From version v4.41+\f[R] +.PP +You can put expressions into \f[C].yq\f[R] files, use whitespace and +comments to break up complex expressions and explain what\[cq]s going +on. +.SS Using expression files and comments +.PP +Note that you can execute the file directly - but make sure you make the +expression file executable. +.PP +Given a sample.yaml file of: +.IP +.nf +\f[C] +a: + b: old +\f[R] +.fi +.PP +And an `update.yq' expression file of: +.IP +.nf +\f[C] +#! yq + +# This is a yq expression that updates the map +# for several great reasons outlined here. + +\&.a.b = \[dq]new\[dq] # line comment here +| .a.c = \[dq]frog\[dq] + +# Now good things will happen. +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +\&./update.yq sample.yaml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: new + c: frog +\f[R] +.fi +.SS Flags in expression files +.PP +You can specify flags on the shebang line, this only works when +executing the file directly. +.PP +Given a sample.yaml file of: +.IP +.nf +\f[C] +a: + b: old +\f[R] +.fi +.PP +And an `update.yq' expression file of: +.IP +.nf +\f[C] +#! yq -oj + +# This is a yq expression that updates the map +# for several great reasons outlined here. + +\&.a.b = \[dq]new\[dq] # line comment here +| .a.c = \[dq]frog\[dq] + +# Now good things will happen. +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +\&./update.yq sample.yaml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +{ + \[dq]a\[dq]: { + \[dq]b\[dq]: \[dq]new\[dq], + \[dq]c\[dq]: \[dq]frog\[dq] + } +} +\f[R] +.fi +.SS Commenting out yq expressions +.PP +Note that \f[C]c\f[R] is no longer set to `frog'. +In this example we\[cq]re calling yq directly and passing the expression +file into \f[C]--from-file\f[R], this is no different from executing the +expression file directly. +.PP +Given a sample.yaml file of: +.IP +.nf +\f[C] +a: + b: old +\f[R] +.fi +.PP +And an `update.yq' expression file of: +.IP +.nf +\f[C] +#! yq +# This is a yq expression that updates the map +# for several great reasons outlined here. + +\&.a.b = \[dq]new\[dq] # line comment here +# | .a.c = \[dq]frog\[dq] + +# Now good things will happen. +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq --from-file update.yq sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: new +\f[R] +.fi +.SS Basic input example +.PP +Given a sample.lua file of: +.IP +.nf +\f[C] +return { + [\[dq]country\[dq]] = \[dq]Australia\[dq]; -- this place + [\[dq]cities\[dq]] = { + \[dq]Sydney\[dq], + \[dq]Melbourne\[dq], + \[dq]Brisbane\[dq], + \[dq]Perth\[dq], + }; +}; +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].\[aq] sample.lua +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +country: Australia +cities: + - Sydney + - Melbourne + - Brisbane + - Perth +\f[R] +.fi +.SS Basic output example +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +--- +country: Australia # this place +cities: +- Sydney +- Melbourne +- Brisbane +- Perth +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=lua \[aq].\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +return { + [\[dq]country\[dq]] = \[dq]Australia\[dq]; -- this place + [\[dq]cities\[dq]] = { + \[dq]Sydney\[dq], + \[dq]Melbourne\[dq], + \[dq]Brisbane\[dq], + \[dq]Perth\[dq], + }; +}; +\f[R] +.fi +.SS Unquoted keys +.PP +Uses the \f[C]--lua-unquoted\f[R] option to produce a nicer-looking +output. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +--- +country: Australia # this place +cities: +- Sydney +- Melbourne +- Brisbane +- Perth +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=lua --lua-unquoted \[aq].\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +return { + country = \[dq]Australia\[dq]; -- this place + cities = { + \[dq]Sydney\[dq], + \[dq]Melbourne\[dq], + \[dq]Brisbane\[dq], + \[dq]Perth\[dq], + }; +}; +\f[R] +.fi +.SS Globals +.PP +Uses the \f[C]--lua-globals\f[R] option to export the values into the +global scope. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +--- +country: Australia # this place +cities: +- Sydney +- Melbourne +- Brisbane +- Perth +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=lua --lua-globals \[aq].\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +country = \[dq]Australia\[dq]; -- this place +cities = { + \[dq]Sydney\[dq], + \[dq]Melbourne\[dq], + \[dq]Brisbane\[dq], + \[dq]Perth\[dq], +}; +\f[R] +.fi +.SS Elaborate example +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +--- +hello: world +tables: + like: this + keys: values + ? look: non-string keys + : True +numbers: + - decimal: 12345 + - hex: 0x7fabc123 + - octal: 0o30 + - float: 123.45 + - infinity: .inf + plus_infinity: +.inf + minus_infinity: -.inf + - not: .nan +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=lua \[aq].\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +return { + [\[dq]hello\[dq]] = \[dq]world\[dq]; + [\[dq]tables\[dq]] = { + [\[dq]like\[dq]] = \[dq]this\[dq]; + [\[dq]keys\[dq]] = \[dq]values\[dq]; + [{ + [\[dq]look\[dq]] = \[dq]non-string keys\[dq]; + }] = true; + }; + [\[dq]numbers\[dq]] = { + { + [\[dq]decimal\[dq]] = 12345; + }, + { + [\[dq]hex\[dq]] = 0x7fabc123; + }, + { + [\[dq]octal\[dq]] = 24; + }, + { + [\[dq]float\[dq]] = 123.45; + }, + { + [\[dq]infinity\[dq]] = (1/0); + [\[dq]plus_infinity\[dq]] = (1/0); + [\[dq]minus_infinity\[dq]] = (-1/0); + }, + { + [\[dq]not\[dq]] = (0/0); + }, + }; +}; +\f[R] +.fi +.SH Properties +.PP +Encode/Decode/Roundtrip to/from a property file. +Line comments on value nodes will be copied across. +.PP +By default, empty maps and arrays are not encoded - see below for an +example on how to encode a value for these. +.SS Encode properties +.PP +Note that empty arrays and maps are not encoded by default. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# block comments come through +person: # neither do comments on maps + name: Mike Wazowski # comments on values appear + pets: + - cat # comments on array values appear + - nested: + - list entry + food: [pizza] # comments on arrays do not +emptyArray: [] +emptyMap: [] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=props sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +# block comments come through +# comments on values appear +person.name = Mike Wazowski + +# comments on array values appear +person.pets.0 = cat +person.pets.1.nested.0 = list entry +person.food.0 = pizza +\f[R] +.fi +.SS Encode properties with array brackets +.PP +Declare the \[en]properties-array-brackets flag to give array paths in +brackets (e.g.\ SpringBoot). +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# block comments come through +person: # neither do comments on maps + name: Mike Wazowski # comments on values appear + pets: + - cat # comments on array values appear + - nested: + - list entry + food: [pizza] # comments on arrays do not +emptyArray: [] +emptyMap: [] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=props --properties-array-brackets sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +# block comments come through +# comments on values appear +person.name = Mike Wazowski + +# comments on array values appear +person.pets[0] = cat +person.pets[1].nested[0] = list entry +person.food[0] = pizza +\f[R] +.fi +.SS Encode properties - custom separator +.PP +Use the \[en]properties-customer-separator flag to specify your own +key/value separator. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# block comments come through +person: # neither do comments on maps + name: Mike Wazowski # comments on values appear + pets: + - cat # comments on array values appear + - nested: + - list entry + food: [pizza] # comments on arrays do not +emptyArray: [] +emptyMap: [] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=props --properties-customer-separator=\[dq] :\[at] \[dq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +# block comments come through +# comments on values appear +person.name :\[at] Mike Wazowski + +# comments on array values appear +person.pets.0 :\[at] cat +person.pets.1.nested.0 :\[at] list entry +person.food.0 :\[at] pizza +\f[R] +.fi +.SS Encode properties: scalar encapsulation +.PP +Note that string values with blank characters in them are encapsulated +with double quotes +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# block comments come through +person: # neither do comments on maps + name: Mike Wazowski # comments on values appear + pets: + - cat # comments on array values appear + - nested: + - list entry + food: [pizza] # comments on arrays do not +emptyArray: [] +emptyMap: [] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=props --unwrapScalar=false sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +# block comments come through +# comments on values appear +person.name = \[dq]Mike Wazowski\[dq] + +# comments on array values appear +person.pets.0 = cat +person.pets.1.nested.0 = \[dq]list entry\[dq] +person.food.0 = pizza +\f[R] +.fi +.SS Encode properties: no comments +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# block comments come through +person: # neither do comments on maps + name: Mike Wazowski # comments on values appear + pets: + - cat # comments on array values appear + - nested: + - list entry + food: [pizza] # comments on arrays do not +emptyArray: [] +emptyMap: [] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=props \[aq]... comments = \[dq]\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +person.name = Mike Wazowski +person.pets.0 = cat +person.pets.1.nested.0 = list entry +person.food.0 = pizza +\f[R] +.fi +.SS Encode properties: include empty maps and arrays +.PP +Use a yq expression to set the empty maps and sequences to your desired +value. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# block comments come through +person: # neither do comments on maps + name: Mike Wazowski # comments on values appear + pets: + - cat # comments on array values appear + - nested: + - list entry + food: [pizza] # comments on arrays do not +emptyArray: [] +emptyMap: [] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=props \[aq](.. | select( (tag == \[dq]!!map\[dq] or tag ==\[dq]!!seq\[dq]) and length == 0)) = \[dq]\[dq]\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +# block comments come through +# comments on values appear +person.name = Mike Wazowski + +# comments on array values appear +person.pets.0 = cat +person.pets.1.nested.0 = list entry +person.food.0 = pizza +emptyArray = +emptyMap = +\f[R] +.fi +.SS Decode properties +.PP +Given a sample.properties file of: +.IP +.nf +\f[C] +# block comments come through +# comments on values appear +person.name = Mike Wazowski + +# comments on array values appear +person.pets.0 = cat +person.pets.1.nested.0 = list entry +person.food.0 = pizza +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=props sample.properties +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +person: + # block comments come through + # comments on values appear + name: Mike Wazowski + pets: + # comments on array values appear + - cat + - nested: + - list entry + food: + - pizza +\f[R] +.fi +.SS Decode properties: numbers +.PP +All values are assumed to be strings when parsing properties, but you +can use the \f[C]from_yaml\f[R] operator on all the strings values to +autoparse into the correct type. +.PP +Given a sample.properties file of: +.IP +.nf +\f[C] +a.b = 10 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=props \[aq] (.. | select(tag == \[dq]!!str\[dq])) |= from_yaml\[aq] sample.properties +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +a: + b: 10 +\f[R] +.fi +.SS Decode properties - array should be a map +.PP +If you have a numeric map key in your property files, use array_to_map +to convert them to maps. +.PP +Given a sample.properties file of: +.IP +.nf +\f[C] +things.10 = mike +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=props \[aq].things |= array_to_map\[aq] sample.properties +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +things: + 10: mike +\f[R] +.fi +.SS Roundtrip +.PP +Given a sample.properties file of: +.IP +.nf +\f[C] +# block comments come through +# comments on values appear +person.name = Mike Wazowski + +# comments on array values appear +person.pets.0 = cat +person.pets.1.nested.0 = list entry +person.food.0 = pizza +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -p=props -o=props \[aq].person.pets.0 = \[dq]dog\[dq]\[aq] sample.properties +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +# block comments come through +# comments on values appear +person.name = Mike Wazowski + +# comments on array values appear +person.pets.0 = dog +person.pets.1.nested.0 = list entry +person.food.0 = pizza +\f[R] +.fi +.SH Recipes +.PP +These examples are intended to show how you can use multiple operators +together so you get an idea of how you can perform complex data +manipulation. +.PP +Please see the details operator +docs (https://mikefarah.gitbook.io/yq/operators) for details on each +individual operator. +.SS Find items in an array +.PP +We have an array and we want to find the elements with a particular +name. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- name: Foo + numBuckets: 0 +- name: Bar + numBuckets: 0 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] | select(.name == \[dq]Foo\[dq])\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +name: Foo +numBuckets: 0 +\f[R] +.fi +.SS Explanation: +.IP \[bu] 2 +\f[C].[]\f[R] splats the array, and puts all the items in the context. +.IP \[bu] 2 +These items are then piped (\f[C]|\f[R]) into +\f[C]select(.name == \[dq]Foo\[dq])\f[R] which will select all the nodes +that have a name property set to `Foo'. +.IP \[bu] 2 +See the select (https://mikefarah.gitbook.io/yq/operators/select) +operator for more information. +.SS Find and update items in an array +.PP +We have an array and we want to \f[I]update\f[R] the elements with a +particular name. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- name: Foo + numBuckets: 0 +- name: Bar + numBuckets: 0 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq](.[] | select(.name == \[dq]Foo\[dq]) | .numBuckets) |= . + 1\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- name: Foo + numBuckets: 1 +- name: Bar + numBuckets: 0 +\f[R] +.fi +.SS Explanation: +.IP \[bu] 2 +Following from the example above\f[C].[]\f[R] splats the array, selects +filters the items. +.IP \[bu] 2 +We then pipe (\f[C]|\f[R]) that into \f[C].numBuckets\f[R], which will +select that field from all the matching items +.IP \[bu] 2 +Splat, select and the field are all in brackets, that whole expression +is passed to the \f[C]|=\f[R] operator as the left hand side expression, +with \f[C]. + 1\f[R] as the right hand side expression. +.IP \[bu] 2 +\f[C]|=\f[R] is the operator that updates fields relative to their own +value, which is referenced as dot (\f[C].\f[R]). +.IP \[bu] 2 +The expression \f[C]. + 1\f[R] increments the numBuckets counter. +.IP \[bu] 2 +See the assign (https://mikefarah.gitbook.io/yq/operators/assign-update) +and add (https://mikefarah.gitbook.io/yq/operators/add) operators for +more information. +.SS Deeply prune a tree +.PP +Say we are only interested in child1 and child2, and want to filter +everything else out. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +parentA: + - bob +parentB: + child1: i am child1 + child3: hiya +parentC: + childX: cool + child2: me child2 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]( + .. | # recurse through all the nodes + select(has(\[dq]child1\[dq]) or has(\[dq]child2\[dq])) | # match parents that have either child1 or child2 + (.child1, .child2) | # select those children + select(.) # filter out nulls +) as $i ireduce({}; # using that set of nodes, create a new result map + setpath($i | path; $i) # and put in each node, using its original path +)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +parentB: + child1: i am child1 +parentC: + child2: me child2 +\f[R] +.fi +.SS Explanation: +.IP \[bu] 2 +Find all the matching child1 and child2 nodes +.IP \[bu] 2 +Using ireduce, create a new map using just those nodes +.IP \[bu] 2 +Set each node into the new map using its original path +.SS Multiple or complex updates to items in an array +.PP +We have an array and we want to \f[I]update\f[R] the elements with a +particular name in reference to its type. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +myArray: + - name: Foo + type: cat + - name: Bar + type: dog +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq]with(.myArray[]; .name = .name + \[dq] - \[dq] + .type)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +myArray: + - name: Foo - cat + type: cat + - name: Bar - dog + type: dog +\f[R] +.fi +.SS Explanation: +.IP \[bu] 2 +The with operator will effectively loop through each given item in the +first given expression, and run the second expression against it. +.IP \[bu] 2 +\f[C].myArray[]\f[R] splats the array in \f[C]myArray\f[R]. +So \f[C]with\f[R] will run against each item in that array +.IP \[bu] 2 +\f[C].name = .name + \[dq] - \[dq] + .type\f[R] this expression is run +against every item, updating the name to be a concatenation of the +original name as well as the type. +.IP \[bu] 2 +See the with (https://mikefarah.gitbook.io/yq/operators/with) operator +for more information and examples. +.SS Sort an array by a field +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +myArray: + - name: Foo + numBuckets: 1 + - name: Bar + numBuckets: 0 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].myArray |= sort_by(.numBuckets)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +myArray: + - name: Bar + numBuckets: 0 + - name: Foo + numBuckets: 1 +\f[R] +.fi +.SS Explanation: +.IP \[bu] 2 +We want to resort \f[C].myArray\f[R]. +.IP \[bu] 2 +\f[C]sort_by\f[R] works by piping an array into it, and it pipes out a +sorted array. +.IP \[bu] 2 +So, we use \f[C]|=\f[R] to update \f[C].myArray\f[R]. +This is the same as doing +\f[C].myArray = (.myArray | sort_by(.numBuckets))\f[R] +.SS Filter, flatten, sort and unique +.PP +Lets find the unique set of names from the document. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +- type: foo + names: + - Fred + - Catherine +- type: bar + names: + - Zelda +- type: foo + names: Fred +- type: foo + names: Ava +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq][.[] | select(.type == \[dq]foo\[dq]) | .names] | flatten | sort | unique\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- Ava +- Catherine +- Fred +\f[R] +.fi +.SS Explanation: +.IP \[bu] 2 +\f[C].[] | select(.type == \[dq]foo\[dq]) | .names\f[R] will select the +array elements of type \[lq]foo\[rq] +.IP \[bu] 2 +Splat \f[C].[]\f[R] will unwrap the array and match all the items. +We need to do this so we can work on the child items, for instance, +filter items out using the \f[C]select\f[R] operator. +.IP \[bu] 2 +But we still want the final results back into an array. +So after we\[cq]re doing working on the children, we wrap everything +back into an array using square brackets around the expression. +\f[C][.[] | select(.type == \[dq]foo\[dq]) | .names]\f[R] +.IP \[bu] 2 +Now have have an array of all the `names' values. +Which includes arrays of strings as well as strings on their own. +.IP \[bu] 2 +Pipe \f[C]|\f[R] this array through \f[C]flatten\f[R]. +This will flatten nested arrays. +So now we have a flat list of all the name value strings +.IP \[bu] 2 +Next we pipe \f[C]|\f[R] that through \f[C]sort\f[R] and then +\f[C]unique\f[R] to get a sorted, unique list of the names! +.IP \[bu] 2 +See the flatten (https://mikefarah.gitbook.io/yq/operators/flatten), +sort (https://mikefarah.gitbook.io/yq/operators/sort) and +unique (https://mikefarah.gitbook.io/yq/operators/unique) for more +information and examples. +.SS Export as environment variables (script), or any custom format +.PP +Given a yaml document, lets output a script that will configure +environment variables with that data. +This same approach can be used for exporting into custom formats. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +var0: string0 +var1: string1 +fruit: + - apple + - banana + - peach +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].[] |( + ( select(kind == \[dq]scalar\[dq]) | key + \[dq]=\[aq]\[rs]\[aq]\[aq]\[dq] + . + \[dq]\[aq]\[rs]\[aq]\[aq]\[dq]), + ( select(kind == \[dq]seq\[dq]) | key + \[dq]=(\[dq] + (map(\[dq]\[aq]\[rs]\[aq]\[aq]\[dq] + . + \[dq]\[aq]\[rs]\[aq]\[aq]\[dq]) | join(\[dq],\[dq])) + \[dq])\[dq]) +)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +var0=\[aq]string0\[aq] +var1=\[aq]string1\[aq] +fruit=(\[aq]apple\[aq],\[aq]banana\[aq],\[aq]peach\[aq]) +\f[R] +.fi +.SS Explanation: +.IP \[bu] 2 +\f[C].[]\f[R] matches all top level elements +.IP \[bu] 2 +We need a string expression for each of the different types that will +produce the bash syntax, we\[cq]ll use the union operator, to join them +together +.IP \[bu] 2 +Scalars, we just need the key and quoted value: +\f[C]( select(kind == \[dq]scalar\[dq]) | key + \[dq]=\[aq]\[dq] + . + \[dq]\[aq]\[dq])\f[R] +.IP \[bu] 2 +Sequences (or arrays) are trickier, we need to quote each value and +\f[C]join\f[R] them with \f[C],\f[R]: +\f[C]map(\[dq]\[aq]\[dq] + . + \[dq]\[aq]\[dq]) | join(\[dq],\[dq])\f[R] +.SS Custom format with nested data +.PP +Like the previous example, but lets handle nested data structures. +In this custom example, we\[cq]re going to join the property paths with +_. +The important thing to keep in mind is that our expression is not +recursive (despite the data structure being so). +Instead we match \f[I]all\f[R] elements on the tree and operate on them. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +simple: string0 +simpleArray: + - apple + - banana + - peach +deep: + property: value + array: + - cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].. |( + ( select(kind == \[dq]scalar\[dq] and parent | kind != \[dq]seq\[dq]) | (path | join(\[dq]_\[dq])) + \[dq]=\[aq]\[rs]\[aq]\[aq]\[dq] + . + \[dq]\[aq]\[rs]\[aq]\[aq]\[dq]), + ( select(kind == \[dq]seq\[dq]) | (path | join(\[dq]_\[dq])) + \[dq]=(\[dq] + (map(\[dq]\[aq]\[rs]\[aq]\[aq]\[dq] + . + \[dq]\[aq]\[rs]\[aq]\[aq]\[dq]) | join(\[dq],\[dq])) + \[dq])\[dq]) +)\[aq] sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +simple=\[aq]string0\[aq] +deep_property=\[aq]value\[aq] +simpleArray=(\[aq]apple\[aq],\[aq]banana\[aq],\[aq]peach\[aq]) +deep_array=(\[aq]cat\[aq]) +\f[R] +.fi +.SS Explanation: +.IP \[bu] 2 +You\[cq]ll need to understand how the previous example works to +understand this extension. +.IP \[bu] 2 +\f[C]..\f[R] matches \f[I]all\f[R] elements, instead of \f[C].[]\f[R] +from the previous example that just matches top level elements. +.IP \[bu] 2 +Like before, we need a string expression for each of the different types +that will produce the bash syntax, we\[cq]ll use the union operator, to +join them together +.IP \[bu] 2 +This time, however, our expression matches every node in the data +structure. +.IP \[bu] 2 +We only want to print scalars that are not in arrays (because we handle +the separately), so well add +\f[C]and parent | kind != \[dq]seq\[dq]\f[R] to the select operator +expression for scalars +.IP \[bu] 2 +We don\[cq]t just want the key any more, we want the full path. +So instead of \f[C]key\f[R] we have \f[C]path | join(\[dq]_\[dq])\f[R] +.IP \[bu] 2 +The expression for sequences follows the same logic +.SS Encode shell variables +.PP +Note that comments are dropped and values will be enclosed in single +quotes as needed. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# comment +name: Mike Wazowski +eyes: + color: turquoise + number: 1 +friends: + - James P. Sullivan + - Celia Mae +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=shell sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +name=\[aq]Mike Wazowski\[aq] +eyes_color=turquoise +eyes_number=1 +friends_0=\[aq]James P. Sullivan\[aq] +friends_1=\[aq]Celia Mae\[aq] +\f[R] +.fi +.SS Encode shell variables: illegal variable names as key. +.PP +Keys that would be illegal as variable keys are adapted. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +ascii_=_symbols: replaced with _ +\[dq]ascii_ _controls\[dq]: dropped (this example uses \[rs]t) +nonascii_\[u05D0]_characters: dropped +effort_expe\[~n]ded_t\[`o]_preserve_accented_latin_letters: moderate (via unicode NFKD) +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=shell sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +ascii___symbols=\[aq]replaced with _\[aq] +ascii__controls=\[aq]dropped (this example uses \[rs]t)\[aq] +nonascii__characters=dropped +effort_expended_to_preserve_accented_latin_letters=\[aq]moderate (via unicode NFKD)\[aq] +\f[R] +.fi +.SS Encode shell variables: empty values, arrays and maps +.PP +Empty values are encoded to empty variables, but empty arrays and maps +are skipped. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +empty: + value: + array: [] + map: {} +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=shell sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +empty_value= +\f[R] +.fi +.SS Encode shell variables: single quotes in values +.PP +Single quotes in values are encoded as `\[lq]'\[lq]\[cq] (close single +quote, double-quoted single quote, open single quote). +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +name: Miles O\[aq]Brien +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=shell sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +name=\[aq]Miles O\[aq]\[dq]\[aq]\[dq]\[aq]Brien\[aq] +\f[R] +.fi +.SH TOML +.PP +Decode from TOML. +Note that \f[C]yq\f[R] does not yet support outputting in TOML format +(and therefore it cannot roundtrip) +.SS Parse: Simple +.PP +Given a sample.toml file of: +.IP +.nf +\f[C] +A = \[dq]hello\[dq] +B = 12 +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].\[aq] sample.toml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +A: hello +B: 12 +\f[R] +.fi +.SS Parse: Deep paths +.PP +Given a sample.toml file of: +.IP +.nf +\f[C] +person.name = \[dq]hello\[dq] +person.address = \[dq]12 cat st\[dq] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].\[aq] sample.toml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +person: + name: hello + address: 12 cat st +\f[R] +.fi +.SS Encode: Scalar +.PP +Given a sample.toml file of: +.IP +.nf +\f[C] +person.name = \[dq]hello\[dq] +person.address = \[dq]12 cat st\[dq] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].person.name\[aq] sample.toml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +hello +\f[R] +.fi +.SS Parse: inline table +.PP +Given a sample.toml file of: +.IP +.nf +\f[C] +name = { first = \[dq]Tom\[dq], last = \[dq]Preston-Werner\[dq] } +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].\[aq] sample.toml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +name: + first: Tom + last: Preston-Werner +\f[R] +.fi +.SS Parse: Array Table +.PP +Given a sample.toml file of: +.IP +.nf +\f[C] +[owner.contact] +name = \[dq]Tom Preston-Werner\[dq] +age = 36 + +[[owner.addresses]] +street = \[dq]first street\[dq] +suburb = \[dq]ok\[dq] + +[[owner.addresses]] +street = \[dq]second street\[dq] +suburb = \[dq]nice\[dq] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].\[aq] sample.toml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +owner: + contact: + name: Tom Preston-Werner + age: 36 + addresses: + - street: first street + suburb: ok + - street: second street + suburb: nice +\f[R] +.fi +.SS Parse: Empty Table +.PP +Given a sample.toml file of: +.IP +.nf +\f[C] +[dependencies] +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].\[aq] sample.toml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +dependencies: {} +\f[R] +.fi +.SH XML +.PP +Encode and decode to and from XML. +Whitespace is not conserved for round trips - but the order of the +fields are. +.PP +Consecutive xml nodes with the same name are assumed to be arrays. +.PP +XML content data, attributes processing instructions and directives are +all created as plain fields. +.PP +This can be controlled by: +.PP +.TS +tab(@); +l l l. +T{ +Flag +T}@T{ +Default +T}@T{ +Sample XML +T} +_ +T{ +\f[C]--xml-attribute-prefix\f[R] +T}@T{ +\f[C]+\f[R] (changing to \f[C]+\[at]\f[R] soon) +T}@T{ +Legs in \f[C]<cat legs=\[dq]4\[dq]/>\f[R] +T} +T{ +\f[C]--xml-content-name\f[R] +T}@T{ +\f[C]+content\f[R] +T}@T{ +Meow in \f[C]<cat>Meow <fur>true</true></cat>\f[R] +T} +T{ +\f[C]--xml-directive-name\f[R] +T}@T{ +\f[C]+directive\f[R] +T}@T{ +\f[C]<!DOCTYPE config system \[dq]blah\[dq]>\f[R] +T} +T{ +\f[C]--xml-proc-inst-prefix\f[R] +T}@T{ +\f[C]+p_\f[R] +T}@T{ +\f[C]<?xml version=\[dq]1\[dq]?>\f[R] +T} +.TE +.PP +{% hint style=\[lq]warning\[rq] %} Default Attribute Prefix will be +changing in v4.30! In order to avoid name conflicts (e.g.\ having an +attribute named \[lq]content\[rq] will create a field that clashes with +the default content name of \[lq]+content\[rq]) the attribute prefix +will be changing to \[lq]+\[at]\[rq]. +.PP +This will affect users that have not set their own prefix and are not +roundtripping XML changes. +.PP +{% endhint %} +.SS Encoder / Decoder flag options +.PP +In addition to the above flags, there are the following xml +encoder/decoder options controlled by flags: +.PP +.TS +tab(@); +lw(23.3n) lw(23.3n) lw(23.3n). +T{ +Flag +T}@T{ +Default +T}@T{ +Description +T} +_ +T{ +\f[C]--xml-strict-mode\f[R] +T}@T{ +false +T}@T{ +Strict mode enforces the requirements of the XML specification. +When switched off the parser allows input containing common mistakes. +See the Golang xml decoder (https://pkg.go.dev/encoding/xml#Decoder) for +more details. +T} +T{ +\f[C]--xml-keep-namespace\f[R] +T}@T{ +true +T}@T{ +Keeps the namespace of attributes +T} +T{ +\f[C]--xml-raw-token\f[R] +T}@T{ +true +T}@T{ +Does not verify that start and end elements match and does not translate +name space prefixes to their corresponding URLs. +T} +T{ +\f[C]--xml-skip-proc-inst\f[R] +T}@T{ +false +T}@T{ +Skips over processing instructions, +e.g.\ \f[C]<?xml version=\[dq]1\[dq]?>\f[R] +T} +T{ +\f[C]--xml-skip-directives\f[R] +T}@T{ +false +T}@T{ +Skips over directives, +e.g.\ \f[C]<!DOCTYPE config system \[dq]blah\[dq]>\f[R] +T} +.TE +.PP +See below for examples +.SS Parse xml: simple +.PP +Notice how all the values are strings, see the next example on how you +can fix that. +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq] encoding=\[dq]UTF-8\[dq]?> +<cat> + <says>meow</says> + <legs>4</legs> + <cute>true</cute> +</cat> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] ++p_xml: version=\[dq]1.0\[dq] encoding=\[dq]UTF-8\[dq] +cat: + says: meow + legs: \[dq]4\[dq] + cute: \[dq]true\[dq] +\f[R] +.fi +.SS Parse xml: number +.PP +All values are assumed to be strings when parsing XML, but you can use +the \f[C]from_yaml\f[R] operator on all the strings values to autoparse +into the correct type. +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq] encoding=\[dq]UTF-8\[dq]?> +<cat> + <says>meow</says> + <legs>4</legs> + <cute>true</cute> +</cat> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq] (.. | select(tag == \[dq]!!str\[dq])) |= from_yaml\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] ++p_xml: version=\[dq]1.0\[dq] encoding=\[dq]UTF-8\[dq] +cat: + says: meow + legs: 4 + cute: true +\f[R] +.fi +.SS Parse xml: array +.PP +Consecutive nodes with identical xml names are assumed to be arrays. +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq] encoding=\[dq]UTF-8\[dq]?> +<animal>cat</animal> +<animal>goat</animal> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] ++p_xml: version=\[dq]1.0\[dq] encoding=\[dq]UTF-8\[dq] +animal: + - cat + - goat +\f[R] +.fi +.SS Parse xml: force as an array +.PP +In XML, if your array has a single item, then yq doesn\[cq]t know its an +array. +This is how you can consistently force it to be an array. +This handles the 3 scenarios of having nothing in the array, having a +single item and having multiple. +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<zoo><animal>cat</animal></zoo> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].zoo.animal |= ([] + .)\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +zoo: + animal: + - cat +\f[R] +.fi +.SS Parse xml: force all as an array +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<zoo><thing><frog>boing</frog></thing></zoo> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].. |= [] + .\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +- zoo: + - thing: + - frog: + - boing +\f[R] +.fi +.SS Parse xml: attributes +.PP +Attributes are converted to fields, with the default attribute prefix +`+'. +Use \[cq]\[en]xml-attribute-prefix\[ga] to set your own. +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq] encoding=\[dq]UTF-8\[dq]?> +<cat legs=\[dq]4\[dq]> + <legs>7</legs> +</cat> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] ++p_xml: version=\[dq]1.0\[dq] encoding=\[dq]UTF-8\[dq] +cat: + +\[at]legs: \[dq]4\[dq] + legs: \[dq]7\[dq] +\f[R] +.fi +.SS Parse xml: attributes with content +.PP +Content is added as a field, using the default content name of +\f[C]+content\f[R]. +Use \f[C]--xml-content-name\f[R] to set your own. +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq] encoding=\[dq]UTF-8\[dq]?> +<cat legs=\[dq]4\[dq]>meow</cat> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] ++p_xml: version=\[dq]1.0\[dq] encoding=\[dq]UTF-8\[dq] +cat: + +content: meow + +\[at]legs: \[dq]4\[dq] +\f[R] +.fi +.SS Parse xml: content split between comments/children +.PP +Multiple content texts are collected into a sequence. +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<root> value <!-- comment-->anotherValue <a>frog</a> cool!</root> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +root: + +content: # comment + - value + - anotherValue + - cool! + a: frog +\f[R] +.fi +.SS Parse xml: custom dtd +.PP +DTD entities are processed as directives. +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<!DOCTYPE root [ +<!ENTITY writer \[dq]Blah.\[dq]> +<!ENTITY copyright \[dq]Blah\[dq]> +]> +<root> + <item>&writer;©right;</item> +</root> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<!DOCTYPE root [ +<!ENTITY writer \[dq]Blah.\[dq]> +<!ENTITY copyright \[dq]Blah\[dq]> +]> +<root> + <item>&writer;&copyright;</item> +</root> +\f[R] +.fi +.SS Parse xml: skip custom dtd +.PP +DTDs are directives, skip over directives to skip DTDs. +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<!DOCTYPE root [ +<!ENTITY writer \[dq]Blah.\[dq]> +<!ENTITY copyright \[dq]Blah\[dq]> +]> +<root> + <item>&writer;©right;</item> +</root> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq --xml-skip-directives \[aq].\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<root> + <item>&writer;&copyright;</item> +</root> +\f[R] +.fi +.SS Parse xml: with comments +.PP +A best attempt is made to preserve comments. +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<!-- before cat --> +<cat> + <!-- in cat before --> + <x>3<!-- multi +line comment +for x --></x> + <!-- before y --> + <y> + <!-- in y before --> + <d><!-- in d before -->z<!-- in d after --></d> + + <!-- in y after --> + </y> + <!-- in_cat_after --> +</cat> +<!-- after cat --> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -oy \[aq].\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +# before cat +cat: + # in cat before + x: \[dq]3\[dq] # multi + # line comment + # for x + # before y + + y: + # in y before + # in d before + d: z # in d after + # in y after + # in_cat_after +# after cat +\f[R] +.fi +.SS Parse xml: keep attribute namespace +.PP +Defaults to true +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<map xmlns=\[dq]some-namespace\[dq] xmlns:xsi=\[dq]some-instance\[dq] xsi:schemaLocation=\[dq]some-url\[dq]></map> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq --xml-keep-namespace=false \[aq].\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<map xmlns=\[dq]some-namespace\[dq] xsi=\[dq]some-instance\[dq] schemaLocation=\[dq]some-url\[dq]></map> +\f[R] +.fi +.PP +instead of +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<map xmlns=\[dq]some-namespace\[dq] xmlns:xsi=\[dq]some-instance\[dq] xsi:schemaLocation=\[dq]some-url\[dq]></map> +\f[R] +.fi +.SS Parse xml: keep raw attribute namespace +.PP +Defaults to true +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<map xmlns=\[dq]some-namespace\[dq] xmlns:xsi=\[dq]some-instance\[dq] xsi:schemaLocation=\[dq]some-url\[dq]></map> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq --xml-raw-token=false \[aq].\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<map xmlns=\[dq]some-namespace\[dq] xmlns:xsi=\[dq]some-instance\[dq] some-instance:schemaLocation=\[dq]some-url\[dq]></map> +\f[R] +.fi +.PP +instead of +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<map xmlns=\[dq]some-namespace\[dq] xmlns:xsi=\[dq]some-instance\[dq] xsi:schemaLocation=\[dq]some-url\[dq]></map> +\f[R] +.fi +.SS Encode xml: simple +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cat: purrs +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=xml sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<cat>purrs</cat> +\f[R] +.fi +.SS Encode xml: array +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +pets: + cat: + - purrs + - meows +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=xml sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<pets> + <cat>purrs</cat> + <cat>meows</cat> +</pets> +\f[R] +.fi +.SS Encode xml: attributes +.PP +Fields with the matching xml-attribute-prefix are assumed to be +attributes. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cat: + +\[at]name: tiger + meows: true +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=xml sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<cat name=\[dq]tiger\[dq]> + <meows>true</meows> +</cat> +\f[R] +.fi +.SS Encode xml: attributes with content +.PP +Fields with the matching xml-content-name is assumed to be content. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +cat: + +\[at]name: tiger + +content: cool +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=xml sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<cat name=\[dq]tiger\[dq]>cool</cat> +\f[R] +.fi +.SS Encode xml: comments +.PP +A best attempt is made to copy comments to xml. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] +# +# header comment +# above_cat +# +cat: # inline_cat + # above_array + array: # inline_array + - val1 # inline_val1 + # above_val2 + - val2 # inline_val2 +# below_cat +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=xml sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<!-- +header comment +above_cat +--> +<!-- inline_cat --> +<cat><!-- above_array inline_array --> + <array>val1<!-- inline_val1 --></array> + <array><!-- above_val2 -->val2<!-- inline_val2 --></array> +</cat><!-- below_cat --> +\f[R] +.fi +.SS Encode: doctype and xml declaration +.PP +Use the special xml names to add/modify proc instructions and +directives. +.PP +Given a sample.yml file of: +.IP +.nf +\f[C] ++p_xml: version=\[dq]1.0\[dq] ++directive: \[aq]DOCTYPE config SYSTEM \[dq]/etc/iwatch/iwatch.dtd\[dq] \[aq] +apple: + +p_coolioo: version=\[dq]1.0\[dq] + +directive: \[aq]CATYPE meow purr puss \[aq] + b: things +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq -o=xml sample.yml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<!DOCTYPE config SYSTEM \[dq]/etc/iwatch/iwatch.dtd\[dq] > +<apple><?coolioo version=\[dq]1.0\[dq]?><!CATYPE meow purr puss > + <b>things</b> +</apple> +\f[R] +.fi +.SS Round trip: with comments +.PP +A best effort is made, but comment positions and white space are not +preserved perfectly. +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<!-- before cat --> +<cat> + <!-- in cat before --> + <x>3<!-- multi +line comment +for x --></x> + <!-- before y --> + <y> + <!-- in y before --> + <d><!-- in d before -->z<!-- in d after --></d> + + <!-- in y after --> + </y> + <!-- in_cat_after --> +</cat> +<!-- after cat --> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<!-- before cat --> +<cat><!-- in cat before --> + <x>3<!-- multi +line comment +for x --></x><!-- before y --> + <y><!-- in y before +in d before --> + <d>z<!-- in d after --></d><!-- in y after --> + </y><!-- in_cat_after --> +</cat><!-- after cat --> +\f[R] +.fi +.SS Roundtrip: with doctype and declaration +.PP +yq parses XML proc instructions and directives into nodes. +Unfortunately the underlying XML parser loses whitespace information. +.PP +Given a sample.xml file of: +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<!DOCTYPE config SYSTEM \[dq]/etc/iwatch/iwatch.dtd\[dq] > +<apple> + <?coolioo version=\[dq]1.0\[dq]?> + <!CATYPE meow purr puss > + <b>things</b> +</apple> +\f[R] +.fi +.PP +then +.IP +.nf +\f[C] +yq \[aq].\[aq] sample.xml +\f[R] +.fi +.PP +will output +.IP +.nf +\f[C] +<?xml version=\[dq]1.0\[dq]?> +<!DOCTYPE config SYSTEM \[dq]/etc/iwatch/iwatch.dtd\[dq] > +<apple><?coolioo version=\[dq]1.0\[dq]?><!CATYPE meow purr puss > + <b>things</b> +</apple> +\f[R] +.fi +.SH AUTHORS +Mike Farah. -- GitLab