From 6cb93bc19c0e32d5cdb0db9f917df210979a8b8a Mon Sep 17 00:00:00 2001 From: Vinod Bangera <vinodbangera@niveussolutions.com> Date: Mon, 24 Feb 2025 08:25:59 +0530 Subject: [PATCH] extensionType and totalRequest --- Dockerfile | 21 +++++++++++++++++ config/db.js | 19 +++++++++++++++- controllers/aggregateMetric.js | 32 +++++++++++++------------- controllers/usageMetric.js | 40 ++++++++++++++++++++++++++++----- index.js | 6 ++++- node_modules/.package-lock.json | 12 ++++++++++ package-lock.json | 15 ++++++++++++- package.json | 3 ++- 8 files changed, 124 insertions(+), 24 deletions(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..52e6511 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +FROM node:20 as dependencies +# Create and change to the app directory +WORKDIR /usr/src/app + +# Copy package.json and package-lock.json +COPY package*.json ./ + +# Install dependencies +RUN npm install + +# Copy the rest of the application code +COPY . . + +# Expose the port the app runs on +EXPOSE 8080 + +# Define the environment variable for the port +ENV PORT 8080 + +# Start the application +CMD ["node", "index.js"] \ No newline at end of file diff --git a/config/db.js b/config/db.js index c9ad086..77b676e 100644 --- a/config/db.js +++ b/config/db.js @@ -1,4 +1,5 @@ const { Pool } = require("pg"); +const { v4: uuidv4 } = require("uuid"); require("dotenv").config(); const pool = new Pool({ @@ -19,14 +20,30 @@ pool.connect() email VARCHAR(255) NOT NULL, projectId VARCHAR(255) NOT NULL, requestType VARCHAR(50) CHECK (requestType IN ('completion', 'explanation', 'documentation', 'testcase')), + extensionType VARCHAR(50) CHECK (extensionType IN ('vscode', 'intellij')), + totalRequest INT DEFAULT 0, linesOfCodeSuggested INT DEFAULT 0, linesOfCodeAccepted INT DEFAULT 0, - requestId UUID DEFAULT gen_random_uuid(), + requestId UUID NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); `; + const checkConstraintQuery = ` + SELECT conname + FROM pg_constraint + WHERE conname = 'unique_email_requesttype'; + `; + + const alterTableQuery = ` + ALTER TABLE usage_metrics ADD CONSTRAINT unique_email_requesttype UNIQUE (email, requestType, extensionType); + `; + await client.query(createTableQuery); + const result = await client.query(checkConstraintQuery); + if (result.rows.length === 0) { + await client.query(alterTableQuery); + } console.log("Table 'usage_metrics' is ready"); client.release(); diff --git a/controllers/aggregateMetric.js b/controllers/aggregateMetric.js index 24711e0..ccfa09b 100644 --- a/controllers/aggregateMetric.js +++ b/controllers/aggregateMetric.js @@ -2,7 +2,7 @@ const pool = require("../config/db"); const handleGetAggregateMetrics = async (req, res) => { try { - let { userId, startDate, endDate } = req.query; + let { userId, startDate, endDate, extensionType } = req.query; if (!startDate || !endDate) { let now = new Date(); @@ -22,43 +22,45 @@ const handleGetAggregateMetrics = async (req, res) => { SELECT email AS user, projectId, - COUNT(*) AS totalRequests, + COALESCE(SUM(totalRequest), 0) AS totalRequests, COALESCE(SUM(linesOfCodeSuggested), 0) AS totalSuggested, COALESCE(SUM(linesOfCodeAccepted), 0) AS totalAccepted, - COUNT(*) FILTER (WHERE requestType = 'completion') AS completionRequests, + COALESCE(SUM(totalRequest) FILTER (WHERE requestType = 'completion'), 0) AS completionRequests, COALESCE(SUM(linesOfCodeSuggested) FILTER (WHERE requestType = 'completion'), 0) AS completionSuggested, COALESCE(SUM(linesOfCodeAccepted) FILTER (WHERE requestType = 'completion'), 0) AS completionAccepted, - COUNT(*) FILTER (WHERE requestType = 'explanation') AS explanationRequests, - COUNT(*) FILTER (WHERE requestType = 'documentation') AS documentationRequests, - COUNT(*) FILTER (WHERE requestType = 'testcase') AS testcaseRequests, + COALESCE(SUM(totalRequest) FILTER (WHERE requestType = 'explanation'), 0) AS explanationRequests, + COALESCE(SUM(totalRequest) FILTER (WHERE requestType = 'documentation'), 0) AS documentationRequests, + COALESCE(SUM(totalRequest) FILTER (WHERE requestType = 'testcase'), 0) AS testcaseRequests, COALESCE(SUM(linesOfCodeSuggested) FILTER (WHERE requestType = 'testcase'), 0) AS testcaseSuggested FROM usage_metrics WHERE LOWER(email) = LOWER($1) AND created_at BETWEEN $2 AND $3 + ${extensionType ? 'AND extensionType = $4' : ''} GROUP BY email, projectId `; - values = [userId, startDate, endDate]; + values = extensionType ? [userId, startDate, endDate, extensionType] : [userId, startDate, endDate]; } else { - // Q overall metrics (all users) + // overall metrics (all users) query = ` SELECT - COUNT(*) AS totalRequests, + COALESCE(SUM(totalRequest), 0) AS totalRequests, COALESCE(SUM(linesOfCodeSuggested), 0) AS totalSuggested, COALESCE(SUM(linesOfCodeAccepted), 0) AS totalAccepted, - COUNT(*) FILTER (WHERE requestType = 'completion') AS completionRequests, + COALESCE(SUM(totalRequest) FILTER (WHERE requestType = 'completion'), 0) AS completionRequests, COALESCE(SUM(linesOfCodeSuggested) FILTER (WHERE requestType = 'completion'), 0) AS completionSuggested, COALESCE(SUM(linesOfCodeAccepted) FILTER (WHERE requestType = 'completion'), 0) AS completionAccepted, - COUNT(*) FILTER (WHERE requestType = 'explanation') AS explanationRequests, - COUNT(*) FILTER (WHERE requestType = 'documentation') AS documentationRequests, - COUNT(*) FILTER (WHERE requestType = 'testcase') AS testcaseRequests, + COALESCE(SUM(totalRequest) FILTER (WHERE requestType = 'explanation'), 0) AS explanationRequests, + COALESCE(SUM(totalRequest) FILTER (WHERE requestType = 'documentation'), 0) AS documentationRequests, + COALESCE(SUM(totalRequest) FILTER (WHERE requestType = 'testcase'), 0) AS testcaseRequests, COALESCE(SUM(linesOfCodeSuggested) FILTER (WHERE requestType = 'testcase'), 0) AS testcaseSuggested FROM usage_metrics WHERE created_at BETWEEN $1 AND $2 + ${extensionType ? 'AND extensionType = $3' : ''} `; - values = [startDate, endDate]; + values = extensionType ? [startDate, endDate, extensionType] : [startDate, endDate]; } - console.log("Executing Query:", query, "Values:", values); + // console.log("Executing Query:", query, "Values:", values); const result = await pool.query(query, values); diff --git a/controllers/usageMetric.js b/controllers/usageMetric.js index d840eea..0165d0e 100644 --- a/controllers/usageMetric.js +++ b/controllers/usageMetric.js @@ -1,9 +1,11 @@ const pool = require("../config/db"); +const { v4: uuidv4 } = require("uuid"); const handleGetUsageMetrics = async (req, res) => { try { + console.log("Fetching usage metrics..."); const result = await pool.query(` - SELECT id, email, projectId, requestType, linesOfCodeSuggested, linesOfCodeAccepted, created_at + SELECT id, email, projectId, requestType, extensionType, linesOfCodeSuggested, linesOfCodeAccepted, created_at FROM usage_metrics ORDER BY created_at DESC; `); @@ -29,6 +31,7 @@ const handlePostrecordUsageMetric = async (req, res) => { email, projectId, requestType, + extensionType, linesOfCodeSuggested, linesOfCodeAccepted, } = req.body; @@ -37,6 +40,7 @@ const handlePostrecordUsageMetric = async (req, res) => { !email || !projectId || !requestType || + !extensionType || linesOfCodeSuggested === undefined || linesOfCodeAccepted === undefined ) { @@ -45,18 +49,44 @@ const handlePostrecordUsageMetric = async (req, res) => { .json({ success: false, message: "All fields are required." }); } - const query = ` - INSERT INTO usage_metrics (email, projectId, requestType, linesOfCodeSuggested, linesOfCodeAccepted) - VALUES ($1, $2, $3, $4, $5) RETURNING id; - `; + const requestId = uuidv4(); + + let query; const values = [ email, projectId, requestType, + extensionType, linesOfCodeSuggested, linesOfCodeAccepted, + requestId, ]; + if (requestType === 'completion' && linesOfCodeSuggested === 0) { + query = ` + INSERT INTO usage_metrics (email, projectId, requestType, extensionType, linesOfCodeSuggested, linesOfCodeAccepted, requestId) + VALUES ($1, $2, $3, $4, $5, $6, $7) + ON CONFLICT (email, requestType, extensionType) + DO UPDATE SET + projectId = EXCLUDED.projectId, + linesOfCodeSuggested = usage_metrics.linesOfCodeSuggested + EXCLUDED.linesOfCodeSuggested, + linesOfCodeAccepted = usage_metrics.linesOfCodeAccepted + EXCLUDED.linesOfCodeAccepted + RETURNING id; + `; + } else { + query = ` + INSERT INTO usage_metrics (email, projectId, requestType, extensionType, linesOfCodeSuggested, linesOfCodeAccepted, requestId, totalRequest) + VALUES ($1, $2, $3, $4, $5, $6, $7, 1) + ON CONFLICT (email, requestType, extensionType) + DO UPDATE SET + projectId = EXCLUDED.projectId, + linesOfCodeSuggested = usage_metrics.linesOfCodeSuggested + EXCLUDED.linesOfCodeSuggested, + linesOfCodeAccepted = usage_metrics.linesOfCodeAccepted + EXCLUDED.linesOfCodeAccepted, + totalRequest = usage_metrics.totalRequest + 1 + RETURNING id; + `; + } + const result = await pool.query(query, values); return res.status(201).json({ diff --git a/index.js b/index.js index 913c567..3405cbe 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,11 @@ const cors = require("cors"); const app = express(); //Middlewares -app.use(cors()); +app.use(cors({ + origin: '*', + methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'] +})); app.use(express.json()); //Routes diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index 72d82bd..1b6cd4c 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -1524,6 +1524,18 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package-lock.json b/package-lock.json index 78db5c5..7eb8788 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,8 @@ "express": "^4.21.2", "mongoose": "^8.10.0", "nodemon": "^3.1.9", - "pg": "^8.13.3" + "pg": "^8.13.3", + "uuid": "^11.1.0" } }, "node_modules/@mongodb-js/saslprep": { @@ -1551,6 +1552,18 @@ "node": ">= 0.4.0" } }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index 51a3da0..b9e26bc 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "express": "^4.21.2", "mongoose": "^8.10.0", "nodemon": "^3.1.9", - "pg": "^8.13.3" + "pg": "^8.13.3", + "uuid": "^11.1.0" } } -- GitLab