mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	feat: persist client application usage (#4534)
Closes # [1-1256](https://linear.app/unleash/issue/1-1256/backend-to-save-application-usage) Adds client application usage persisting on upsert and bulkUpsert functions --------- Signed-off-by: andreas-unleash <andreas@getunleash.ai>
This commit is contained in:
		
							parent
							
								
									68273da213
								
							
						
					
					
						commit
						d19d97cf18
					
				@ -21,6 +21,8 @@ const COLUMNS = [
 | 
			
		||||
];
 | 
			
		||||
const TABLE = 'client_applications';
 | 
			
		||||
 | 
			
		||||
const TABLE_USAGE = 'client_applications_usage';
 | 
			
		||||
 | 
			
		||||
const mapRow: (any) => IClientApplication = (row) => ({
 | 
			
		||||
    appName: row.app_name,
 | 
			
		||||
    createdAt: row.created_at,
 | 
			
		||||
@ -57,6 +59,14 @@ const remapRow = (input) => {
 | 
			
		||||
    return temp;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const remapUsageRow = (input) => {
 | 
			
		||||
    return {
 | 
			
		||||
        app_name: input.appName,
 | 
			
		||||
        project: input.project || '*',
 | 
			
		||||
        environment: input.environment || '*',
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default class ClientApplicationsStore
 | 
			
		||||
    implements IClientApplicationsStore
 | 
			
		||||
{
 | 
			
		||||
@ -72,11 +82,21 @@ export default class ClientApplicationsStore
 | 
			
		||||
    async upsert(details: Partial<IClientApplication>): Promise<void> {
 | 
			
		||||
        const row = remapRow(details);
 | 
			
		||||
        await this.db(TABLE).insert(row).onConflict('app_name').merge();
 | 
			
		||||
        const usageRow = remapUsageRow(details);
 | 
			
		||||
        await this.db(TABLE_USAGE)
 | 
			
		||||
            .insert(usageRow)
 | 
			
		||||
            .onConflict(['app_name', 'project', 'environment'])
 | 
			
		||||
            .merge();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async bulkUpsert(apps: Partial<IClientApplication>[]): Promise<void> {
 | 
			
		||||
        const rows = apps.map(remapRow);
 | 
			
		||||
        const usageRows = apps.map(remapUsageRow);
 | 
			
		||||
        await this.db(TABLE).insert(rows).onConflict('app_name').merge();
 | 
			
		||||
        await this.db(TABLE_USAGE)
 | 
			
		||||
            .insert(usageRows)
 | 
			
		||||
            .onConflict(['app_name', 'project', 'environment'])
 | 
			
		||||
            .merge();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async exists(appName: string): Promise<boolean> {
 | 
			
		||||
 | 
			
		||||
@ -63,12 +63,23 @@ export default class RegisterController extends Controller {
 | 
			
		||||
        return 'default';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static extractProjectFromRequest(
 | 
			
		||||
        req: IAuthRequest<unknown, void, ClientApplicationSchema>,
 | 
			
		||||
    ) {
 | 
			
		||||
        const token = req.get('Authorisation');
 | 
			
		||||
        if (token) {
 | 
			
		||||
            return token.split(':')[0];
 | 
			
		||||
        }
 | 
			
		||||
        return 'default';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async registerClientApplication(
 | 
			
		||||
        req: IAuthRequest<unknown, void, ClientApplicationSchema>,
 | 
			
		||||
        res: Response<void>,
 | 
			
		||||
    ): Promise<void> {
 | 
			
		||||
        const { body: data, ip: clientIp, user } = req;
 | 
			
		||||
        data.environment = RegisterController.resolveEnvironment(user, data);
 | 
			
		||||
        data.project = RegisterController.extractProjectFromRequest(req);
 | 
			
		||||
        await this.clientInstanceService.registerClient(data, clientIp);
 | 
			
		||||
        res.status(202).end();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -91,4 +91,5 @@ export const clientRegisterSchema = joi
 | 
			
		||||
        started: joi.date().required(),
 | 
			
		||||
        interval: joi.number().required(),
 | 
			
		||||
        environment: joi.string().optional(),
 | 
			
		||||
        project: joi.string().optional(),
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,32 @@
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
exports.up = function (db, callback) {
 | 
			
		||||
    db.runSql(
 | 
			
		||||
        `
 | 
			
		||||
        DROP TABLE IF EXISTS client_applications_usage;
 | 
			
		||||
 | 
			
		||||
        CREATE TABLE IF NOT EXISTS client_applications_usage (
 | 
			
		||||
           app_name VARCHAR(255) REFERENCES client_applications(app_name) ON DELETE CASCADE,
 | 
			
		||||
           project VARCHAR(255) NOT NULL ,
 | 
			
		||||
           environment VARCHAR(100) NOT NULL ,
 | 
			
		||||
           PRIMARY KEY(app_name, project, environment)
 | 
			
		||||
        ) ;
 | 
			
		||||
    `,
 | 
			
		||||
        callback,
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
exports.down = function (db, callback) {
 | 
			
		||||
    db.runSql(
 | 
			
		||||
        `
 | 
			
		||||
        DROP TABLE IF EXISTS client_applications_usage;
 | 
			
		||||
        CREATE TABLE IF NOT EXISTS client_applications_usage (
 | 
			
		||||
           app_name VARCHAR(255) REFERENCES client_applications(app_name) ON DELETE CASCADE,
 | 
			
		||||
           project VARCHAR(255) REFERENCES projects(id) ON DELETE CASCADE,
 | 
			
		||||
           environment VARCHAR(100) REFERENCES environments(name) ON DELETE CASCADE,
 | 
			
		||||
           PRIMARY KEY(app_name, project, environment)
 | 
			
		||||
        ) ;
 | 
			
		||||
    `,
 | 
			
		||||
        callback,
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user