Skip to content

Commit

Permalink
refactor: update geo tables (#675)
Browse files Browse the repository at this point in the history
# Pull Request type



Please check the type of change your PR introduces:

- [ ] Bugfix
- [ ] Feature
- [ ] Code style update (formatting, renaming)
- [x] Refactoring (no functional changes, no API changes)
- [ ] Build-related changes
- [ ] Documentation content changes
- [ ] Other (please describe):

## What is the current behavior?

Geo data was directly in GovDist/Country records.

Issue Number: N/A

## What is the new behavior?

- Moved all generic geo data to separate table
- Populated geo data for entire world (sourced from [Natural Earth](https://www.naturalearthdata.com/))
- Linked Country/GovDist records to geo records
- Updated search query to reference new table

## Does this introduce a breaking change?

- [ ] Yes
- [x] No



## Other information




PR-URL: #675
Co-authored-by: Joe Karow <[email protected]>
  • Loading branch information
kodiakhq[bot] and JoeKarow authored Jul 20, 2023
2 parents 14f38b3 + 21e027b commit 75ee768
Show file tree
Hide file tree
Showing 14 changed files with 495 additions and 46 deletions.
51 changes: 27 additions & 24 deletions packages/api/lib/prismaRaw/orgSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,9 @@ filters(
),
covered_areas AS (
SELECT
ARRAY_AGG(DISTINCT c .id) AS country,
ARRAY_AGG(DISTINCT gd.id) AS district
FROM "Country" c
JOIN points ON TRUE
JOIN "GovDist" gd ON ST_CoveredBy(points.degrees, gd.geo)
WHERE ST_CoveredBy(points.degrees, c .geo)
id
FROM "GeoData" g
WHERE ST_CoveredBy((select degrees from points), g.geo)
),
attributes AS (
SELECT * FROM (
Expand Down Expand Up @@ -69,6 +66,20 @@ services AS (
ols. "orgLocationId",
os. "organizationId"
ORDER BY os."organizationId", ols."orgLocationId"
),
service_area as (
SELECT
country."geoDataId" as "countryGeoId",
district."geoDataId" as "districtGeoId",
country.cca3 as "cca3",
sa."organizationId",
sa."orgLocationId"
FROM "ServiceArea" sa
JOIN "ServiceAreaCountry" sac ON sac. "serviceAreaId" = sa.id AND sac.active
JOIN "ServiceAreaDist" sad ON sad. "serviceAreaId" = sa.id AND sad.active
JOIN "Country" country ON country.id = sac. "countryId"
JOIN "GovDist" district ON district.id = sad. "govDistId"
WHERE sa.active AND sa."organizationId" is not null
)
SELECT
*,
Expand All @@ -91,23 +102,13 @@ services AS (
}
MIN(
ROUND(
ST_Distance(ST_Transform(loc.geo, 3857), points.meters)::int
ST_Distance(ST_Transform(loc.geo, 3857), (SELECT meters FROM points))::int
)
) AS distance,
ARRAY_REMOVE(ARRAY_AGG(DISTINCT country.cca3), NULL) AS "national"
ARRAY_REMOVE(ARRAY_AGG(DISTINCT sa.cca3), NULL) AS "national"
FROM "OrgLocation" loc
JOIN points ON TRUE
JOIN filters ON TRUE
JOIN covered_areas ca ON TRUE
INNER JOIN "Organization" org ON org.id = loc. "orgId"
AND org.published
AND NOT org.deleted
LEFT JOIN "ServiceArea" sa ON sa. "orgLocationId" = loc.id
OR sa. "organizationId" = loc. "orgId"
LEFT JOIN "ServiceAreaCountry" sac ON sac. "serviceAreaId" = sa.id
LEFT JOIN "ServiceAreaDist" sad ON sad. "serviceAreaId" = sa.id
LEFT JOIN "Country" country ON country.id = sac. "countryId"
LEFT JOIN "GovDist" district ON district.id = sad. "govDistId"
LEFT JOIN service_area sa ON sa. "organizationId" = loc. "orgId"
${
serviceFilter?.length
? Prisma.sql`
Expand All @@ -122,12 +123,14 @@ services AS (
}
WHERE
(
ST_DWithin(ST_Transform(loc.geo, 3857), points.meters, ${searchRadius})
OR country.id = ANY (ca.country)
OR district.id = ANY (ca.district)
ST_DWithin(ST_Transform(loc.geo, 3857), (SELECT meters FROM points), ${searchRadius})
OR sa."countryGeoId" = ANY(SELECT id FROM covered_areas)
OR sa."districtGeoId" = ANY(SELECT id FROM covered_areas)
)
AND loc.published = TRUE
AND loc.deleted = FALSE
AND loc.published
AND org.published
AND NOT loc.deleted
AND NOT org.deleted
GROUP BY
loc."orgId"
ORDER BY
Expand Down
1 change: 1 addition & 0 deletions packages/db/lib/idGen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const idPrefix = {
dataMigration: 'data',
fieldVisibility: 'fviz',
freeText: 'ftxt',
geoData: 'geod',
govDist: 'gdst',
govDistType: 'gdty',
internalNote: 'note',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { z } from 'zod'

import fs from 'fs'
import path from 'path'

import { prisma } from '~db/client'
import { formatMessage } from '~db/prisma/common'
import { type MigrationJob } from '~db/prisma/dataMigrationRunner'
import { createLogger, type JobDef, jobPostRunner } from '~db/prisma/jobPreRun'

/** Define the job metadata here. */
const jobDef: JobDef = {
jobId: '2023-07-19_district-data-corrections',
title: 'Governing District data corrections',
createdBy: 'Joe Karow',
/** Optional: Longer description for the job */
description: undefined,
}

const PrDataSchema = z.object({ id: z.string(), iso: z.string() }).array()
const MxDataSchema = z.object({ id: z.string(), iso: z.string() }).array()
/**
* Job export - this variable MUST be UNIQUE
*
* Use the format `jobYYYYMMDD` and append a letter afterwards if there is already a job with this name.
*
* @example `job20230404`
*
* @example `job20230404b`
*/
export const job20230719a = {
title: `${jobDef.jobId} - ${jobDef.title}`,
task: async (_ctx, task) => {
/** Create logging instance */
createLogger(task, jobDef.jobId)
const log = (...args: Parameters<typeof formatMessage>) => (task.output = formatMessage(...args))
/**
* Start defining your data migration from here.
*
* To log output, use `task.output = 'Message to log'`
*
* This will be written to `stdout` and to a log file in `/prisma/migration-logs/`
*/

const prData = PrDataSchema.parse(JSON.parse(fs.readFileSync(path.join(__dirname, 'pr.json'), 'utf-8')))
const mxData = MxDataSchema.parse(JSON.parse(fs.readFileSync(path.join(__dirname, 'mx.json'), 'utf-8')))
const isoUpdates = await prisma.$transaction(
[...prData, ...mxData].map(({ id, iso }) => prisma.govDist.update({ where: { id }, data: { iso } }))
)
log(`ISO codes updated: ${isoUpdates.length}`)

const updateName = (id: string, name: string, slug?: string) =>
prisma.govDist.update({
where: { id },
data: { name, slug, key: { update: { text: name, key: slug } } },
})
// Do stuff
const updates = await prisma.$transaction([
updateName('gdst_01GW2HJA0BE7FF4F7YKAR9VKSG', 'DeWitt', 'us-illinois-dewitt-county'),
updateName('gdst_01GW2HJFJZPT7RNQMXM7H8HKR8', 'LaRue'),
updateName('gdst_01GW2HJGHGYD74339CP83XHKTG', 'DeSoto', 'us-louisiana-desoto-county'),
updateName('gdst_01GW2HJ01XRKWVBQTGFZQW33VB', 'Kusilvak', 'us-alaska-kusilvak-county'),
updateName('gdst_01GW2HK2DX86W6Y6HZ8ZDRAXJV', 'LeFlore', 'us-oklahoma-leflore-county'),
updateName('gdst_01GW2HJV6SWRQMJ0H36AAEPTM1', 'Coös'),
updateName('gdst_01GW2HK67J9DK0JXBK4VK4C4EM', 'Oglala Lakota', 'us-south-dakota-oglala-lakota-county'),
])
log(`Names updated: ${updates.length}`)

const updateMx = await prisma.orgLocation.updateMany({
where: { govDistId: 'gdst_01GW2HKJ7RG6XAZFVW3KHZEJ5N' },
data: { govDistId: 'gdst_01GW2HKJ7TH3H6DP8T7X9JD0P7' },
})
log(`Mexico locations updated: ${updateMx.count}`)

const removals = await prisma.govDist.deleteMany({
where: {
id: {
in: [
'gdst_01GW2HKJ7RG6XAZFVW3KHZEJ5N',
'gdst_01GW2HKB0KG2G0R852TF709SVM',
'gdst_01GW2HKB0KMSRD4J9FX440P7D7',
],
},
},
})
log(`Districts deleted: ${removals.count}`)

/**
* DO NOT REMOVE BELOW
*
* This writes a record to the DB to register that this migration has run successfully.
*/
await jobPostRunner(jobDef)
},
def: jobDef,
} satisfies MigrationJob
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"id":"gdst_01GW2HKJ7QDVHS9K3FJGJ3DCVG","iso":"MX-COA"},{"id":"gdst_01GW2HKJ7TH3H6DP8T7X9JD0P7","iso":"MX-DIF"},{"id":"gdst_01GW2HKJ7TVTPXQXX72QHX8P8T","iso":"MX-MIC"},{"id":"gdst_01GW2HKJ7WVV7V5NA1XP5BD0A7","iso":"MX-NLE"},{"id":"gdst_01GW2HKJ7XQWNY7KYE4GFSRVY9","iso":"MX-QUE"},{"id":"gdst_01GW2HKJ7X81B6PQNKDGBY35FT","iso":"MX-SLP"},{"id":"gdst_01GW2HKJ7ZPEGHSE8Y0C6AJ2HK","iso":"MX-VER"},{"id":"gdst_01GW2HKJ7ZAFQ34D6TVHT2AJ88","iso":"MX-YUC"}]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"iso":"PR-01","id":"gdst_01GW2HKF7MNPRM44JZ70DZNZ75"},{"iso":"PR-02","id":"gdst_01GW2HKF7QQADN2XEJEGRZGA32"},{"iso":"PR-03","id":"gdst_01GW2HKF7GDB9A0Y61RH4DE1Y7"},{"iso":"PR-04","id":"gdst_01GW2HKF7MHG9HQGMG6HW76GTY"},{"iso":"PR-05","id":"gdst_01GW2HKF7QZYRM5N4YWRDX0D51"},{"iso":"PR-06","id":"gdst_01GW2HKF7MJ6N0ZP2EVQW7PKSZ"},{"iso":"PR-07","id":"gdst_01GW2HKF7ASDCF6MJX1GR7A9WD"},{"iso":"PR-08","id":"gdst_01GW2HKF7QAWDF8MDJPC4ATW3C"},{"iso":"PR-09","id":"gdst_01GW2HKF7KWSFQ2BBNE06FBJ8B"},{"iso":"PR-10","id":"gdst_01GW2HKF7AAHGX7T7W6AZJWYAE"},{"iso":"PR-11","id":"gdst_01GW2HKF7K7GQPKHXMAZ353S8Q"},{"iso":"PR-12","id":"gdst_01GW2HKF7NB99SEGDAGPWGQ7HH"},{"iso":"PR-13","id":"gdst_01GW2HKF7BSBYYNEMZ6QVF8227"},{"iso":"PR-14","id":"gdst_01GW2HKF7E342VRJMB9JBQGCB8"},{"iso":"PR-15","id":"gdst_01GW2HKF7K6K1YGQMXC75C7FEN"},{"iso":"PR-16","id":"gdst_01GW2HKF7B83PQP7G4GY5H1F1Y"},{"iso":"PR-17","id":"gdst_01GW2HKF7N2795CHTK7B9FMBMT"},{"iso":"PR-18","id":"gdst_01GW2HKF7EJC9Z7Q854T284T8Q"},{"iso":"PR-19","id":"gdst_01GW2HKF7N4BXQNPGJ2SSB3HZP"},{"iso":"PR-20","id":"gdst_01GW2HKF7KNW1P6M0CBTP9DJPH"},{"iso":"PR-21","id":"gdst_01GW2HKF7ES2899PBSYADF5CGZ"},{"iso":"PR-22","id":"gdst_01GW2HKF7E1MAS1DCAF251JMS0"},{"iso":"PR-23","id":"gdst_01GW2HKF7C8TEXW0TX7BNR3ZJP"},{"iso":"PR-24","id":"gdst_01GW2HKF7NM95AMSGKNYVNMX4K"},{"iso":"PR-25","id":"gdst_01GW2HKF7NJ8N815ZSVQ6PP8F8"},{"iso":"PR-26","id":"gdst_01GW2HKF7KY7TE0STKHEKB8TCT"},{"iso":"PR-27","id":"gdst_01GW2HKF7FJX1TV2FACXBDTY8V"},{"iso":"PR-28","id":"gdst_01GW2HKF7CT97CA6YVEKY451FF"},{"iso":"PR-29","id":"gdst_01GW2HKF7FKYKQ8FJ5EAG5FQGG"},{"iso":"PR-30","id":"gdst_01GW2HKF7N8X0C9FVKWQRPZ0N5"},{"iso":"PR-31","id":"gdst_01GW2HKF7FP0SMK1DBEP03CCPT"},{"iso":"PR-32","id":"gdst_01GW2HKF7CPSVHHJVMRV1TCEPH"},{"iso":"PR-33","id":"gdst_01GW2HKF7KPB26QY6V5AGPHQCK"},{"iso":"PR-34","id":"gdst_01GW2HKF7PBJAHMG2YTEB5E6QN"},{"iso":"PR-35","id":"gdst_01GW2HKF7GKZBEW06ATJGN7YA0"},{"iso":"PR-36","id":"gdst_01GW2HKF7C8PZMQX3ZPA4SQA0R"},{"iso":"PR-37","id":"gdst_01GW2HKF7QNDYT5EJJSNHV70Q0"},{"iso":"PR-38","id":"gdst_01GW2HKF7GFWQFZM4W8B6XE278"},{"iso":"PR-39","id":"gdst_01GW2HKF7JCH0F0VGDMC9T859G"},{"iso":"PR-40","id":"gdst_01GW2HKF7KKF2ZRBGWJ65XYB1H"},{"iso":"PR-41","id":"gdst_01GW2HKF7GJZ9K8JZHNY36F1S1"},{"iso":"PR-42","id":"gdst_01GW2HKF7GP9242YXKBP7ZY7SZ"},{"iso":"PR-43","id":"gdst_01GW2HKF7DQFZ2RSYBJQ6ZTTSX"},{"iso":"PR-44","id":"gdst_01GW2HKF7MZFQQ65W2WV6B3HFJ"},{"iso":"PR-45","id":"gdst_01GW2HKF7P4GF3D9AH52RC8PAB"},{"iso":"PR-46","id":"gdst_01GW2HKF7G4BFBE603PNE92JZ7"},{"iso":"PR-47","id":"gdst_01GW2HKF7PWWJXJ0XKJW6BRCQ1"},{"iso":"PR-48","id":"gdst_01GW2HKF7DKTN8REXVNGVAECB8"},{"iso":"PR-49","id":"gdst_01GW2HKF7GJBK2M8GR9YSWMHM0"},{"iso":"PR-50","id":"gdst_01GW2HKF7PJWWVN43HSZXECPP4"},{"iso":"PR-51","id":"gdst_01GW2HKF7M2DS24Q59CSHA0DY5"},{"iso":"PR-52","id":"gdst_01GW2HKF7H4FBMYSFFGJZYH0MH"},{"iso":"PR-53","id":"gdst_01GW2HKF7HJBVR2JFQ1VAWS6JD"},{"iso":"PR-54","id":"gdst_01GW2HKF7DCSXHCYDJ28QWER0N"},{"iso":"PR-55","id":"gdst_01GW2HKF7PQJ4CM33MH3AEM1RA"},{"iso":"PR-56","id":"gdst_01GW2HKF7HFBFSHR7JYV7NHF0Z"},{"iso":"PR-57","id":"gdst_01GW2HKF7MD86ZXFZYAKS2GJNR"},{"iso":"PR-58","id":"gdst_01GW2HKF7PV9TMP8VWK93FTV2J"},{"iso":"PR-59","id":"gdst_01GW2HKF7D4HT3G8QJ6825DV48"},{"iso":"PR-60","id":"gdst_01GW2HKF7HMQPDNKPBKNXDZR6P"},{"iso":"PR-61","id":"gdst_01GW2HKF7HDC2BETD8TXG8M3N8"},{"iso":"PR-62","id":"gdst_01GW2HKF7PYS8BKRNW15QN0S0D"},{"iso":"PR-63","id":"gdst_01GW2HKF7MZHTPEG6PYHA6FWFF"},{"iso":"PR-64","id":"gdst_01GW2HKF7H0Q44P9ERJFFPJBFC"},{"iso":"PR-65","id":"gdst_01GW2HKF7Q4W804RJYJGSN9YDS"},{"iso":"PR-66","id":"gdst_01GW2HKF7DMJDRY12E121NAPY5"},{"iso":"PR-67","id":"gdst_01GW2HKF7H2VNGTNFXZW160HHP"},{"iso":"PR-68","id":"gdst_01GW2HKF7QD21G3Y0R6E0CB8RH"},{"iso":"PR-69","id":"gdst_01GW2HKF7DCAZN6WSP89JENB8R"},{"iso":"PR-70","id":"gdst_01GW2HKF7J713E50Y0QV06MQXV"},{"iso":"PR-71","id":"gdst_01GW2HKF7M73DDSZHXFGQ590SV"},{"iso":"PR-72","id":"gdst_01GW2HKF7QAE0RFPT8NC27V024"},{"iso":"PR-73","id":"gdst_01GW2HKF7JSS7C4C4QRJHCMTJH"},{"iso":"PR-74","id":"gdst_01GW2HKF7EJNVQWD2TRZT2SH0S"},{"iso":"PR-75","id":"gdst_01GW2HKF7J1ADADNHCE9AWWGTP"},{"iso":"PR-76","id":"gdst_01GW2HKF7J3GGEMV7WYXFEP5AS"},{"iso":"PR-77","id":"gdst_01GW2HKF7J0062R97R77JPGEH6"},{"iso":"PR-78","id":"gdst_01GW2HKF7JBB2EXCZFTX3V5ABR"}]
1 change: 1 addition & 0 deletions packages/db/prisma/data-migrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ export * from './2023-07-12_1-add-remote-tags/index'
export * from './2023-07-12_2-leader-focus-attribs/index'
export * from './2023-07-12_3-update-tags-attributes/index'
export * from './2023-07-17_SWT-update'
export * from './2023-07-19_district-data-corrections/index'
// codegen:end
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
-- AlterTable
ALTER TABLE "Country" ADD COLUMN "geoDataId" TEXT;

-- AlterTable
ALTER TABLE "GovDist" ADD COLUMN "geoDataId" TEXT;

-- CreateTable
CREATE TABLE "GeoData" (
"id" TEXT NOT NULL,
"name" TEXT NOT NULL,
"geo" geometry(multipolygon,4326) NOT NULL,
"iso" TEXT NOT NULL,
"iso2" TEXT,
"abbrev" TEXT,
"type" TEXT,
"adminLevel" INTEGER NOT NULL,

CONSTRAINT "GeoData_pkey" PRIMARY KEY ("id")
);

-- CreateIndex
CREATE INDEX "GeoData_geo_idx" ON "GeoData" USING SPGIST ("geo");

-- CreateIndex
CREATE INDEX "GeoData_name_idx" ON "GeoData"("name");

-- CreateIndex
CREATE INDEX "GeoData_iso_idx" ON "GeoData"("iso");

-- CreateIndex
CREATE INDEX "GeoData_abbrev_idx" ON "GeoData"("abbrev");

-- CreateIndex
CREATE INDEX "GeoData_iso_abbrev_idx" ON "GeoData"("iso", "abbrev");

-- CreateIndex
CREATE INDEX "GeoData_iso_adminLevel_idx" ON "GeoData"("iso", "adminLevel");

-- CreateIndex
CREATE INDEX "Country_geoDataId_idx" ON "Country"("geoDataId");

-- CreateIndex
CREATE INDEX "GovDist_geoDataId_idx" ON "GovDist"("geoDataId");

-- AddForeignKey
ALTER TABLE "Country" ADD CONSTRAINT "Country_geoDataId_fkey" FOREIGN KEY ("geoDataId") REFERENCES "GeoData"("id") ON DELETE SET NULL ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "GovDist" ADD CONSTRAINT "GovDist_geoDataId_fkey" FOREIGN KEY ("geoDataId") REFERENCES "GeoData"("id") ON DELETE SET NULL ON UPDATE CASCADE;

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
Warnings:
- A unique constraint covering the columns `[geoDataId]` on the table `Country` will be added. If there are existing duplicate values, this will fail.
- A unique constraint covering the columns `[geoDataId]` on the table `GovDist` will be added. If there are existing duplicate values, this will fail.
*/
-- CreateIndex
CREATE UNIQUE INDEX "Country_geoDataId_key" ON "Country"("geoDataId");

-- CreateIndex
CREATE UNIQUE INDEX "GovDist_geoDataId_key" ON "GovDist"("geoDataId");

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
-- Clear blank fields
UPDATE
"OrgLocation"
SET
"street2" = NULL
WHERE
"street2" = '';

UPDATE
"OrgLocation"
SET
"name" = NULL
WHERE
"name" = '';

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
Warnings:
- You are about to drop the column `geo` on the `Country` table. All the data in the column will be lost.
- You are about to drop the column `geoJSON` on the `Country` table. All the data in the column will be lost.
- You are about to drop the column `geoWKT` on the `Country` table. All the data in the column will be lost.
- You are about to drop the column `geo` on the `GovDist` table. All the data in the column will be lost.
- You are about to drop the column `geoJSON` on the `GovDist` table. All the data in the column will be lost.
- You are about to drop the column `geoWKT` on the `GovDist` table. All the data in the column will be lost.
*/
-- DropIndex
DROP INDEX "Country_geo_idx";

-- DropIndex
DROP INDEX "GovDist_geo_idx";

-- AlterTable
ALTER TABLE "Country" DROP COLUMN "geo",
DROP COLUMN "geoJSON",
DROP COLUMN "geoWKT";

-- AlterTable
ALTER TABLE "GovDist" DROP COLUMN "geo",
DROP COLUMN "geoJSON",
DROP COLUMN "geoWKT";
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
-- DropIndex
DROP INDEX "GeoData_geo_idx";

-- DropIndex
DROP INDEX "OrgLocation_geo_idx";

-- CreateIndex
CREATE INDEX "AttributeToCategory_attributeId_idx" ON "AttributeToCategory"("attributeId");

-- CreateIndex
CREATE INDEX "AttributeToCategory_categoryId_idx" ON "AttributeToCategory"("categoryId");

-- CreateIndex
CREATE INDEX "GeoData_geo_idx" ON "GeoData" USING GIST("geo");

-- CreateIndex
CREATE INDEX "OrgLocation_geo_idx" ON "OrgLocation" USING GIST("geo");

-- CreateIndex
CREATE INDEX "OrgLocationService_serviceId_orgLocationId_idx" ON "OrgLocationService"("serviceId", "orgLocationId");

-- CreateIndex
CREATE INDEX "ServiceAreaCountry_serviceAreaId_countryId_active_idx" ON "ServiceAreaCountry"("serviceAreaId", "countryId", "active");

-- CreateIndex
CREATE INDEX "ServiceAreaDist_serviceAreaId_govDistId_active_idx" ON "ServiceAreaDist"("serviceAreaId", "govDistId", "active");

-- CreateIndex
CREATE INDEX "ServiceTagCountry_countryId_idx" ON "ServiceTagCountry"("countryId");

-- CreateIndex
CREATE INDEX "ServiceTagCountry_serviceId_idx" ON "ServiceTagCountry"("serviceId");

Loading

0 comments on commit 75ee768

Please sign in to comment.