Skip to content

Commit 0660588

Browse files
committed
feat: infer organization country from location (CM-1366)
Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com>
1 parent 858d121 commit 0660588

11 files changed

Lines changed: 58 additions & 2 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- organizations.country is a denormalized default for Insights (Sequin syncs
2+
-- organizations, not orgAttributes). Provenance still lives in orgAttributes
3+
-- (source = system for inferred values), same dual-write pattern as location.
4+
alter table "organizations"
5+
add column if not exists "country" text;

backend/src/database/models/organization.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ export default (sequelize) => {
4545
type: DataTypes.TEXT,
4646
allowNull: true,
4747
},
48+
country: {
49+
type: DataTypes.TEXT,
50+
allowNull: true,
51+
},
4852
description: {
4953
type: DataTypes.TEXT,
5054
allowNull: true,

backend/src/database/repositories/organizationRepository.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class OrganizationRepository {
7676
['founded', 'o."founded"'],
7777
['headline', 'o."headline"'],
7878
['location', 'o."location"'],
79+
['country', 'o."country"'],
7980
['tags', 'o."tags"'],
8081
['type', 'o."type"'],
8182
['isTeamOrganization', 'o."isTeamOrganization"'],
@@ -243,6 +244,7 @@ class OrganizationRepository {
243244
'logo',
244245
'tags',
245246
'location',
247+
'country',
246248
'employees',
247249
'revenueRange',
248250
'employeeChurnRate',
@@ -256,6 +258,7 @@ class OrganizationRepository {
256258
phoneNumbers: (a, b) => lodash.isEqual((a || []).sort(), (b || []).sort()),
257259
logo: (a, b) => a === b,
258260
location: (a, b) => a === b,
261+
country: (a, b) => a === b,
259262
isTeamOrganization: (a, b) => a === b,
260263
isAffiliationBlocked: (a, b) => a === b,
261264
attributes: (a, b) => lodash.isEqual(a, b),

services/apps/organizations_enrichment_worker/src/activities/enrichment.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ export async function applyEnrichmentToOrganization(
210210
const orgData = await findOrgById(qx, organizationId, [
211211
OrganizationField.ID,
212212
OrganizationField.DISPLAY_NAME,
213+
OrganizationField.LOCATION,
214+
OrganizationField.COUNTRY,
213215
OrganizationField.IS_TEAM_ORGANIZATION,
214216
OrganizationField.MANUALLY_CREATED,
215217
])

services/libs/data-access-layer/src/organizations/attributesConfig.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const ORG_DB_FIELDS = [
1616
'revenueRange',
1717
'importHash',
1818
'location',
19+
'country',
1920
'isTeamOrganization',
2021
'isAffiliationBlocked',
2122
'type',
@@ -52,6 +53,12 @@ export const ORG_DB_ATTRIBUTES: OrgAttributeDef[] = [
5253
type: OrganizationAttributeType.STRING,
5354
defaultColumn: 'location',
5455
},
56+
{
57+
name: 'country',
58+
incomingType: OrganizationAttributeType.STRING,
59+
type: OrganizationAttributeType.STRING,
60+
defaultColumn: 'country',
61+
},
5562
{
5663
name: 'type',
5764
incomingType: OrganizationAttributeType.STRING,
@@ -230,6 +237,7 @@ export function findAttribute(name: string): OrgAttributeDef {
230237
export const ORG_DB_ATTRIBUTE_SOURCE_PRIORITY = [
231238
OrganizationAttributeSource.CUSTOM,
232239
OrganizationAttributeSource.LFX_SERVE,
240+
OrganizationAttributeSource.SYSTEM,
233241
OrganizationAttributeSource.ENRICHMENT_LFX_INTERNAL_API,
234242
OrganizationAttributeSource.ENRICHMENT_PEOPLEDATALABS,
235243
OrganizationAttributeSource.CVENT,

services/libs/data-access-layer/src/organizations/base.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const ORG_SELECT_COLUMNS = [
3939
'revenueRange',
4040
'importHash',
4141
'location',
42+
'country',
4243
'isTeamOrganization',
4344
'isAffiliationBlocked',
4445
'type',
@@ -401,6 +402,7 @@ export async function insertOrganizations(
401402
'revenueRange',
402403
'importHash',
403404
'location',
405+
'country',
404406
'isTeamOrganization',
405407
'isAffiliationBlocked',
406408
'type',
@@ -661,6 +663,7 @@ export async function findOrCreateOrganization(
661663
tags: data.tags,
662664
employees: data.employees,
663665
location: data.location,
666+
country: data.country,
664667
type: data.type,
665668
size: data.size,
666669
headline: data.headline,
@@ -754,6 +757,7 @@ export enum OrganizationField {
754757
EMPLOYEES = 'employees',
755758
REVENUE_RANGE = 'revenueRange',
756759
LOCATION = 'location',
760+
COUNTRY = 'country',
757761
IS_TEAM_ORGANIZATION = 'isTeamOrganization',
758762
IS_AFFILIATION_BLOCKED = 'isAffiliationBlocked',
759763
TYPE = 'type',

services/libs/data-access-layer/src/organizations/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export interface IDbOrganization {
1515
revenueRange?: IOrganizationRevenueRange
1616
importHash?: string
1717
location?: string
18+
country?: string
1819
isTeamOrganization: boolean
1920
isAffiliationBlocked?: boolean
2021
type?: string
@@ -36,6 +37,7 @@ export interface IDbOrganizationInput {
3637
revenueRange?: IOrganizationRevenueRange
3738
importHash?: string
3839
location?: string
40+
country?: string
3941
isTeamOrganization: boolean
4042
isAffiliationBlocked?: boolean
4143
type?: string

services/libs/data-access-layer/src/organizations/utils.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { groupBy } from '@crowd/common'
1+
import { getCountry, groupBy } from '@crowd/common'
22
import { OrganizationAttributeSource, OrganizationAttributeType } from '@crowd/types'
33

44
import {
@@ -216,7 +216,32 @@ export function prepareOrganizationData(
216216
}
217217
}
218218

219-
// we should have organization data and processed attributes at the end
219+
// Infer country from location when missing
220+
if (
221+
!attributes.some(({ name }) => name === 'country') &&
222+
!(existingAttributes ?? []).some(({ name }) => name === 'country')
223+
) {
224+
const location =
225+
attributes.find(({ name, default: isDefault }) => name === 'location' && isDefault)?.value ??
226+
(existingAttributes ?? []).find(
227+
({ name, default: isDefault }) => name === 'location' && isDefault,
228+
)?.value ??
229+
existingOrg?.location
230+
231+
const country = getCountry(location)
232+
233+
if (country) {
234+
attributes.push({
235+
name: 'country',
236+
source: OrganizationAttributeSource.SYSTEM,
237+
default: true,
238+
value: country,
239+
})
240+
241+
orgRes.country = country
242+
}
243+
}
244+
220245
return {
221246
organization: orgRes,
222247
attributes,

services/libs/types/src/db/organizations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export interface OrganizationDbRow {
88
revenueRange: Record<string, unknown> | null
99
importHash: string | null
1010
location: string | null
11+
country: string | null
1112
isTeamOrganization: boolean
1213
isAffiliationBlocked: boolean
1314
type: string | null

services/libs/types/src/enums/organizations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export enum OrganizationIdentityType {
4242
export enum OrganizationAttributeSource {
4343
CUSTOM = 'custom',
4444
LFX_SERVE = 'lfx-serve',
45+
SYSTEM = 'system',
4546
ENRICHMENT_LFX_INTERNAL_API = 'enrichment-lfx-internal-api',
4647
ENRICHMENT_PEOPLEDATALABS = 'enrichment-peopledatalabs',
4748
CVENT = 'cvent',

0 commit comments

Comments
 (0)