Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
christopherswenson committed Jul 30, 2024
1 parent 5715861 commit 61d8d74
Show file tree
Hide file tree
Showing 13 changed files with 265 additions and 107 deletions.
20 changes: 14 additions & 6 deletions packages/malloy/src/lang/ast/field-space/dynamic-space.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,23 @@ export abstract class DynamicSpace extends StaticSpace {
}

structDef(): model.StructDef {
const parameters = this.fromStruct.parameters || {};
if (this.final === undefined) {

// TODO this is kinda weird: we grab all the parameters so that we can
// populate the "final" structDef with parameters immediately so that views
// (or nested views) can see them when they are compiling and need to know
// the struct def of the source while it is still being defined.
const parameters = {};
for (const [name, entry] of this.entries()) {
if (entry instanceof SpaceParam) {
parameters[name] = entry.parameter();
}
}

this.final = {
...this.fromStruct,
fields: [],
parameters,
};
// Need to process the entities in specific order
const fields: [string, SpaceField][] = [];
Expand All @@ -117,8 +129,6 @@ export abstract class DynamicSpace extends StaticSpace {
turtles.push([name, spaceEntry]);
} else if (spaceEntry instanceof SpaceField) {
fields.push([name, spaceEntry]);
} else if (spaceEntry instanceof SpaceParam) {
parameters[name] = spaceEntry.parameter();
}
}
const reorderFields = [...fields, ...joins, ...turtles];
Expand All @@ -142,9 +152,7 @@ export abstract class DynamicSpace extends StaticSpace {
// }
}
}
if (Object.entries(parameters).length > 0) {
this.final.parameters = parameters;
}

// If we have join expressions, we need to now go back and fill them in
for (const [join, missingOn] of fixupJoins) {
join.fixupJoinOn(this, missingOn);
Expand Down
2 changes: 2 additions & 0 deletions packages/malloy/src/lang/ast/field-space/query-spaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export abstract class QueryOperationSpace
readonly astEl: MalloyElement
) {
super(queryInputSpace.emptyStructDef());

// TODO I don't understand at all how QueryInputSpace gets its map?
this.exprSpace = new QueryInputSpace(queryInputSpace, this);
if (refineThis) this.addRefineFromFields(refineThis);
}
Expand Down
12 changes: 6 additions & 6 deletions packages/malloy/src/lang/ast/query-elements/query-arrow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,17 @@ export class QueryArrow extends QueryBase implements QueryElement {
if (this.source instanceof Source) {
// We create a fresh query with either the QOPDesc as the head,
// the view as the head, or the scalar as the head (if scalar lenses is enabled)
const structRef = isRefOk
? this.source.structRef(parameterSpace)
: this.source.structDef(parameterSpace);
const invoked = isRefOk
? this.source.structRef(parameterSpace)
: {structRef: this.source.structDef(parameterSpace)};
queryBase = {
type: 'query',
structRef,
...invoked,
pipeline: [],
location: this.location,
};
inputStruct = refIsStructDef(structRef)
? structRef
inputStruct = refIsStructDef(invoked.structRef)
? invoked.structRef
: this.source.structDef(parameterSpace);
fieldSpace = new StaticSpace(inputStruct);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
*/

import {
InvokedStructRef,
StructDef,
StructRef,
refIsStructDef,
Expand All @@ -37,8 +38,8 @@ export class QueryHeadStruct extends Source {
super();
}

structRef(): StructRef {
return this.fromRef;
structRef(): InvokedStructRef {
return {structRef: this.fromRef};
}

structDef(parameterSpace: ParameterSpace | undefined): StructDef {
Expand Down
10 changes: 5 additions & 5 deletions packages/malloy/src/lang/ast/query-elements/query-raw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,16 @@ export class QueryRaw extends MalloyElement implements QueryElement {
parameterSpace: ParameterSpace | undefined,
isRefOk: boolean
): QueryComp {
const structRef = isRefOk
const invoked = isRefOk
? this.source.structRef(parameterSpace)
: this.source.structDef(parameterSpace);
const structDef = refIsStructDef(structRef)
? structRef
: {structRef: this.source.structDef(parameterSpace)};
const structDef = refIsStructDef(invoked.structRef)
? invoked.structRef
: this.source.structDef(parameterSpace);
return {
query: {
type: 'query',
structRef,
...invoked,
pipeline: [{type: 'raw', fields: []}],
location: this.location,
},
Expand Down
120 changes: 71 additions & 49 deletions packages/malloy/src/lang/ast/source-elements/named-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@
*/

import {
InvokedStructRef,
isCastType,
isSQLBlockStruct,
isValueParameter,
Parameter,
paramHasValue,
StructDef,
StructRef,
} from '../../../model/malloy_types';

import {Source} from './source';
Expand Down Expand Up @@ -61,19 +62,18 @@ export class NamedSource extends Source {
return this.ref instanceof ModelEntryReference ? this.ref.name : this.ref;
}

structRef(parameterSpace: ParameterSpace | undefined): StructRef {
if (this.args !== undefined) {
return this.structDef(parameterSpace);
}
structRef(parameterSpace: ParameterSpace | undefined): InvokedStructRef {
const modelEnt = this.modelEntry(this.ref);
// TODO right now we just expand the structRef if it has any parameters; but we should really
// evaluate arguments separately and return them here, to be included in the query;
if (modelEnt && (!modelEnt.exported || modelEnt.entry.type === 'struct' && modelEnt.entry.parameters)) {
// If we are not exporting the referenced structdef, don't
// use the reference
return this.structDef(parameterSpace);
// If we are not exporting the referenced structdef, don't use the reference
if (modelEnt && !modelEnt.exported) {
return {
structRef: this.structDef(parameterSpace)
};
}
return this.refName;
return {
structRef: this.refName,
sourceArguments: this.evaluateArgumentsForRef(parameterSpace),
};
}

refLog(message: string, severity?: LogSeverity) {
Expand Down Expand Up @@ -110,42 +110,22 @@ export class NamedSource extends Source {
return {...entry};
}

structDef(parameterSpace: ParameterSpace | undefined): StructDef {
return this.withParameters(parameterSpace, []);
}

withParameters(
private evaluateArgumentsForRef(
parameterSpace: ParameterSpace | undefined,
pList: HasParameter[] | undefined
): StructDef {
/*
Can't really generate the callback list until after all the
things before me are translated, and that kinda screws up
the translation process, so that might be a better place
to start the next step, because how that gets done might
make any code I write which ignores the translation problem
kind of meaningless.
Maybe the output of a translation is something which describes
all the missing data, and then there is a "link" step where you
can do other translations and link them into a partial translation
which might result in a full translation.
*/

): Record<string, Parameter> {
const base = this.modelStruct();
if (!base) {
const notFound = ErrorFactory.structDef;
const err = `${this.refName}-undefined`;
notFound.name = notFound.name + err;
notFound.dialect = notFound.dialect + err;
return notFound;
}
// Clone parameters to not mutate
const parameters = {};
for (const paramName in base.parameters) {
parameters[paramName] = {...base.parameters[paramName]};
if (base === undefined) {
return {};
}

return this.evaluateArguments(parameterSpace, base.parameters, []);
}

private evaluateArguments(
parameterSpace: ParameterSpace | undefined,
parametersIn: Record<string, Parameter> | undefined,
parametersOut: HasParameter[] | undefined
): Record<string, Parameter> {
const outArguments = {};
const passedNames = new Set();
for (const argument of this.args ?? []) {
Expand All @@ -166,14 +146,14 @@ export class NamedSource extends Source {
continue;
}
passedNames.add(name);
const parameter = parameters[name];
const parameter = (parametersIn ?? {})[name];
if (!parameter) {
id.log(
`\`${this.refName}\` has no declared parameter named \`${id.refString}\``
);
} else {
if (isValueParameter(parameter)) {
const paramSpace = parameterSpace ?? new ParameterSpace(pList ?? []);
const paramSpace = parameterSpace ?? new ParameterSpace(parametersOut ?? []);
const pVal = argument.value.getExpression(paramSpace);
let value = pVal.value;
if (pVal.dataType !== parameter.type && isCastType(parameter.type)) {
Expand All @@ -189,10 +169,11 @@ export class NamedSource extends Source {
}
}

for (const paramName in parameters) {
for (const paramName in parametersIn) {
if (!(paramName in outArguments)) {
if (paramHasValue(parameters[paramName])) {
outArguments[paramName] = parameters[paramName];
if (paramHasValue(parametersIn[paramName])) {
// TODO probably should not do this, and just look in the referenced source to get the default parameter values.
outArguments[paramName] = {...parametersIn[paramName]};
} else {
this.refLog(
`Argument not provided for required parameter \`${paramName}\``
Expand All @@ -201,11 +182,52 @@ export class NamedSource extends Source {
}
}

return outArguments;
}

structDef(parameterSpace: ParameterSpace | undefined): StructDef {
return this.withParameters(parameterSpace, []);
}

withParameters(
parameterSpace: ParameterSpace | undefined,
pList: HasParameter[] | undefined
): StructDef {
/*
Can't really generate the callback list until after all the
things before me are translated, and that kinda screws up
the translation process, so that might be a better place
to start the next step, because how that gets done might
make any code I write which ignores the translation problem
kind of meaningless.
Maybe the output of a translation is something which describes
all the missing data, and then there is a "link" step where you
can do other translations and link them into a partial translation
which might result in a full translation.
*/

const base = this.modelStruct();
if (!base) {
const notFound = ErrorFactory.structDef;
const err = `${this.refName}-undefined`;
notFound.name = notFound.name + err;
notFound.dialect = notFound.dialect + err;
return notFound;
}

const outParameters = {};
for (const parameter of pList ?? []) {
const compiled = parameter.parameter();
outParameters[compiled.name] = compiled;
}

const outArguments = this.evaluateArguments(
parameterSpace,
base.parameters,
pList
);

const ret = {...base, parameters: outParameters, arguments: outArguments};
this.document()?.rememberToAddModelAnnotations(ret);
return ret;
Expand Down
4 changes: 4 additions & 0 deletions packages/malloy/src/lang/ast/source-elements/query-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export class QuerySource extends Source {
...comp.outputStruct,
structSource: {type: 'query', query: comp.query} as StructSource,
};
// TODO test this
if (comp.query.sourceArguments !== undefined) {
queryStruct.arguments = comp.query.sourceArguments;
}
this.document()?.rememberToAddModelAnnotations(queryStruct);
return queryStruct;
}
Expand Down
8 changes: 5 additions & 3 deletions packages/malloy/src/lang/ast/source-elements/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import {StructDef, StructRef} from '../../../model/malloy_types';
import {InvokedStructRef, StructDef} from '../../../model/malloy_types';
import {MalloyElement} from '../types/malloy-element';
import {HasParameter} from '../parameters/has-parameter';
import {ParameterSpace} from '../field-space/parameter-space';
Expand All @@ -33,8 +33,10 @@ import {ParameterSpace} from '../field-space/parameter-space';
export abstract class Source extends MalloyElement {
abstract structDef(parameterSpace: ParameterSpace | undefined): StructDef;

structRef(parameterSpace: ParameterSpace | undefined): StructRef {
return this.structDef(parameterSpace);
structRef(parameterSpace: ParameterSpace | undefined): InvokedStructRef {
return {
structRef: this.structDef(parameterSpace)
};
}

withParameters(
Expand Down
8 changes: 5 additions & 3 deletions packages/malloy/src/lang/ast/source-elements/sql-source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@

import {
StructDef,
StructRef,
SQLBlockSource,
InvokedStructRef,
} from '../../../model/malloy_types';
import {makeSQLBlock} from '../../../model/sql_block';
import {NeedCompileSQL} from '../../translate-response';
Expand Down Expand Up @@ -54,8 +54,10 @@ export class SQLSource extends Source {
return this.requestBlock;
}

structRef(): StructRef {
return this.structDef();
structRef(): InvokedStructRef {
return {
structRef: this.structDef()
};
}

validateConnectionName(): boolean {
Expand Down
Loading

0 comments on commit 61d8d74

Please sign in to comment.