@@ -7,7 +7,11 @@ import {
77} from "@databuddy/db/schema" ;
88import { eq } from "@databuddy/db" ;
99import { appRouter , type Context } from "@databuddy/rpc" ;
10- import { splitTraits , upsertProfile } from "@databuddy/services/identity" ;
10+ import {
11+ resolveTraitSegment ,
12+ splitTraits ,
13+ upsertProfile ,
14+ } from "@databuddy/services/identity" ;
1115import {
1216 addToOrganization ,
1317 cleanup ,
@@ -246,3 +250,89 @@ describe("upsertProfile trait history", () => {
246250 ) . toHaveLength ( 0 ) ;
247251 } ) ;
248252} ) ;
253+
254+ describe ( "profiles.traitKeys / traitValues" , ( ) => {
255+ iit ( "lists distinct keys and values for the website only" , async ( ) => {
256+ const user = await signUp ( ) ;
257+ const org = await insertOrganization ( ) ;
258+ await addToOrganization ( user . id , org . id , "member" ) ;
259+ const website = await insertWebsite ( { organizationId : org . id } ) ;
260+ const otherWebsite = await insertWebsite ( { organizationId : org . id } ) ;
261+ await seedProfile ( website . id , "user_1" , {
262+ traits : { plan : "pro" , beta : true } ,
263+ } ) ;
264+ await seedProfile ( website . id , "user_2" , { traits : { plan : "free" } } ) ;
265+ await seedProfile ( otherWebsite . id , "user_3" , {
266+ traits : { region : "eu" } ,
267+ } ) ;
268+ const ctx = userContext ( user , org . id ) ;
269+
270+ const keys = await call ( appRouter . profiles . traitKeys , ctx ) ( {
271+ websiteId : website . id ,
272+ } ) ;
273+ expect ( keys ) . toEqual ( [ "beta" , "plan" ] ) ;
274+
275+ const values = await call ( appRouter . profiles . traitValues , ctx ) ( {
276+ websiteId : website . id ,
277+ key : "plan" ,
278+ } ) ;
279+ expect ( values ) . toEqual ( [ "free" , "pro" ] ) ;
280+ } ) ;
281+
282+ iit ( "rejects non-members" , async ( ) => {
283+ const user = await signUp ( ) ;
284+ const org = await insertOrganization ( ) ;
285+ const website = await insertWebsite ( { organizationId : org . id } ) ;
286+ const ctx = userContext ( user , org . id ) ;
287+
288+ await expectCode (
289+ call ( appRouter . profiles . traitKeys , ctx ) ( { websiteId : website . id } ) ,
290+ "FORBIDDEN"
291+ ) ;
292+ } ) ;
293+ } ) ;
294+
295+ describe ( "resolveTraitSegment" , ( ) => {
296+ iit ( "resolves profile ids by trait predicate scoped to the website" , async ( ) => {
297+ const org = await insertOrganization ( ) ;
298+ const website = await insertWebsite ( { organizationId : org . id } ) ;
299+ const otherWebsite = await insertWebsite ( { organizationId : org . id } ) ;
300+ await seedProfile ( website . id , "user_1" , { traits : { plan : "pro" } } ) ;
301+ await seedProfile ( website . id , "user_2" , { traits : { plan : "free" } } ) ;
302+ await seedProfile ( website . id , "user_3" , {
303+ traits : { plan : "pro" , beta : true } ,
304+ } ) ;
305+ await seedProfile ( otherWebsite . id , "user_4" , { traits : { plan : "pro" } } ) ;
306+
307+ const pro = await resolveTraitSegment ( website . id , [
308+ { field : "trait:plan" , op : "eq" , value : "pro" } ,
309+ ] ) ;
310+ expect ( pro . sort ( ) ) . toEqual ( [ "user_1" , "user_3" ] ) ;
311+
312+ const proBeta = await resolveTraitSegment ( website . id , [
313+ { field : "trait:plan" , op : "eq" , value : "pro" } ,
314+ { field : "trait:beta" , op : "eq" , value : "true" } ,
315+ ] ) ;
316+ expect ( proBeta ) . toEqual ( [ "user_3" ] ) ;
317+
318+ const notPro = await resolveTraitSegment ( website . id , [
319+ { field : "trait:plan" , op : "ne" , value : "pro" } ,
320+ ] ) ;
321+ expect ( notPro ) . toEqual ( [ "user_2" ] ) ;
322+
323+ const inList = await resolveTraitSegment ( website . id , [
324+ { field : "trait:plan" , op : "in" , value : [ "free" , "trial" ] } ,
325+ ] ) ;
326+ expect ( inList ) . toEqual ( [ "user_2" ] ) ;
327+
328+ const emptyIn = await resolveTraitSegment ( website . id , [
329+ { field : "trait:plan" , op : "in" , value : [ ] } ,
330+ ] ) ;
331+ expect ( emptyIn ) . toEqual ( [ ] ) ;
332+
333+ const emptyNotIn = await resolveTraitSegment ( website . id , [
334+ { field : "trait:plan" , op : "not_in" , value : [ ] } ,
335+ ] ) ;
336+ expect ( emptyNotIn . sort ( ) ) . toEqual ( [ "user_1" , "user_2" , "user_3" ] ) ;
337+ } ) ;
338+ } ) ;
0 commit comments