Skip to content

Commit

Permalink
New method acumualte
Browse files Browse the repository at this point in the history
  • Loading branch information
nshiab committed Feb 18, 2025
1 parent 626b3e4 commit 165b3ab
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 0 deletions.
45 changes: 45 additions & 0 deletions src/class/SimpleWebTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import capitalizeQuery from "../methods/capitalizeQuery.ts";
import logDataWeb from "../helpers/logDataWeb.ts";
import getProjectionParquet from "../helpers/getProjectionParquet.ts";
import unifyColumns from "../helpers/unifyColumns.ts";
import accumulateQuery from "../helpers/accumulateQuery.ts";
// Not working for now
// import getProjection from "../helpers/getProjection.js"

Expand Down Expand Up @@ -2350,6 +2351,50 @@ export default class SimpleWebTable extends Simple {
}
}

/**
* Computes the cumulative sum of values in a column. Don't forget to sort your data first.
*
* @example
* Basic usage
* ```ts
* // Computes the cumulative sum of values in column1 in a new column cumulative.
* await table.accumulate("column1", "cumulative")
* ```
*
* @example
* With categories
* ```ts
* // Computes the cumulative sum of values in column1 in a new column cumulative. Using values in column2 as categories.
* await table.accumulate("column1", "cumulative", { categories: "column2" })
* ```
*
* @param column - The name of the column storing the values to be accumulated.
* @param newColumn - The name of the new column in which the computed values will be stored.
* @param options - An optional object with configuration options:
* @param options.categories - The category or categories to be used for the accumulation.
*/
async accumulate(
column: string,
newColumn: string,
options: {
categories?: string | string[];
} = {},
) {
await this.addRowNumber("idForAccumulate");

await queryDB(
this,
accumulateQuery(this.name, column, newColumn, options),
mergeOptions(this, {
table: this.name,
method: "accumulate()",
parameters: { column, newColumn, options },
}),
);

await this.removeColumns("idForAccumulate");
}

/**
* Computes rolling aggregations, like a rolling average. For rows without enough preceding or following rows, returns NULL. For this method to work properly, don't forget to sort your data first.
*
Expand Down
23 changes: 23 additions & 0 deletions src/helpers/accumulateQuery.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import stringToArray from "./stringToArray.ts";

export default function accumulateQuery(
table: string,
column: string,
newColumn: string,
options: {
categories?: string | string[];
} = {},
) {
const categories = options.categories
? stringToArray(options.categories)
: [];
const partition = categories.length > 0
? `PARTITION BY ${categories.map((d) => `${d}`).join(", ")}`
: "";

const query =
`CREATE OR REPLACE TABLE ${table} AS SELECT *, SUM(${column}) OVER (${partition} ORDER BY idForAccumulate) AS ${newColumn}
FROM ${table};`;

return query;
}
60 changes: 60 additions & 0 deletions test/unit/methods/accumulate.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { assertEquals } from "jsr:@std/assert";
import SimpleDB from "../../../src/class/SimpleDB.ts";

Deno.test("should add the cumulative sum in a new column", async () => {
const sdb = new SimpleDB();
const table = sdb.newTable("data");
await table.loadArray([
{ key1: 1 },
{ key1: 2 },
{ key1: 3 },
]);
await table.accumulate("key1", "cumulative");
const data = await table.getData();
assertEquals(data, [
{ key1: 1, cumulative: 1 },
{ key1: 2, cumulative: 3 },
{ key1: 3, cumulative: 6 },
]);
await sdb.done();
});
Deno.test("should add the cumulative sum in a new column without reordering the rows", async () => {
const sdb = new SimpleDB();
const table = sdb.newTable("data");
await table.loadArray([
{ key1: 3 },
{ key1: 1 },
{ key1: 2 },
]);
await table.accumulate("key1", "cumulative");
const data = await table.getData();
assertEquals(data, [
{ key1: 3, cumulative: 3 },
{ key1: 1, cumulative: 4 },
{ key1: 2, cumulative: 6 },
]);
await sdb.done();
});
Deno.test("should add the cumulative sum in a new column with categories", async () => {
const sdb = new SimpleDB();
const table = sdb.newTable("data");
await table.loadArray([
{ key1: 6, key2: "b" },
{ key1: 1, key2: "a" },
{ key1: 4, key2: "b" },
{ key1: 2, key2: "a" },
{ key1: 3, key2: "a" },
{ key1: 5, key2: "b" },
]);
await table.accumulate("key1", "cumulative", { categories: "key2" });
const data = await table.getData();
assertEquals(data, [
{ key1: 1, key2: "a", cumulative: 1 },
{ key1: 2, key2: "a", cumulative: 3 },
{ key1: 3, key2: "a", cumulative: 6 },
{ key1: 6, key2: "b", cumulative: 6 },
{ key1: 4, key2: "b", cumulative: 10 },
{ key1: 5, key2: "b", cumulative: 15 },
]);
await sdb.done();
});

0 comments on commit 165b3ab

Please sign in to comment.