@milaboratories/ptabler-expression-js 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/expressions.cjs +867 -0
- package/dist/expressions.cjs.map +1 -0
- package/dist/expressions.d.ts +297 -0
- package/dist/expressions.d.ts.map +1 -0
- package/dist/expressions.js +840 -0
- package/dist/expressions.js.map +1 -0
- package/dist/functions.cjs +180 -0
- package/dist/functions.cjs.map +1 -0
- package/dist/functions.d.ts +80 -0
- package/dist/functions.d.ts.map +1 -0
- package/dist/functions.js +166 -0
- package/dist/functions.js.map +1 -0
- package/dist/index.cjs +47 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +39 -0
- package/src/expressions.ts +944 -0
- package/src/functions.ts +183 -0
- package/src/index.ts +11 -0
- package/src/types.ts +1 -0
package/src/functions.ts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory functions for creating expressions - mirrors Tengo pt library API
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { LiteralValue } from './expressions';
|
|
6
|
+
import { ColumnExpressionImpl, ExpressionImpl, LiteralExpressionImpl, LogicalExpressionImpl, MinMaxExpressionImpl, RankExpressionImpl, StringConcatExpressionImpl, WhenThenOtherwiseExpressionImpl } from './expressions';
|
|
7
|
+
|
|
8
|
+
// Internal helpers mirroring Tengo behavior
|
|
9
|
+
function isExpression(v: unknown): v is ExpressionImpl {
|
|
10
|
+
return v instanceof ExpressionImpl;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function asExprFromString(value: string, interpretation: 'col' | 'lit'): ExpressionImpl {
|
|
14
|
+
return interpretation === 'col' ? col(value) : lit(value);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function coerceToExpressionList(
|
|
18
|
+
items: Array<ExpressionImpl | string> | ExpressionImpl | string,
|
|
19
|
+
interpretationForString: 'col' | 'lit',
|
|
20
|
+
): ExpressionImpl[] {
|
|
21
|
+
const arr = Array.isArray(items) ? items : [items];
|
|
22
|
+
return arr.map((it) => (typeof it === 'string' ? asExprFromString(it, interpretationForString) : it));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Create a column reference expression
|
|
27
|
+
* @param name Column name
|
|
28
|
+
*/
|
|
29
|
+
export function col(name: string): ColumnExpressionImpl {
|
|
30
|
+
return new ColumnExpressionImpl(name);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Create a literal value expression
|
|
35
|
+
* @param value Literal value (number, string, boolean, null, etc.)
|
|
36
|
+
*/
|
|
37
|
+
export function lit(value: LiteralValue): LiteralExpressionImpl {
|
|
38
|
+
return new LiteralExpressionImpl(value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Create an AND expression with multiple operands (horizontal AND)
|
|
43
|
+
* @param expressions Array of expressions to AND together
|
|
44
|
+
*/
|
|
45
|
+
export function allHorizontal(...expressions: Array<ExpressionImpl | string>): LogicalExpressionImpl {
|
|
46
|
+
// Interpret string args as column names. We don't flatten nested ANDs to keep implementation simple.
|
|
47
|
+
const processed: ExpressionImpl[] = expressions.map((e) => (typeof e === 'string' ? col(e) : e));
|
|
48
|
+
return new LogicalExpressionImpl('and', processed);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Create an OR expression with multiple operands (horizontal OR)
|
|
53
|
+
* @param expressions Array of expressions to OR together
|
|
54
|
+
*/
|
|
55
|
+
export function anyHorizontal(...expressions: Array<ExpressionImpl | string>): LogicalExpressionImpl {
|
|
56
|
+
// Interpret string args as column names. We don't flatten nested ORs to keep implementation simple.
|
|
57
|
+
const processed: ExpressionImpl[] = expressions.map((e) => (typeof e === 'string' ? col(e) : e));
|
|
58
|
+
return new LogicalExpressionImpl('or', processed);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create an AND expression with multiple operands
|
|
63
|
+
* @param expressions Array of expressions to AND together
|
|
64
|
+
*/
|
|
65
|
+
export function and(...expressions: Array<ExpressionImpl | string>): LogicalExpressionImpl {
|
|
66
|
+
return allHorizontal(...expressions);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Create an OR expression with multiple operands
|
|
71
|
+
* @param expressions Array of expressions to OR together
|
|
72
|
+
*/
|
|
73
|
+
export function or(...expressions: Array<ExpressionImpl | string>): LogicalExpressionImpl {
|
|
74
|
+
return anyHorizontal(...expressions);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Concatenate string representations with optional delimiter (Tengo: concatStr)
|
|
79
|
+
* String inputs are treated as literals.
|
|
80
|
+
*/
|
|
81
|
+
export function concatStr(
|
|
82
|
+
expressions: Array<ExpressionImpl | string>,
|
|
83
|
+
options?: { delimiter?: string },
|
|
84
|
+
): ExpressionImpl {
|
|
85
|
+
if (!Array.isArray(expressions) || expressions.length === 0) {
|
|
86
|
+
throw new Error('concatStr requires a non-empty array of expressions');
|
|
87
|
+
}
|
|
88
|
+
const ops = coerceToExpressionList(expressions, 'lit');
|
|
89
|
+
const delimiter = options?.delimiter ?? '';
|
|
90
|
+
return new StringConcatExpressionImpl(ops, delimiter);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Element-wise min across expressions (Tengo: minHorizontal). Strings -> columns.
|
|
95
|
+
*/
|
|
96
|
+
export function minHorizontal(expressions: Array<ExpressionImpl | string>): ExpressionImpl {
|
|
97
|
+
if (!Array.isArray(expressions) || expressions.length === 0) {
|
|
98
|
+
throw new Error('minHorizontal requires a non-empty array of expressions');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const ops = coerceToExpressionList(expressions, 'col');
|
|
102
|
+
return new MinMaxExpressionImpl('min', ops);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Element-wise max across expressions (Tengo: maxHorizontal). Strings -> columns.
|
|
107
|
+
*/
|
|
108
|
+
export function maxHorizontal(expressions: Array<ExpressionImpl | string>): ExpressionImpl {
|
|
109
|
+
if (!Array.isArray(expressions) || expressions.length === 0) {
|
|
110
|
+
throw new Error('maxHorizontal requires a non-empty array of expressions');
|
|
111
|
+
}
|
|
112
|
+
const ops = coerceToExpressionList(expressions, 'col');
|
|
113
|
+
return new MinMaxExpressionImpl('max', ops);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Create a conditional when-then expression builder
|
|
118
|
+
* @param condition Boolean expression condition
|
|
119
|
+
*/
|
|
120
|
+
export function when(condition: ExpressionImpl): WhenThenBuilder {
|
|
121
|
+
return WhenThenBuilder.start(condition);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Create a rank expression
|
|
126
|
+
* @param expression Expression to rank
|
|
127
|
+
* @param options Ranking options
|
|
128
|
+
*/
|
|
129
|
+
export function rank(orderBy: ExpressionImpl | string | Array<ExpressionImpl | string>, descending = false): RankBuilder {
|
|
130
|
+
const orderByList = coerceToExpressionList(orderBy, 'col');
|
|
131
|
+
return new RankBuilder(orderByList, descending);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Builder class for when-then-otherwise conditional expressions
|
|
136
|
+
*/
|
|
137
|
+
export class WhenThenBuilder {
|
|
138
|
+
private constructor(
|
|
139
|
+
private readonly clauses: Array<{ when: ExpressionImpl; then: ExpressionImpl }>,
|
|
140
|
+
private readonly currentWhen?: ExpressionImpl,
|
|
141
|
+
) {}
|
|
142
|
+
|
|
143
|
+
static start(condition: ExpressionImpl): WhenThenBuilder {
|
|
144
|
+
if (!isExpression(condition)) throw new Error('when() expects an Expression');
|
|
145
|
+
return new WhenThenBuilder([], condition);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
when(condition: ExpressionImpl): WhenThenBuilder {
|
|
149
|
+
if (this.currentWhen) throw new Error('.when() must follow a .then()');
|
|
150
|
+
if (!isExpression(condition)) throw new Error('.when() expects an Expression');
|
|
151
|
+
return new WhenThenBuilder(this.clauses, condition);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
then(value: ExpressionImpl | LiteralValue): WhenThenBuilder {
|
|
155
|
+
if (!this.currentWhen) throw new Error('.then() must follow a .when()');
|
|
156
|
+
const expr = isExpression(value) ? value : lit(value);
|
|
157
|
+
const nextClauses = this.clauses.slice();
|
|
158
|
+
nextClauses.push({ when: this.currentWhen, then: expr });
|
|
159
|
+
return new WhenThenBuilder(nextClauses, undefined);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
otherwise(value: ExpressionImpl | LiteralValue): WhenThenOtherwiseExpressionImpl {
|
|
163
|
+
if (this.currentWhen) throw new Error('.otherwise() must follow a .then()');
|
|
164
|
+
if (this.clauses.length === 0) {
|
|
165
|
+
throw new Error('At least one .when().then() clause is required before .otherwise()');
|
|
166
|
+
}
|
|
167
|
+
const expr = isExpression(value) ? value : lit(value);
|
|
168
|
+
return new WhenThenOtherwiseExpressionImpl(this.clauses, expr);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Rank builder and expression
|
|
173
|
+
export class RankBuilder {
|
|
174
|
+
constructor(
|
|
175
|
+
private readonly orderBy: ExpressionImpl[],
|
|
176
|
+
private readonly descending: boolean,
|
|
177
|
+
) {}
|
|
178
|
+
|
|
179
|
+
over(partitionBy: ExpressionImpl | string | Array<ExpressionImpl | string>): RankExpressionImpl {
|
|
180
|
+
const partitionByList = coerceToExpressionList(partitionBy, 'col');
|
|
181
|
+
return new RankExpressionImpl(this.orderBy, partitionByList, this.descending);
|
|
182
|
+
}
|
|
183
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PTabler JavaScript Expression System
|
|
3
|
+
*
|
|
4
|
+
* Provides JavaScript/TypeScript implementation of PTabler expression API
|
|
5
|
+
* with identical JSON output to Tengo implementation.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Export core expression classes
|
|
9
|
+
export * from './expressions';
|
|
10
|
+
export * from './functions';
|
|
11
|
+
export * from './types';
|
package/src/types.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type * from '@platforma-open/milaboratories.software-ptabler.schema';
|