@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.
@@ -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';