( profiles: IClickhouseProfile[], projectId: string )
| 140 | * Used by Mixpanel (and other providers) to import user profiles during an import job. |
| 141 | */ |
| 142 | export async function insertProfilesBatch( |
| 143 | profiles: IClickhouseProfile[], |
| 144 | projectId: string |
| 145 | ): Promise<{ inserted: number }> { |
| 146 | if (profiles.length === 0) { |
| 147 | return { inserted: 0 }; |
| 148 | } |
| 149 | |
| 150 | const normalized = profiles.map((p) => ({ |
| 151 | id: p.id, |
| 152 | project_id: projectId, |
| 153 | first_name: p.first_name ?? '', |
| 154 | last_name: p.last_name ?? '', |
| 155 | email: p.email ?? '', |
| 156 | avatar: p.avatar ?? '', |
| 157 | is_external: p.is_external ?? true, |
| 158 | properties: Object.fromEntries( |
| 159 | Object.entries(p.properties || {}).filter( |
| 160 | (kv): kv is [string, string] => kv[1] != null && kv[1] !== '' |
| 161 | ) |
| 162 | ) as Record<string, string>, |
| 163 | created_at: p.created_at, |
| 164 | last_seen_at: p.last_seen_at ?? p.created_at, |
| 165 | })); |
| 166 | |
| 167 | await ch.insert({ |
| 168 | table: TABLE_NAMES.profiles, |
| 169 | values: normalized, |
| 170 | format: 'JSONEachRow', |
| 171 | }); |
| 172 | |
| 173 | return { inserted: normalized.length }; |
| 174 | } |
| 175 | |
| 176 | /** |
| 177 | * Delete all staging data for an import. Used to get a clean slate on retry |
no test coverage detected