if (userPluginConfig.isFunnelAnalysisEnabled()) { binder.bind(FunnelQueryExecutor.class).to(PostgresqlFunnelQueryExecutor.class); if (userPluginConfig.isRetentionAnalysisEnabled()) { binder.bind(RetentionQueryExecutor.class).to(PostgresqlRetentionQueryExecutor.class); if (userPluginConfig.getEnableUserMapping()) { binder.bind(UserMergeTableHook.class).asEagerSingleton();
@Path("/get_online_users") @POST @JsonRequest @ApiOperation(value = "Get connected users", authorizations = @Authorization(value = "read_key") ) public CompletableFuture<Collection<Map<String, Object>>> getConnectedUsers(@Named("project") RequestContext context) { Collection<Object> connectedUsers = webSocketService.getConnectedUsers(context.project); return CompletableFuture.completedFuture(connectedUsers.stream() .map(id -> ImmutableMap.of(config.getIdentifierColumn(), id)) .collect(Collectors.toList())); }
private ActiveModuleList(UserPluginConfig userPluginConfig, boolean userStorageMailbox, RealTimeConfig realtimeConfig, EventStreamConfig eventStreamConfig, EventExplorerConfig eventExplorerConfig, UserPluginConfig userStorage, ProjectConfig projectConfig, boolean scheduledTasksEnabled, boolean webhookEnabled, boolean customDatabaseEnabled) { this.userStorage = userPluginConfig.isEnabled(); this.userMailbox = userStorageMailbox; this.funnelAnalysisEnabled = userPluginConfig.isFunnelAnalysisEnabled(); this.automationEnabled = userPluginConfig.getAutomationEnabled(); this.abTestingEnabled = userPluginConfig.getAbTestingEnabled(); this.retentionAnalysisEnabled = userPluginConfig.isRetentionAnalysisEnabled(); this.eventExplorer = eventExplorerConfig.isEventExplorerEnabled(); this.realtime = realtimeConfig.isRealtimeModuleEnabled(); this.eventStream = eventStreamConfig.getEventStreamEnabled(); this.userStorageEventFilter = userStorage.getStorageModule() != null; this.companyName = projectConfig.getCompanyName(); this.timeColumn = projectConfig.getTimeColumn(); this.userColumn = projectConfig.getUserColumn(); this.customDatabaseEnabled = customDatabaseEnabled; this.scheduledTasksEnabled = scheduledTasksEnabled; this.webhookEnabled = webhookEnabled; } }
Iterable<String> actionList = userPluginConfig.getActionList(); if (actionList != null) { for (String actionName : actionList) { if (userPluginConfig.getStorageModule() != null) { binder.bind(UserHttpService.class).asEagerSingleton(); if (!userPluginConfig.getEnableUserMapping()) { Multibinder<UserPropertyMapper> userPropertyMappers = Multibinder.newSetBinder(binder, UserPropertyMapper.class); Multibinder<EventMapper> eventMappers = Multibinder.newSetBinder(binder, EventMapper.class);
@Inject public PrestoRetentionQueryExecutor( ProjectConfig projectConfig, QueryExecutorService executor, Metastore metastore, MaterializedViewService materializedViewService, UserPluginConfig userPluginConfig) { this.projectConfig = projectConfig; this.executor = executor; this.metastore = metastore; this.materializedViewService = materializedViewService; this.userMappingEnabled = userPluginConfig.getEnableUserMapping(); }
@BeforeSuite public void setup() throws Exception { testingEnvironment = new TestingEnvironment(); PrestoConfig prestoConfig = testingEnvironment.getPrestoConfig(); InMemoryQueryMetadataStore queryMetadataStore = new InMemoryQueryMetadataStore(); metastore = new PrestoRakamRaptorMetastore(testingEnvironment.getPrestoMetastore(), new EventBus(), new ProjectConfig(), prestoConfig); metastore.setup(); PrestoQueryExecutor queryExecutor = new PrestoQueryExecutor(new ProjectConfig(), prestoConfig, null, metastore); PrestoMaterializedViewService materializedViewService = new PrestoMaterializedViewService( new PrestoConfig(), queryExecutor, metastore, queryMetadataStore, Clock.systemUTC()); QueryExecutorService queryExecutorService = new QueryExecutorService(queryExecutor, metastore, materializedViewService, '"'); retentionQueryExecutor = new PrestoRetentionQueryExecutor(new ProjectConfig(), queryExecutorService, metastore, materializedViewService, new UserPluginConfig()); testingPrestoEventStore = new TestingPrestoEventStore(queryExecutor, prestoConfig); // TODO: Presto throws "No node available" error, find a way to avoid this ugly hack. Thread.sleep(1000); super.setup(); }
@Inject public PrestoFunnelQueryExecutor( ProjectConfig projectConfig, PrestoConfig prestoConfig, FastGenericFunnelQueryExecutor fastPrestoFunnelQueryExecutor, PrestoApproxFunnelQueryExecutor approxFunnelQueryExecutor, Metastore metastore, QueryExecutor executor, UserPluginConfig userPluginConfig) { super(projectConfig, metastore, executor); this.prestoConfig = prestoConfig; this.fastPrestoFunnelQueryExecutor = fastPrestoFunnelQueryExecutor; this.approxFunnelQueryExecutor = approxFunnelQueryExecutor; this.userMappingEnabled = userPluginConfig.getEnableUserMapping(); this.fastPrestoFunnelQueryExecutor.setTimeStampMapping(timeStampMapping); this.approxFunnelQueryExecutor.setTimeStampMapping(timeStampMapping); super.timeStampMapping = timeStampMapping; }
@BeforeSuite @Override public void setup() throws Exception { testingEnvironment = new TestingEnvironment(); PrestoConfig prestoConfig = testingEnvironment.getPrestoConfig(); InMemoryQueryMetadataStore inMemoryQueryMetadataStore = new InMemoryQueryMetadataStore(); JDBCPoolDataSource prestoMetastore = testingEnvironment.getPrestoMetastore(); EventBus eventBus = new EventBus(); metastore = new PrestoRakamRaptorMetastore(prestoMetastore, eventBus, new ProjectConfig(), prestoConfig); metastore.setup(); PrestoQueryExecutor prestoQueryExecutor = new PrestoQueryExecutor(new ProjectConfig(), prestoConfig, null, metastore); PrestoMaterializedViewService materializedViewService = new PrestoMaterializedViewService( new PrestoConfig(), prestoQueryExecutor, metastore, inMemoryQueryMetadataStore, Clock.systemUTC()); QueryExecutorService queryExecutorService = new QueryExecutorService(prestoQueryExecutor, metastore, materializedViewService, '"'); FastGenericFunnelQueryExecutor fastGenericFunnelQueryExecutor = new FastGenericFunnelQueryExecutor(queryExecutorService, new ProjectConfig(), metastore); PrestoApproxFunnelQueryExecutor prestoApproxFunnelQueryExecutor = new PrestoApproxFunnelQueryExecutor(new ProjectConfig(), queryExecutorService, metastore); funnelQueryExecutor = new PrestoFunnelQueryExecutor(new ProjectConfig(), new PrestoConfig(), fastGenericFunnelQueryExecutor, prestoApproxFunnelQueryExecutor, metastore, prestoQueryExecutor, new UserPluginConfig()); testingPrestoEventStore = new TestingPrestoEventStore(prestoQueryExecutor, prestoConfig); super.setup(); }
if (userPluginConfig.getEnableUserMapping()) { binder.bind(UserMergeTableHook.class).asEagerSingleton(); if (userPluginConfig.isFunnelAnalysisEnabled()) { binder.bind(FunnelQueryExecutor.class).to(PrestoFunnelQueryExecutor.class); binder.bind(PrestoApproxFunnelQueryExecutor.class).asEagerSingleton(); if (userPluginConfig.isRetentionAnalysisEnabled()) { binder.bind(RetentionQueryExecutor.class).to(PrestoRetentionQueryExecutor.class);
.append(config.getEnableUserMapping() ? "coalesce(mapping._user, collection._user, collection._device_id) as _user" : "collection._user") .append(" from %s collection"); if (config.getEnableUserMapping() && getHasDeviceId(project, filter.collection)) { if (config.getEnableUserMapping()) { builder.append(" group by mapping._user, collection._user, collection._device_id"); } else {
@GET @ApiOperation(value = "Get user storage metadata", authorizations = @Authorization(value = "read_key")) @JsonRequest @Path("/metadata") public MetadataResponse getMetadata(@Named("project") RequestContext context) { return new MetadataResponse(config.getIdentifierColumn(), service.getMetadata(context)); }
if (userPluginConfig.getEnableUserMapping()) { throw new IllegalStateException("Clickhouse module doesn't support user mapping."); if (userPluginConfig.isFunnelAnalysisEnabled()) { binder.bind(FunnelQueryExecutor.class).to(ClickHouseFunnelQueryExecutor.class); if (userPluginConfig.isRetentionAnalysisEnabled()) { binder.bind(RetentionQueryExecutor.class).to(ClickHouseRetentionQueryExecutor.class);
public void merge(String project, Object user, Object anonymousId, Instant createdAt, Instant mergedAt) { if (!config.getEnableUserMapping()) { throw new RakamException(NOT_IMPLEMENTED); } GenericData.Record properties = new GenericData.Record(ANONYMOUS_USER_MAPPING_SCHEMA); properties.put(0, anonymousId); properties.put(1, user); properties.put(2, createdAt.toEpochMilli()); properties.put(3, mergedAt.toEpochMilli()); eventStore.store(new Event(project, ANONYMOUS_ID_MAPPING, null, null, properties)); } }
query = String.format("select distinct %s as %s from (%s) ", checkTableColumn(projectConfig.getUserColumn()), config.getIdentifierColumn(), eventFilter.stream().map(f -> String.format(getEventFilterQuery(context.project, f), checkCollection(f.collection))) .collect(Collectors.joining(" union all "))); config.getIdentifierColumn(), collections.stream().map(c -> String.format("select %s from %s collection where collection.%s is not null", "_user", checkCollection(c.getKey()), checkTableColumn(projectConfig.getUserColumn()))).collect(Collectors.joining(" union all ")));
@JsonRequest @ApiOperation(value = "Merge user with anonymous id", authorizations = @Authorization(value = "write_key")) @ApiResponses(value = {@ApiResponse(code = 404, message = "User does not exist.")}) @Path("/merge") @IgnoreApi @AllowCookie public void mergeUser(RakamHttpRequest request, @BodyParam MergeRequest mergeRequest) { // TODO: what if a user sends real user ids instead of its previous anonymous id? if (!config.getEnableUserMapping()) { throw new RakamException("The feature is not supported", PRECONDITION_FAILED); } Object anonymousId = mergeRequest.anonymousId; DefaultFullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, wrappedBuffer(OK_MESSAGE)); setBrowser(request, response); if (anonymousId == null) { throw new RakamException("Anonymous id is required", BAD_REQUEST); } String project = apiKeyService.getProjectOfApiKey(mergeRequest.api.apiKey, WRITE_KEY); service.merge(project, mergeRequest.id, anonymousId, Instant.ofEpochMilli(mergeRequest.createdAt), Instant.ofEpochMilli(mergeRequest.mergedAt)); request.response(response).end(); }
public void merge(String project, Object user, Object anonymousId, Instant createdAt, Instant mergedAt) { if (!config.getEnableUserMapping()) { throw new RakamException(HttpResponseStatus.NOT_IMPLEMENTED); } GenericData.Record properties = new GenericData.Record(ANONYMOUS_USER_MAPPING_SCHEMA); properties.put(0, anonymousId); properties.put(1, user); properties.put(2, (int) Math.floorDiv(createdAt.getEpochSecond(), 86400)); properties.put(3, (int) Math.floorDiv(mergedAt.getEpochSecond(), 86400)); eventStore.store(new Event(project, ANONYMOUS_ID_MAPPING, null, null, properties)); }