@malloydata/malloy 0.0.300 → 0.0.301
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/lang/ast/query-items/field-declaration.js +7 -2
- package/dist/lang/ast/statements/define-source.js +25 -23
- package/dist/lang/parse-log.d.ts +1 -0
- package/dist/model/composite_source_utils.d.ts +3 -2
- package/dist/model/composite_source_utils.js +115 -5
- package/dist/model/malloy_types.d.ts +9 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +4 -4
|
@@ -263,8 +263,13 @@ class FieldDefinitionValue extends space_field_1.SpaceField {
|
|
|
263
263
|
return this.fieldName;
|
|
264
264
|
}
|
|
265
265
|
fieldDef() {
|
|
266
|
-
var _a;
|
|
267
|
-
|
|
266
|
+
var _a, _b;
|
|
267
|
+
// Checking `defInQuery` is necessary to support a case where a field needs
|
|
268
|
+
// to be looked up from the output space (ex: in `order_by: a`), but where
|
|
269
|
+
// the field is defined in a group_by expression (ex: `group_by: a.day`).
|
|
270
|
+
// In this case, this.exprDef.fieldDef() only ever returns an
|
|
271
|
+
// AtomicFieldDef anyways, so it is safe in this particular implementation.
|
|
272
|
+
const def = (_b = (_a = this.defInSource) !== null && _a !== void 0 ? _a : this.defInQuery) !== null && _b !== void 0 ? _b : this.exprDef.fieldDef(this.space, this.name);
|
|
268
273
|
this.defInSource = def;
|
|
269
274
|
return def;
|
|
270
275
|
}
|
|
@@ -26,6 +26,7 @@ exports.DefineSourceList = exports.DefineSource = void 0;
|
|
|
26
26
|
const error_factory_1 = require("../error-factory");
|
|
27
27
|
const malloy_element_1 = require("../types/malloy-element");
|
|
28
28
|
const noteable_1 = require("../types/noteable");
|
|
29
|
+
const composite_source_utils_1 = require("../../../model/composite_source_utils");
|
|
29
30
|
class DefineSource extends malloy_element_1.MalloyElement {
|
|
30
31
|
constructor(name, sourceExpr, exported, parameters) {
|
|
31
32
|
super();
|
|
@@ -44,33 +45,34 @@ class DefineSource extends malloy_element_1.MalloyElement {
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
execute(doc) {
|
|
47
|
-
var _a;
|
|
48
|
+
var _a, _b, _c;
|
|
48
49
|
if (doc.modelEntry(this.name)) {
|
|
49
50
|
this.logError('source-definition-name-conflict', `Cannot redefine '${this.name}'`);
|
|
51
|
+
return;
|
|
50
52
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
: this.note;
|
|
71
|
-
}
|
|
72
|
-
doc.setEntry(this.name, { entry, exported: this.exported });
|
|
53
|
+
const theSource = (_a = this.sourceExpr) === null || _a === void 0 ? void 0 : _a.getSource();
|
|
54
|
+
if (theSource === undefined) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const parameters = this.deduplicatedParameters();
|
|
58
|
+
const structDef = theSource.withParameters(undefined, this.parameters);
|
|
59
|
+
this.validateParameterShadowing(parameters, structDef);
|
|
60
|
+
if (error_factory_1.ErrorFactory.didCreate(structDef)) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const entry = {
|
|
64
|
+
...structDef,
|
|
65
|
+
as: this.name,
|
|
66
|
+
location: this.location,
|
|
67
|
+
};
|
|
68
|
+
if (this.note) {
|
|
69
|
+
entry.annotation = structDef.annotation
|
|
70
|
+
? { ...this.note, inherits: structDef.annotation }
|
|
71
|
+
: this.note;
|
|
73
72
|
}
|
|
73
|
+
entry.partitionComposite =
|
|
74
|
+
(_c = (0, composite_source_utils_1.getPartitionCompositeDesc)(this.note, structDef, (_b = this.sourceExpr) !== null && _b !== void 0 ? _b : this)) !== null && _c !== void 0 ? _c : structDef.partitionComposite;
|
|
75
|
+
doc.setEntry(this.name, { entry, exported: this.exported });
|
|
74
76
|
}
|
|
75
77
|
deduplicatedParameters() {
|
|
76
78
|
if (this.parameters === undefined)
|
package/dist/lang/parse-log.d.ts
CHANGED
|
@@ -384,6 +384,7 @@ type MessageParameterTypes = {
|
|
|
384
384
|
'grouped-by-not-found': string;
|
|
385
385
|
'non-scalar-grouped-by': string;
|
|
386
386
|
'missing-required-group-by': string;
|
|
387
|
+
'invalid-partition-composite': string;
|
|
387
388
|
};
|
|
388
389
|
export declare const MESSAGE_FORMATTERS: PartialErrorCodeMessageMap;
|
|
389
390
|
export type MessageCode = keyof MessageParameterTypes;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BooleanFilter, NumberFilter, StringFilter, TemporalFilter } from '@malloydata/malloy-filter';
|
|
2
2
|
import type { MalloyElement } from '../lang/ast';
|
|
3
|
-
import type { FieldUsage, PipeSegment, SourceDef, Expr,
|
|
3
|
+
import type { FieldUsage, PipeSegment, SourceDef, Expr, RequiredGroupBy, Annotation, PartitionCompositeDesc, StructDef } from './malloy_types';
|
|
4
4
|
type CompositeCouldNotFindFieldError = {
|
|
5
5
|
code: 'could_not_find_field';
|
|
6
6
|
data: {
|
|
@@ -51,6 +51,7 @@ interface CompositeFailure {
|
|
|
51
51
|
source: SourceDef;
|
|
52
52
|
issues: CompositeIssue[];
|
|
53
53
|
}
|
|
54
|
+
export declare function getPartitionCompositeDesc(annotation: Annotation | undefined, structDef: StructDef, logTo: MalloyElement): PartitionCompositeDesc | undefined;
|
|
54
55
|
type SingleNarrowedCompositeFieldResolution = {
|
|
55
56
|
source: SourceDef;
|
|
56
57
|
nested?: SingleNarrowedCompositeFieldResolution | undefined;
|
|
@@ -84,7 +85,7 @@ export declare function fieldUsageJoinPaths(fieldUsage: FieldUsage[]): string[][
|
|
|
84
85
|
export declare function checkRequiredGroupBys(compositeResolvedSourceDef: SourceDef, segment: PipeSegment): RequiredGroupBy[];
|
|
85
86
|
export declare function pathEq(a: string[], b: string[]): boolean;
|
|
86
87
|
export declare function pathBegins(path: string[], prefix: string[]): boolean;
|
|
87
|
-
export declare function hasCompositesAnywhere(source:
|
|
88
|
+
export declare function hasCompositesAnywhere(source: SourceDef): boolean;
|
|
88
89
|
export declare function logCompositeError(error: CompositeError, logTo: MalloyElement): void;
|
|
89
90
|
export declare function compileFilterExpression(ft: string, fexpr: Expr): {
|
|
90
91
|
kind: 'date' | 'timestamp';
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.getPartitionCompositeDesc = getPartitionCompositeDesc;
|
|
9
10
|
exports.resolveCompositeSources = resolveCompositeSources;
|
|
10
11
|
exports.fieldUsagePaths = fieldUsagePaths;
|
|
11
12
|
exports.formatFieldUsages = formatFieldUsages;
|
|
@@ -27,10 +28,11 @@ exports.compileFilterExpression = compileFilterExpression;
|
|
|
27
28
|
const malloy_filter_1 = require("@malloydata/malloy-filter");
|
|
28
29
|
const malloy_types_1 = require("./malloy_types");
|
|
29
30
|
const utils_1 = require("../lang/utils");
|
|
31
|
+
const annotation_1 = require("../annotation");
|
|
30
32
|
function _resolveCompositeSources(path, source, rootFields, nests, fieldUsage,
|
|
31
33
|
// for resolving nested composites; the list of sources to try
|
|
32
34
|
sources) {
|
|
33
|
-
var _a, _b, _c, _d;
|
|
35
|
+
var _a, _b, _c, _d, _e;
|
|
34
36
|
// TODO skip all this if the tree doesn't have any composite sources
|
|
35
37
|
let base = { ...source };
|
|
36
38
|
let anyComposites = false;
|
|
@@ -93,8 +95,9 @@ sources) {
|
|
|
93
95
|
abort();
|
|
94
96
|
continue overSources;
|
|
95
97
|
}
|
|
96
|
-
if (inputSource.type === 'composite'
|
|
97
|
-
|
|
98
|
+
if (inputSource.type === 'composite' ||
|
|
99
|
+
inputSource.partitionComposite !== undefined) {
|
|
100
|
+
const resolveInner = _resolveCompositeSources(path, inputSource, genRootFields(rootFields, path, fieldsForLookup, false), nests, compositeUsageInThisSource, inputSource.type === 'composite' ? inputSource.sources : undefined);
|
|
98
101
|
if ('error' in resolveInner) {
|
|
99
102
|
// Third point where we abort; if a nested composite failed; we don't call abort() because we want to unnest the failures from
|
|
100
103
|
if (resolveInner.error.code === 'no_suitable_composite_source_input') {
|
|
@@ -171,6 +174,29 @@ sources) {
|
|
|
171
174
|
};
|
|
172
175
|
}
|
|
173
176
|
}
|
|
177
|
+
else if (source.partitionComposite !== undefined) {
|
|
178
|
+
anyComposites = true;
|
|
179
|
+
const expanded = expandFieldUsage(fieldUsage, rootFields).result;
|
|
180
|
+
// TODO possibly abort if expanded has missing fields...
|
|
181
|
+
const expandedCategorized = categorizeFieldUsage(expanded);
|
|
182
|
+
const { partitionFilter, issues } = getPartitionCompositeFilter(source.partitionComposite, expandedCategorized.sourceUsage);
|
|
183
|
+
if (issues !== undefined) {
|
|
184
|
+
return {
|
|
185
|
+
error: {
|
|
186
|
+
code: 'no_suitable_composite_source_input',
|
|
187
|
+
data: {
|
|
188
|
+
failures: issues.map(iss => ({ source, issues: iss })),
|
|
189
|
+
usage: expanded,
|
|
190
|
+
path,
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
base = {
|
|
196
|
+
...source,
|
|
197
|
+
filterList: [...((_e = source.filterList) !== null && _e !== void 0 ? _e : []), partitionFilter],
|
|
198
|
+
};
|
|
199
|
+
}
|
|
174
200
|
if (!joinsProcessed) {
|
|
175
201
|
const expanded = expandFieldUsage(fieldUsage, getJoinFields(rootFields, path));
|
|
176
202
|
if (expanded.missingFields.length > 0) {
|
|
@@ -260,6 +286,89 @@ function categorizeFieldUsage(fieldUsage) {
|
|
|
260
286
|
}
|
|
261
287
|
return categorized;
|
|
262
288
|
}
|
|
289
|
+
function getPartitionCompositePartition(partitionComposite, fieldUsage) {
|
|
290
|
+
const issues = [];
|
|
291
|
+
const compositeFieldsUsed = fieldUsage.filter(u => partitionComposite.compositeFields.some(f => u.path.length === 1 && u.path[0] === f));
|
|
292
|
+
for (const partition of partitionComposite.partitions) {
|
|
293
|
+
const missingFields = compositeFieldsUsed.filter(u => u.path.length !== 1 || !partition.fields.includes(u.path[0]));
|
|
294
|
+
if (missingFields.length === 0) {
|
|
295
|
+
return { partitionId: partition.id, issues: undefined };
|
|
296
|
+
}
|
|
297
|
+
issues.push(missingFields.map(f => ({ type: 'missing-field', field: f })));
|
|
298
|
+
}
|
|
299
|
+
return {
|
|
300
|
+
partitionId: undefined,
|
|
301
|
+
issues,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function getPartitionCompositeFilter(partitionComposite, fieldUsage) {
|
|
305
|
+
const { partitionId, issues } = getPartitionCompositePartition(partitionComposite, fieldUsage);
|
|
306
|
+
if (issues !== undefined)
|
|
307
|
+
return { issues, partitionFilter: undefined };
|
|
308
|
+
const partitionFilter = {
|
|
309
|
+
node: 'filterCondition',
|
|
310
|
+
code: '',
|
|
311
|
+
expressionType: 'scalar',
|
|
312
|
+
e: {
|
|
313
|
+
node: '=',
|
|
314
|
+
kids: {
|
|
315
|
+
left: {
|
|
316
|
+
node: 'field',
|
|
317
|
+
// TODO validate field exists
|
|
318
|
+
path: [partitionComposite.partitionField],
|
|
319
|
+
},
|
|
320
|
+
right: {
|
|
321
|
+
node: 'stringLiteral',
|
|
322
|
+
literal: partitionId,
|
|
323
|
+
},
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
return { partitionFilter, issues: undefined };
|
|
328
|
+
}
|
|
329
|
+
function getPartitionCompositeDesc(annotation, structDef, logTo) {
|
|
330
|
+
if (annotation === undefined)
|
|
331
|
+
return undefined;
|
|
332
|
+
const compilerFlags = (0, annotation_1.annotationToTag)(annotation, { prefix: /^#!\s*/ }).tag;
|
|
333
|
+
const partitionCompositeTag = compilerFlags.tag('experimental', 'partition_composite');
|
|
334
|
+
if (partitionCompositeTag === undefined)
|
|
335
|
+
return undefined;
|
|
336
|
+
if (structDef.type === 'composite') {
|
|
337
|
+
logTo.logError('invalid-partition-composite', 'Source is already composite; cannot apply partition composite');
|
|
338
|
+
return undefined;
|
|
339
|
+
}
|
|
340
|
+
const partitionField = partitionCompositeTag.text('partition_field');
|
|
341
|
+
const partitionsTag = partitionCompositeTag.tag('partitions');
|
|
342
|
+
if (partitionField === undefined) {
|
|
343
|
+
logTo.logError('invalid-partition-composite', 'Partition composite must specify `partition_field`');
|
|
344
|
+
return undefined;
|
|
345
|
+
}
|
|
346
|
+
if (partitionsTag === undefined) {
|
|
347
|
+
logTo.logError('invalid-partition-composite', 'Partition composite must specify `partitions`');
|
|
348
|
+
return undefined;
|
|
349
|
+
}
|
|
350
|
+
const partitions = [];
|
|
351
|
+
const allFields = new Set();
|
|
352
|
+
const ids = Object.keys(partitionsTag.getProperties());
|
|
353
|
+
for (const id of ids) {
|
|
354
|
+
const partitionTag = partitionsTag.tag(id);
|
|
355
|
+
if (partitionTag === undefined) {
|
|
356
|
+
logTo.logError('invalid-partition-composite', `Invalid partition specification for \`${id}\`; must be a tag with property \\fields\``);
|
|
357
|
+
return undefined;
|
|
358
|
+
}
|
|
359
|
+
const fields = Object.keys(partitionsTag.getProperties());
|
|
360
|
+
allFields.forEach(f => allFields.add(f));
|
|
361
|
+
partitions.push({ id, fields });
|
|
362
|
+
}
|
|
363
|
+
for (const field of [partitionField, ...allFields]) {
|
|
364
|
+
const def = structDef.fields.find(f => { var _a; return ((_a = f.as) !== null && _a !== void 0 ? _a : f.name) === field; });
|
|
365
|
+
if (def === undefined) {
|
|
366
|
+
logTo.logError('invalid-partition-composite', `Composite partition field \`${field}\` not present in source`);
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
const compositeFields = structDef.fields.map(f => { var _a; return (_a = f.as) !== null && _a !== void 0 ? _a : f.name; });
|
|
370
|
+
return { partitionField, partitions, compositeFields };
|
|
371
|
+
}
|
|
263
372
|
function composeAnnotations(base, slice) {
|
|
264
373
|
var _a, _b, _c, _d;
|
|
265
374
|
if (base === undefined)
|
|
@@ -854,10 +963,11 @@ function sortIssuesByReferenceLocation(issues) {
|
|
|
854
963
|
});
|
|
855
964
|
}
|
|
856
965
|
function hasCompositesAnywhere(source) {
|
|
857
|
-
if (source.type === 'composite')
|
|
966
|
+
if (source.type === 'composite' || source.partitionComposite !== undefined) {
|
|
858
967
|
return true;
|
|
968
|
+
}
|
|
859
969
|
for (const field of source.fields) {
|
|
860
|
-
if ((0, malloy_types_1.isJoined)(field) && hasCompositesAnywhere(field)) {
|
|
970
|
+
if ((0, malloy_types_1.isJoined)(field) && (0, malloy_types_1.isSourceDef)(field) && hasCompositesAnywhere(field)) {
|
|
861
971
|
return true;
|
|
862
972
|
}
|
|
863
973
|
}
|
|
@@ -623,6 +623,14 @@ interface StructDefBase extends HasLocation, NamedObject {
|
|
|
623
623
|
modelAnnotation?: ModelAnnotation;
|
|
624
624
|
fields: FieldDef[];
|
|
625
625
|
}
|
|
626
|
+
export interface PartitionCompositeDesc {
|
|
627
|
+
partitionField: string;
|
|
628
|
+
partitions: {
|
|
629
|
+
id: string;
|
|
630
|
+
fields: string[];
|
|
631
|
+
}[];
|
|
632
|
+
compositeFields: string[];
|
|
633
|
+
}
|
|
626
634
|
interface SourceDefBase extends StructDefBase, Filtered, ResultStructMetadata {
|
|
627
635
|
arguments?: Record<string, Argument>;
|
|
628
636
|
parameters?: Record<string, Parameter>;
|
|
@@ -630,6 +638,7 @@ interface SourceDefBase extends StructDefBase, Filtered, ResultStructMetadata {
|
|
|
630
638
|
connection: string;
|
|
631
639
|
primaryKey?: PrimaryKeyRef;
|
|
632
640
|
dialect: string;
|
|
641
|
+
partitionComposite?: PartitionCompositeDesc;
|
|
633
642
|
}
|
|
634
643
|
/** which field is the primary key in this struct */
|
|
635
644
|
export type PrimaryKeyRef = string;
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const MALLOY_VERSION = "0.0.
|
|
1
|
+
export declare const MALLOY_VERSION = "0.0.301";
|
package/dist/version.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MALLOY_VERSION = void 0;
|
|
4
4
|
// generated with 'generate-version-file' script; do not edit manually
|
|
5
|
-
exports.MALLOY_VERSION = '0.0.
|
|
5
|
+
exports.MALLOY_VERSION = '0.0.301';
|
|
6
6
|
//# sourceMappingURL=version.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malloydata/malloy",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.301",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dist/index.js",
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"generate-version-file": "VERSION=$(npm pkg get version --workspaces=false | tr -d \\\")\necho \"// generated with 'generate-version-file' script; do not edit manually\\nexport const MALLOY_VERSION = '$VERSION';\" > src/version.ts"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@malloydata/malloy-filter": "0.0.
|
|
45
|
-
"@malloydata/malloy-interfaces": "0.0.
|
|
46
|
-
"@malloydata/malloy-tag": "0.0.
|
|
44
|
+
"@malloydata/malloy-filter": "0.0.301",
|
|
45
|
+
"@malloydata/malloy-interfaces": "0.0.301",
|
|
46
|
+
"@malloydata/malloy-tag": "0.0.301",
|
|
47
47
|
"antlr4ts": "^0.5.0-alpha.4",
|
|
48
48
|
"assert": "^2.0.0",
|
|
49
49
|
"jaro-winkler": "^0.2.8",
|