-
Notifications
You must be signed in to change notification settings - Fork 727
Improvement/stricter serp api enrichment filter #2670
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
842aa4f
3d7f7b8
52ecd05
9d44c1c
66f54f0
aa80955
5e47a45
abb976d
0808d9a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,10 +1,16 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { findMemberIdentityWithTheMostActivityInPlatform as findMemberIdentityWithTheMostActivityInPlatformQuestDb } from '@crowd/data-access-layer/src/activities' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| findMemberEnrichmentCacheDb, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| insertMemberEnrichmentCacheDb, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| touchMemberEnrichmentCacheUpdatedAtDb, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| updateMemberEnrichmentCacheDb, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } from '@crowd/data-access-layer/src/old/apps/premium/members_enrichment_worker' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { IMemberEnrichmentCache, MemberEnrichmentSource } from '@crowd/types' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { RedisCache } from '@crowd/redis' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| IEnrichableMemberIdentityActivityAggregate, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| IMemberEnrichmentCache, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| MemberEnrichmentSource, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } from '@crowd/types' | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| import { EnrichmentSourceServiceFactory } from '../factory' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { svc } from '../main' | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -27,7 +33,7 @@ export async function getEnrichmentData( | |||||||||||||||||||||||||||||||||||||||||||||||||
| input: IEnrichmentSourceInput, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<IMemberEnrichmentData | null> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const service = EnrichmentSourceServiceFactory.getEnrichmentSourceService(source, svc.log) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (service.isEnrichableBySource(input)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (service.isEnrichableBySource(input) && (await hasRemainingCredits(source))) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return service.getData(input) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return null | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -52,6 +58,41 @@ export async function isCacheObsolete( | |||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function setHasRemainingCredits( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| source: MemberEnrichmentSource, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| hasCredits: boolean, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const redisCache = new RedisCache(`enrichment-${source}`, svc.redis, svc.log) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (hasCredits) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await redisCache.set('hasRemainingCredits', 'true', 60) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await redisCache.set('hasRemainingCredits', 'false', 60) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function getHasRemainingCredits(source: MemberEnrichmentSource): Promise<boolean> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const redisCache = new RedisCache(`enrichment-${source}`, svc.redis, svc.log) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return (await redisCache.get('hasRemainingCredits')) === 'true' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+73
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle Missing Cache Entries in If the cache key does not exist, Modify the function to handle export async function getHasRemainingCredits(source: MemberEnrichmentSource): Promise<boolean> {
const redisCache = new RedisCache(`enrichment-${source}`, svc.redis, svc.log)
- return (await redisCache.get('hasRemainingCredits')) === 'true'
+ const value = await redisCache.get('hasRemainingCredits')
+ if (value === 'true') {
+ return true
+ } else if (value === 'false') {
+ return false
+ } else {
+ return false // or consider throwing an error if appropriate
+ }
}📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function hasRemainingCreditsExists(source: MemberEnrichmentSource): Promise<boolean> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const redisCache = new RedisCache(`enrichment-${source}`, svc.redis, svc.log) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return await redisCache.exists('hasRemainingCredits') | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function hasRemainingCredits(source: MemberEnrichmentSource): Promise<boolean> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const service = EnrichmentSourceServiceFactory.getEnrichmentSourceService(source, svc.log) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (await hasRemainingCreditsExists(source)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return getHasRemainingCredits(source) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const hasCredits = await service.hasRemainingCredits() | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| await setHasRemainingCredits(source, hasCredits) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return hasCredits | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+83
to
+94
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Optimize The current implementation of Refactor the function as follows: export async function hasRemainingCredits(source: MemberEnrichmentSource): Promise<boolean> {
const cachedValue = await getHasRemainingCredits(source)
- if (await hasRemainingCreditsExists(source)) {
- return getHasRemainingCredits(source)
- }
+ if (cachedValue !== null) {
+ return cachedValue
+ }
const service = EnrichmentSourceServiceFactory.getEnrichmentSourceService(source, svc.log)
const hasCredits = await service.hasRemainingCredits()
await setHasRemainingCredits(source, hasCredits)
return hasCredits
}📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function findMemberEnrichmentCache( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| source: MemberEnrichmentSource, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| memberId: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -81,3 +122,10 @@ export async function touchMemberEnrichmentCacheUpdatedAt( | |||||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<void> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await touchMemberEnrichmentCacheUpdatedAtDb(svc.postgres.writer.connection(), memberId, source) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function findMemberIdentityWithTheMostActivityInPlatform( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| memberId: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| platform: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<IEnrichableMemberIdentityActivityAggregate> { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return findMemberIdentityWithTheMostActivityInPlatformQuestDb(svc.questdbSQL, memberId, platform) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,7 +27,9 @@ import { | |
| export default class EnrichmentServiceClearbit extends LoggerBase implements IEnrichmentService { | ||
| public source: MemberEnrichmentSource = MemberEnrichmentSource.CLEARBIT | ||
| public platform = `enrichment-${this.source}` | ||
| public enrichableBySql = `mi.type = 'email' and mi.verified` | ||
| public enrichMembersWithActivityMoreThan = 10 | ||
|
|
||
| public enrichableBySql = `"activitySummary".total_count > ${this.enrichMembersWithActivityMoreThan} AND mi.type = 'email' and mi.verified` | ||
|
|
||
| // bust cache after 120 days | ||
| public cacheObsoleteAfterSeconds = 60 * 60 * 24 * 120 | ||
|
|
@@ -63,6 +65,10 @@ export default class EnrichmentServiceClearbit extends LoggerBase implements IEn | |
| return enriched | ||
| } | ||
|
|
||
| async hasRemainingCredits(): Promise<boolean> { | ||
| return true | ||
| } | ||
|
Comment on lines
+68
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Implement actual credit checking logic similar to SERP service The current implementation always returns - async hasRemainingCredits(): Promise<boolean> {
- return true
- }
+ async hasRemainingCredits(): Promise<boolean> {
+ try {
+ const response = await axios.get('https://api.clearbit.com/v1/remaining_credits', {
+ auth: {
+ username: process.env['CROWD_ENRICHMENT_CLEARBIT_API_KEY'],
+ password: ''
+ }
+ });
+ return response.data.remaining > 0;
+ } catch (error) {
+ this.log.error('Failed to check Clearbit credits:', error);
+ return false;
+ }
+ }
🔗 Analysis chainImplement actual credit checking logic. The current implementation always returns Let's verify if other enrichment services have proper credit checking implemented: Consider implementing proper credit checking: - async hasRemainingCredits(): Promise<boolean> {
- return true
- }
+ async hasRemainingCredits(): Promise<boolean> {
+ try {
+ // Add actual credit checking logic here
+ // Example: Check Clearbit API quota/usage endpoints
+ return true
+ } catch (err) {
+ this.log.error(`Failed to check Clearbit credits: ${err}`)
+ return false
+ }
+ }🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Search for hasRemainingCredits implementations in other enrichment services
ast-grep --pattern 'async hasRemainingCredits(): Promise<boolean> {
$$$
}'
Length of output: 78 Script: #!/bin/bash
# Let's try a broader search for hasRemainingCredits implementations
rg -l "hasRemainingCredits"
# Then let's look at the interface definition
rg "interface.*EnrichmentService" -A 10
Length of output: 1616 Script: #!/bin/bash
# Let's examine the implementations in other services
rg "hasRemainingCredits.*Promise<boolean>" -A 5 services/apps/premium/members_enrichment_worker/src/sources/serp/service.ts services/apps/premium/members_enrichment_worker/src/sources/progai/service.ts
Length of output: 1554 Script: #!/bin/bash
# Let's see the complete SERP implementation to understand the credit checking logic
rg "hasRemainingCredits.*Promise<boolean>" -A 15 services/apps/premium/members_enrichment_worker/src/sources/serp/service.ts
Length of output: 622 |
||
|
|
||
| private async getDataUsingEmail(email: string): Promise<IMemberEnrichmentDataClearbit> { | ||
| let response: IMemberEnrichmentClearbitAPIResponse | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -124,6 +124,10 @@ export default class EnrichmentServiceProgAI extends LoggerBase implements IEnri | |
| return enrichableUsingGithubHandle || enrichableUsingEmail | ||
| } | ||
|
|
||
| async hasRemainingCredits(): Promise<boolean> { | ||
| return true | ||
| } | ||
|
Comment on lines
+127
to
+129
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Align implementation with existing patterns. To maintain consistency with the rest of the codebase, consider these improvements:
Here's a suggested implementation: async hasRemainingCredits(): Promise<boolean> {
- return true
+ try {
+ this.log.debug('Checking ProgAI remaining credits')
+ // Add credit checking logic here
+ const hasCredits = true // Replace with actual check
+ this.log.debug(`ProgAI credits available: ${hasCredits}`)
+ return hasCredits
+ } catch (err) {
+ this.log.error('Error checking ProgAI credits', err)
+ throw new Error(`Failed to check ProgAI credits: ${err.message}`)
+ }
}
|
||
|
|
||
| async getData(input: IEnrichmentSourceInput): Promise<IMemberEnrichmentDataProgAI> { | ||
| let enriched: IMemberEnrichmentDataProgAI = null | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -37,6 +37,10 @@ export interface IEnrichmentService { | |
| // can the source enrich using this input | ||
| isEnrichableBySource(input: IEnrichmentSourceInput): boolean | ||
|
|
||
| // does the source have credits to enrich members, if returned false the source will be skipped | ||
| // response will be saved to redis for 60 seconds and will be used for subsequent calls | ||
| hasRemainingCredits(): Promise<boolean> | ||
|
Comment on lines
+40
to
+42
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Codebase verification Implementation check reveals potential issues with credit validation The verification shows that:
• 🔗 Analysis chainVerify implementation across all enrichment services. Let's ensure all enrichment services properly implement the new Let me try a different approach to search for the implementations. Let me check specifically for the 🏁 Scripts executedThe following scripts were executed for the analysis: Script: #!/bin/bash
# Description: Check implementation of hasRemainingCredits across enrichment services
# Test: Search for class implementations of enrichment services
echo "Searching for enrichment service implementations..."
ast-grep --pattern 'class $_ implements IEnrichmentService {
$$$
}'
# Test: Verify hasRemainingCredits implementation in each service
echo "Verifying hasRemainingCredits implementation..."
ast-grep --pattern 'async hasRemainingCredits(): Promise<boolean> {
$$$
}'
Length of output: 368 Script: #!/bin/bash
# Search for files containing IEnrichmentService
echo "Files referencing IEnrichmentService:"
rg "IEnrichmentService" -l
# Search for class implementations and hasRemainingCredits
echo -e "\nImplementations and method details:"
rg "class.*implements.*IEnrichmentService" -A 20
Length of output: 8082 Script: #!/bin/bash
# Check for hasRemainingCredits implementation in each service file
echo "Checking SERP implementation:"
rg "hasRemainingCredits" services/apps/premium/members_enrichment_worker/src/sources/serp/service.ts -A 5
echo -e "\nChecking Clearbit implementation:"
rg "hasRemainingCredits" services/apps/premium/members_enrichment_worker/src/sources/clearbit/service.ts -A 5
echo -e "\nChecking ProgAI implementation:"
rg "hasRemainingCredits" services/apps/premium/members_enrichment_worker/src/sources/progai/service.ts -A 5
Length of output: 1195 |
||
|
|
||
| // SQL filter to get enrichable members for a source | ||
| // members table is available as "members" alias | ||
| // memberIdentities table is available as "mi" alias | ||
|
|
@@ -66,7 +70,7 @@ export interface IMemberEnrichmentDataNormalizedOrganization { | |
| } | ||
|
|
||
| export interface IGetMembersForEnrichmentArgs { | ||
| afterId?: string | ||
| afterCursor: { activityCount: number; memberId: string } | null | ||
| } | ||
|
|
||
| export interface IMemberEnrichmentSocialData { | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -8,6 +8,7 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ActivityDisplayVariant, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IActivityBySentimentMoodResult, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IActivityByTypeAndPlatformResult, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IEnrichableMemberIdentityActivityAggregate, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| IMemberIdentity, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ITimeseriesDatapoint, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| MemberIdentityType, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -1391,3 +1392,24 @@ export async function getLastActivitiesForMembers( | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| segmentIds, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export async function findMemberIdentityWithTheMostActivityInPlatform( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| qdbConn: DbConnOrTx, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| platform: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| memberId: string, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): Promise<IEnrichableMemberIdentityActivityAggregate> { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const query = ` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SELECT count(a.id) AS "activityCount", a.platform, a.username | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FROM activities a | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WHERE a."memberId" = $(memberId) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AND a.platform = $(platform) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GROUP BY a.platform, a.username | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ORDER BY activity_count DESC | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LIMIT 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return qdbConn.oneOrNone(query, { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| memberId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| platform, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1396
to
+1415
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix SQL query issues and add proper type mapping There are several issues in the implementation:
Apply this diff to fix the issues: export async function findMemberIdentityWithTheMostActivityInPlatform(
qdbConn: DbConnOrTx,
platform: string,
memberId: string,
): Promise<IEnrichableMemberIdentityActivityAggregate> {
const query = `
- SELECT count(a.id) AS "activityCount", a.platform, a.username
+ SELECT COUNT(a.id) AS "activityCount", a."platform", a."username"
FROM activities a
WHERE a."memberId" = $(memberId)
AND a.platform = $(platform)
+ AND a."deletedAt" IS NULL
- GROUP BY a.platform, a.username
- ORDER BY activity_count DESC
+ GROUP BY a."platform", a."username"
+ ORDER BY "activityCount" DESC
LIMIT 1;
`
- return qdbConn.oneOrNone(query, {
+ const result = await qdbConn.oneOrNone(query, {
memberId,
platform,
})
+
+ return result ? {
+ activityCount: parseInt(result.activityCount),
+ platform: result.platform,
+ username: result.username
+ } : null
}📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Function needs unit tests
The implementation of
findMemberIdentityWithTheMostActivityInPlatformwas found inservices/libs/data-access-layer/src/activities/sql.ts, but no corresponding test files were discovered. Since this is a new backend functionality that executes SQL queries, it should be properly tested.findMemberIdentityWithTheMostActivityInPlatforminservices/libs/data-access-layer/src/activities/sql.test.ts🔗 Analysis chain
LGTM! Changes follow established patterns.
The addition of
findMemberIdentityWithTheMostActivityInPlatformto imports and exports is clean and maintains consistent ordering.Let's verify the test coverage for this new functionality:
Also applies to: 54-54
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
Length of output: 977
Script:
Length of output: 280
Script:
Length of output: 36040