Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/src/packages/database/postgres/retention/active-users.ts
Views: 687
import getLogger from "@cocalc/backend/logger";1const log = getLogger("database:retention:active-users");23export default async function activeUsers({4model,5table,6last_start_time,7pool,8start,9stop,10period,11}) {12const query = `WITH13periods0 AS (14SELECT $1::timestamp + (n * $2::interval) AS period_start,15$1::timestamp + ((n + 1) * $2::interval) AS period_end16FROM generate_series(0, floor(EXTRACT(EPOCH FROM (now() - $1::timestamp - '1 second'::interval)) / EXTRACT(EPOCH FROM $2::interval))::integer) AS n17),18periods AS (SELECT * FROM periods0 ${19last_start_time == null ? "" : "WHERE period_start > $3"20}),21period_counts AS (22SELECT periods.period_start, COUNT(DISTINCT ${table}.account_id) AS count23FROM periods24LEFT JOIN ${table} ON ${table}.time >= periods.period_start AND ${table}.time < periods.period_end25GROUP BY periods.period_start26)27SELECT periods.period_start, periods.period_end, COALESCE(period_counts.count, 0) AS count28FROM periods29LEFT JOIN period_counts ON periods.period_start = period_counts.period_start30WHERE periods.period_end <= NOW()31ORDER BY periods.period_start`;3233const getSize = async (rows) => {34if (rows.length == 0) return 0;35return (36await pool.query(37`SELECT COUNT(DISTINCT(account_id)) as size FROM ${table} WHERE time >= $1::timestamp AND time < $2::timestamp`,38[start, rows[rows.length - 1].period_end]39)40).rows[0].size;41};4243if (last_start_time == null) {44log.debug("just compute all the data");45const { rows } = await pool.query(query, [start, period]);46if (rows.length == 0) {47// shouldn't happen because should get excluded above...48return;49}50const active = rows.map((x) => parseInt(x.count));51const last_start_time = rows[rows.length - 1].period_start;52await pool.query(53"INSERT INTO crm_retention(start,stop,model,period,active,last_start_time,size) VALUES($1,$2,$3,$4,$5,$6,$7)",54[start, stop, model, period, active, last_start_time, await getSize(rows)]55);56} else {57log.debug("compute the missing data and put it into the database");58const { rows } = await pool.query(query, [start, period, last_start_time]);59if (rows.length == 0) {60// shouldn't happen because should get excluded...61return;62}63const active = rows.map((x) => parseInt(x.count));64const new_last_start_time = rows[rows.length - 1].period_start;65await pool.query(66"UPDATE crm_retention SET last_start_time=$5::timestamp, active = array_cat(active, $6::integer[]) WHERE start=$1 AND stop=$2 AND model=$3 AND period=$4 AND size=$7",67[68start,69stop,70model,71period,72new_last_start_time,73active,74await getSize(rows),75]76);77}78}7980/*81WITH82periods AS (83SELECT '2023-04-03'::timestamp + (n * '1 day'::interval) AS period_start,84'2023-04-03'::timestamp + ((n + 1) * '1 day'::interval) AS period_end85FROM generate_series(0, floor(EXTRACT(EPOCH FROM (now() - '2023-04-03'::timestamp - '1 second'::interval)) / EXTRACT(EPOCH FROM '1 day'::interval))::integer) AS n86),87period_counts AS (88SELECT periods.period_start, COUNT(DISTINCT file_access_log.account_id) AS count89FROM periods90LEFT JOIN file_access_log ON file_access_log.time >= periods.period_start AND file_access_log.time < periods.period_end91GROUP BY periods.period_start92)93SELECT periods.period_start, periods.period_end, COALESCE(period_counts.count, 0) AS count94FROM periods95LEFT JOIN period_counts ON periods.period_start = period_counts.period_start96WHERE periods.period_end <= NOW()97ORDER BY periods.period_start;9899*/100101102