Skip to content
This repository was archived by the owner on Jul 28, 2025. It is now read-only.

Commit 66c508d

Browse files
committed
refactoring formulas
1 parent e871858 commit 66c508d

File tree

16 files changed

+239
-82
lines changed

16 files changed

+239
-82
lines changed

docs/docs/features/Formulas.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ The root object `db` has the following functions:
3131

3232
- `js` : execute a javascript function that you previously defined in the `js` folder of your table in the database or plugin global settings. (I.E.: `db.js.myFunction( arg1, arg2)`)
3333
- `dataview`: expose the dataview API. (see [Dataview API](https://github.com/blacksmithgu/obsidian-dataview/blob/master/src/api/plugin-api.ts))
34-
- `rollup`: expose the rollup functions of the dbfolder plugin. (see [Rollup documentation](/features/Relations/#rollups))
34+
- `rollup`: expose the rollup functions of the dbfolder plugin. (see [Rollup documentation](/obsidian-db-folder/features/Relations/#rollups))
3535

3636
#### Javascript file structure
3737
To add a javascript file to the `js` folder, it must be a `.js` file and have the following structure:

src/DatabaseView.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { obtainFormulasFromFolder } from "automations/AutomationsHelper";
21
import { DatabaseColumn } from "cdm/DatabaseModel";
32
import { UpdaterData, ViewEvents } from "cdm/EmitterModel";
43
import {
@@ -38,6 +37,7 @@ import {
3837
Menu,
3938
} from "obsidian";
4039
import { createRoot, Root } from "react-dom/client";
40+
import { DbAutomationService } from "services/AutomationService";
4141
import DatabaseInfo from "services/DatabaseInfo";
4242
import { LOGGER } from "services/Logger";
4343
import { SettingsModal } from "Settings";
@@ -168,7 +168,7 @@ export class DatabaseView extends TextFileView implements HoverParent {
168168
);
169169
this.initial = obtainInitialType(this.columns);
170170

171-
this.formulas = await obtainFormulasFromFolder(
171+
this.formulas = await DbAutomationService.buildFns(
172172
this.diskConfig.yaml.config
173173
);
174174
// Define table properties

src/automations/AutomationsHelper.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

src/automations/Footer.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { DEFAULT_SETTINGS, FooterType } from "helpers/Constants";
22
import { Literal } from "obsidian-dataview";
33
import { DataviewService } from "services/DataviewService";
44
import { DateTime } from "luxon";
5+
import { DbAutomationService } from "services/AutomationService";
56

67
export default class Footer {
78
constructor(public readonly colValues: Literal[]) { }
@@ -119,10 +120,7 @@ export default class Footer {
119120
* @returns
120121
*/
121122
public sum(): string {
122-
const total = this.colValues
123-
.map((value) => Number(value))
124-
.filter((value) => !isNaN(value))
125-
.reduce((acc: number, value: number) => acc + value, 0);
123+
const total = DbAutomationService.coreFns.numbers.sum(this.colValues);
126124
return `Total: ${total}`;
127125
}
128126

@@ -131,10 +129,7 @@ export default class Footer {
131129
* @returns
132130
*/
133131
public min(): string {
134-
const min = this.colValues
135-
.map((value) => Number(value))
136-
.filter((value) => !isNaN(value))
137-
.reduce((acc: number, value: number) => Math.min(acc, value), Number.MAX_SAFE_INTEGER);
132+
const min = DbAutomationService.coreFns.numbers.min(this.colValues);
138133
return `Min: ${min}`;
139134
}
140135

@@ -143,10 +138,7 @@ export default class Footer {
143138
* @returns
144139
*/
145140
public max(): string {
146-
const max = this.colValues
147-
.map((value) => Number(value))
148-
.filter((value) => !isNaN(value))
149-
.reduce((acc: number, value: number) => Math.max(acc, value), Number.MIN_SAFE_INTEGER);
141+
const max = DbAutomationService.coreFns.numbers.max(this.colValues);
150142
return `Max: ${max}`;
151143
}
152144

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { FormulaFunctions } from "automations/formula_functions/FormulaFunctions";
2-
import { IGenerateObject } from "automations/IGenerateObject";
2+
import { IGenerateObject } from "automations/core/IGenerateObject";
33
import { LocalSettings } from "cdm/SettingsModel";
4-
import { Link } from "obsidian-dataview";
5-
import { DataviewService } from "services/DataviewService";
6-
import Rollup from "automations/Rollup";
74
export class FormulaGenerator implements IGenerateObject {
85
public js_functions: FormulaFunctions;
96

@@ -16,13 +13,8 @@ export class FormulaGenerator implements IGenerateObject {
1613
}
1714

1815
async generate_object(): Promise<Record<string, unknown>> {
19-
const final_object: Record<string, unknown> = {};
20-
Object.assign(final_object, {
16+
return {
2117
js: await this.generate_js_functions(),
22-
dataview: DataviewService.getDataviewAPI(),
23-
rollup: (relation: Link[]) => new Rollup(relation)
24-
}
25-
);
26-
return final_object;
18+
};
2719
}
2820
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { IGenerateObject } from "automations/core/IGenerateObject";
2+
import { DatabaseFnType } from "cdm/ModulesFnModel";
3+
import { DbModule } from "./core/DbModule";
4+
import { NumbersFn } from "./core/modules/NumbersFn";
5+
export class ModulesGenerator implements IGenerateObject {
6+
private modules_array: Array<DbModule> = [];
7+
8+
constructor() {
9+
this.modules_array.push(new NumbersFn());
10+
}
11+
12+
async init(): Promise<void> {
13+
for (const mod of this.modules_array) {
14+
await mod.init();
15+
}
16+
}
17+
18+
async generate_object(): Promise<DatabaseFnType> {
19+
const internal_functions_object: { [key: string]: unknown } = {};
20+
for (const mod of this.modules_array) {
21+
internal_functions_object[mod.getName()] =
22+
await mod.generate_object();
23+
}
24+
25+
return internal_functions_object as DatabaseFnType;
26+
}
27+
}

src/automations/Rollup.ts

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import { LocalSettings } from "cdm/SettingsModel";
22
import { DEFAULT_SETTINGS, InputType, ROLLUP_ACTIONS } from "helpers/Constants";
33
import { Link, Literal, SMarkdownPage } from "obsidian-dataview";
4+
import { DbAutomationService } from "services/AutomationService";
45
import { DataviewService } from "services/DataviewService";
56
import { LOGGER } from "services/Logger";
67
import { ParseService } from "services/ParseService";
78

89
class Rollup {
910
private pages: Record<string, Literal>[];
1011

12+
/**
13+
* Obtains the metadata associated to a list of links
14+
* @param relation
15+
* @returns
16+
*/
1117
static generatePages(relation: Link[]): Record<string, Literal>[] {
1218
return relation.map((link) =>
1319
DataviewService.getDataviewAPI().page(link.path)
@@ -27,27 +33,27 @@ class Rollup {
2733
let result = "";
2834
switch (action) {
2935
case ROLLUP_ACTIONS.SUM:
30-
result = this.sum(key);
36+
result = this.sum(key).toString();
3137
break;
3238

3339
case ROLLUP_ACTIONS.COUNT_ALL:
34-
result = this.countAll(key);
40+
result = this.countAll(key).toString();
3541
break;
3642

3743
case ROLLUP_ACTIONS.COUNT_UNIQUE:
38-
result = this.countUnique(key);
44+
result = this.countUnique(key).toString();
3945
break;
4046

4147
case ROLLUP_ACTIONS.ORIGINAL_VALUE:
4248
result = this.originalValue(key);
4349
break;
4450

4551
case ROLLUP_ACTIONS.TRUTHY_COUNT:
46-
result = this.truthyCount(key);
52+
result = this.truthyCount(key).toString();
4753
break;
4854

4955
case ROLLUP_ACTIONS.FALSY_COUNT:
50-
result = this.falsyCount(key);
56+
result = this.falsyCount(key).toString();
5157
break;
5258

5359
case ROLLUP_ACTIONS.PERCENT_EMPTY:
@@ -59,15 +65,15 @@ class Rollup {
5965
break;
6066

6167
case ROLLUP_ACTIONS.ALL_TASKS:
62-
result = this.allTasks();
68+
result = this.allTasks().toString();
6369
break;
6470

6571
case ROLLUP_ACTIONS.TASK_COMPLETED:
66-
result = this.taskCompleted();
72+
result = this.taskCompleted().toString();
6773
break;
6874

6975
case ROLLUP_ACTIONS.TASK_TODO:
70-
result = this.taskTodo();
76+
result = this.taskTodo().toString();
7177
break;
7278

7379
default:
@@ -85,44 +91,35 @@ class Rollup {
8591
* Iters over the pages and sums the values of the key
8692
* @returns
8793
*/
88-
public sum(key: string): string {
94+
public sum(key: string): number {
8995
// Check if key is not truthy, return empty string
9096
if (!key) {
91-
return "";
97+
return NaN;
9298
}
93-
let sum = 0;
94-
this.pages.forEach((page) => {
95-
if (page[key]) {
96-
sum += Number(page[key]);
97-
}
98-
});
99-
return sum.toString();
99+
const rawValues = this.rawValues(key);
100+
return DbAutomationService.coreFns.numbers.sum(rawValues)
100101
}
101102

102103
/**
103104
* Obtains the number of pages of the relation with the key informed
104105
* @returns
105106
*/
106-
public countAll(key: string): string {
107+
public countAll(key: string): number {
107108
// Check if key is not truthy, return empty string
108109
if (!key) {
109-
return "";
110+
return 0;
110111
}
111-
return this.pages.filter((page) => page[key] !== undefined).length.toString();
112+
return this.rawValues(key).length;
112113
}
113114

114-
public countUnique(key: string): string {
115+
public countUnique(key: string): number {
115116
// Check if key is not truthy, return empty string
116117
if (!key) {
117-
return "";
118+
return 0;
118119
}
119120
const uniqueValues = new Set();
120-
this.pages
121-
.filter((page) => page[key] !== undefined)
122-
.forEach((page) => {
123-
uniqueValues.add(page[key]);
124-
});
125-
return uniqueValues.size.toString();
121+
this.rawValues(key).forEach((value) => uniqueValues.add(value));
122+
return uniqueValues.size;
126123
}
127124

128125
/**
@@ -135,25 +132,28 @@ class Rollup {
135132
return "";
136133
}
137134
const settings = config || DEFAULT_SETTINGS.local_settings;
138-
return this.pages
139-
.filter((page) => page[key])
140-
.map((page) => ParseService.parseLiteral(page[key], InputType.MARKDOWN, settings)).join(", ");
135+
return this.rawValues(key)
136+
.map((value) => ParseService.parseLiteral(
137+
value,
138+
InputType.MARKDOWN,
139+
settings))
140+
.join(", ");
141141
}
142142

143-
public falsyCount(key: string): string {
143+
public falsyCount(key: string): number {
144144
// Check if key is not truthy, return empty string
145145
if (!key) {
146-
return "";
146+
return 0;
147147
}
148-
return this.pages.filter((page) => page[key] !== undefined && !page[key]).length.toString();
148+
return this.pages.filter((page) => page[key] !== undefined && !page[key]).length;
149149
}
150150

151-
public truthyCount(key: string): string {
151+
public truthyCount(key: string): number {
152152
// Check if key is not truthy, return empty string
153153
if (!key) {
154-
return "";
154+
return 0;
155155
}
156-
return this.pages.filter((page) => page[key] !== undefined && page[key]).length.toString();
156+
return this.pages.filter((page) => page[key] !== undefined && page[key]).length;
157157
}
158158

159159
public percentEmpty(key: string): string {
@@ -176,25 +176,29 @@ class Rollup {
176176
return `${((filled / total) * 100).toFixed(2)}%`;
177177
}
178178

179-
public allTasks(): string {
179+
public allTasks(): number {
180180
return this.pages.map((page: SMarkdownPage) => {
181181
const file_tasks = page.file.tasks;
182182
return file_tasks.length
183-
}).reduce((a, b) => a + b, 0).toString();
183+
}).reduce((a, b) => a + b, 0);
184184
}
185185

186-
public taskCompleted(): string {
186+
public taskCompleted(): number {
187187
return this.pages.map((page: SMarkdownPage) => {
188188
const file_tasks = page.file.tasks;
189189
return file_tasks.filter(task => task.checked).length
190-
}).reduce((a, b) => a + b, 0).toString();
190+
}).reduce((a, b) => a + b, 0);
191191
}
192192

193-
public taskTodo(): string {
193+
public taskTodo(): number {
194194
return this.pages.map((page: SMarkdownPage) => {
195195
const file_tasks = page.file.tasks;
196196
return file_tasks.filter(task => !task.checked).length
197-
}).reduce((a, b) => a + b, 0).toString();
197+
}).reduce((a, b) => a + b, 0);
198+
}
199+
200+
private rawValues(key: string): Literal[] {
201+
return this.pages.filter((page) => page[key] !== undefined).map((page) => page[key]);
198202
}
199203
}
200204

src/automations/core/DbModule.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
import { IGenerateObject } from "./IGenerateObject";
3+
4+
export abstract class DbModule implements IGenerateObject {
5+
public abstract name: string;
6+
protected static_functions: Map<string, unknown> = new Map();
7+
protected dynamic_functions: Map<string, unknown> = new Map();
8+
protected static_object: { [x: string]: unknown };
9+
10+
constructor() { }
11+
12+
getName(): string {
13+
return this.name;
14+
}
15+
16+
abstract create_static_functions(): Promise<void>;
17+
abstract create_dynamic_functions(): Promise<void>;
18+
19+
async init(): Promise<void> {
20+
await this.create_static_functions();
21+
this.static_object = Object.fromEntries(this.static_functions);
22+
}
23+
24+
async generate_object(): Promise<Record<string, unknown>> {
25+
await this.create_dynamic_functions();
26+
27+
return {
28+
...this.static_object,
29+
...this.static_object,
30+
...Object.fromEntries(this.dynamic_functions),
31+
};
32+
}
33+
}

0 commit comments

Comments
 (0)