@malloydata/malloy-tests 0.0.74-dev230812015425 → 0.0.74-dev230815162117

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/src/tags.spec.ts CHANGED
@@ -21,7 +21,7 @@
21
21
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  */
23
23
 
24
- import {Tags, Annotation, MalloyTags, TagDict, Tag} from '@malloydata/malloy';
24
+ import {TagDict, Tag} from '@malloydata/malloy';
25
25
  import {runtimeFor} from './runtimes';
26
26
 
27
27
  declare global {
@@ -64,138 +64,6 @@ expect.extend({
64
64
 
65
65
  const runtime = runtimeFor('duckdb');
66
66
 
67
- interface TestAnnotation {
68
- inherits?: TestAnnotation;
69
- blockNotes?: string[];
70
- notes: string[];
71
- }
72
-
73
- function unTestify(ta: TestAnnotation): Annotation {
74
- const dloc = {
75
- url: __filename,
76
- range: {start: {character: 0, line: 0}, end: {character: 0, line: 0}},
77
- };
78
- const ret: Annotation = {
79
- notes: ta.notes.map(t => {
80
- return {text: t, at: dloc};
81
- }),
82
- };
83
- if (ta.blockNotes) {
84
- ret.blockNotes = ta.blockNotes.map(t => {
85
- return {text: t, at: dloc};
86
- });
87
- }
88
- if (ta.inherits) {
89
- ret.inherits = unTestify(ta.inherits);
90
- }
91
- return ret;
92
- }
93
-
94
- class TestTags extends Tags {
95
- constructor(ta: TestAnnotation) {
96
- super(unTestify(ta));
97
- }
98
- }
99
-
100
- function tstTaglist(a: TestAnnotation): string[] {
101
- return new TestTags(a).getTagList();
102
- }
103
-
104
- function tstTagParse(s: string): MalloyTags {
105
- return new TestTags({notes: [s]}).getMalloyTags();
106
- }
107
-
108
- describe('tag utilities', () => {
109
- test('own/block ordering is correct', () => {
110
- const testA = tstTaglist({
111
- notes: ['#tag'],
112
- blockNotes: ['#blockTag'],
113
- });
114
- expect(testA).toEqual(['#blockTag', '#tag']);
115
- });
116
- test('inherit ordering is correct', () => {
117
- const testA = tstTaglist({
118
- inherits: {notes: ['#inherited']},
119
- notes: ['#tag'],
120
- });
121
- expect(testA).toEqual(['#inherited', '#tag']);
122
- });
123
- test.todo('check that results are annotated');
124
- test('doc annotations', () => {
125
- const a = tstTagParse('#" This is a doc string');
126
- expect(a).toMatchObject({docStrings: ['This is a doc string']});
127
- });
128
- test('simple property', () => {
129
- const a = tstTagParse('# linechart');
130
- expect(a.properties).toHaveProperty('linechart', true);
131
- });
132
- test('negated property', () => {
133
- const a = tstTagParse('# linechart -linechart');
134
- expect(a.properties).not.toHaveProperty('linechart', true);
135
- });
136
- test('simple quoted property', () => {
137
- const a = tstTagParse('# "linechart"');
138
- expect(a.properties).toHaveProperty('linechart', true);
139
- });
140
- test('quoted property with " and space', () => {
141
- const annotation = '# "a \\"chart\\""';
142
- const a = tstTagParse(annotation);
143
- expect(a.properties).toHaveProperty('a "chart"', true);
144
- });
145
- test('escaped non-quote', () => {
146
- const annotation = '# "\\x"';
147
- const a = tstTagParse(annotation);
148
- expect(a.properties).toHaveProperty('x', true);
149
- });
150
- test('non-terminated string', () => {
151
- const annotation = '# x="\\"';
152
- const a = tstTagParse(annotation);
153
- expect(a.properties).not.toHaveProperty('x', true);
154
- });
155
- test('quoted property with value', () => {
156
- const a = tstTagParse('# "linechart"=yes');
157
- expect(a.properties).toHaveProperty('linechart', 'yes');
158
- });
159
- test('property with simple value', () => {
160
- const a = tstTagParse('# chart=line');
161
- expect(a.properties).toHaveProperty('chart', 'line');
162
- });
163
- test('property with quoted value', () => {
164
- const a = tstTagParse('# chart="line"');
165
- expect(a.properties).toHaveProperty('chart', 'line');
166
- });
167
- test('spaces ignored', () => {
168
- const a = tstTagParse('# chart = line ');
169
- expect(a.properties).toHaveProperty('chart', 'line');
170
- });
171
- test('= with no value', () => {
172
- expect(tstTagParse('# name = ')).toMatchObject({properties: {}});
173
- });
174
- test('multiple = with no value', () => {
175
- expect(tstTagParse('# name = = me')).toMatchObject({properties: {}});
176
- });
177
- test('missing quote', () => {
178
- expect(tstTagParse('# name = "no quote')).toMatchObject({properties: {}});
179
- });
180
- test('leading =', () => {
181
- expect(tstTagParse('# =name ')).toMatchObject({properties: {}});
182
- });
183
- test('complex line', () => {
184
- const a = tstTagParse('# a b=c "d"=e f="g" "h"="i" "j" k -a');
185
- expect(a).toBeDefined();
186
- if (a) {
187
- expect(a.properties).toEqual({
188
- b: 'c',
189
- d: 'e',
190
- f: 'g',
191
- h: 'i',
192
- j: true,
193
- k: true,
194
- });
195
- }
196
- });
197
- });
198
-
199
67
  type TagTestTuple = [string, TagDict];
200
68
  describe('tagParse to Tag', () => {
201
69
  const tagTests: TagTestTuple[] = [
@@ -343,6 +211,50 @@ describe('Tag access', () => {
343
211
  const n = a?.numeric();
344
212
  expect(n).toBeUndefined();
345
213
  });
214
+ test('full text array', () => {
215
+ const strToParse = 'a=[b,c]';
216
+ const getTags = Tag.fromTagline(strToParse, undefined);
217
+ expect(getTags.log).toEqual([]);
218
+ const a = getTags.tag.tag('a');
219
+ expect(a).toBeDefined();
220
+ const ais = a?.textArray();
221
+ expect(ais).toEqual(['b', 'c']);
222
+ });
223
+ test('filtered text array', () => {
224
+ const strToParse = 'a=[b,c,{d}]';
225
+ const getTags = Tag.fromTagline(strToParse, undefined);
226
+ expect(getTags.log).toEqual([]);
227
+ const a = getTags.tag.tag('a');
228
+ expect(a).toBeDefined();
229
+ const ais = a?.textArray();
230
+ expect(ais).toEqual(['b', 'c']);
231
+ });
232
+ test('full numeric array', () => {
233
+ const strToParse = 'a=[1,2]';
234
+ const getTags = Tag.fromTagline(strToParse, undefined);
235
+ expect(getTags.log).toEqual([]);
236
+ const a = getTags.tag.tag('a');
237
+ expect(a).toBeDefined();
238
+ const ais = a?.numericArray();
239
+ expect(ais).toEqual([1, 2]);
240
+ });
241
+ test('filtered numeric array', () => {
242
+ const strToParse = 'a=[1,2,three]';
243
+ const getTags = Tag.fromTagline(strToParse, undefined);
244
+ expect(getTags.log).toEqual([]);
245
+ const a = getTags.tag.tag('a');
246
+ expect(a).toBeDefined();
247
+ const ais = a?.numericArray();
248
+ expect(ais).toEqual([1, 2]);
249
+ });
250
+ test('has', () => {
251
+ const strToParse = 'a b.d';
252
+ const getTags = Tag.fromTagline(strToParse, undefined);
253
+ expect(getTags.log).toEqual([]);
254
+ expect(getTags.tag.has('a')).toBeTruthy();
255
+ expect(getTags.tag.has('b', 'd')).toBeTruthy();
256
+ expect(getTags.tag.has('c')).toBeFalsy();
257
+ });
346
258
  });
347
259
 
348
260
  describe('## top level', () => {
@@ -355,41 +267,37 @@ describe('## top level', () => {
355
267
  `
356
268
  )
357
269
  .getModel();
358
- const modelDesc = model.getTags().getMalloyTags();
359
- expect(modelDesc).toEqual({
360
- properties: {propertyTag: true},
361
- docStrings: ['Doc String\n'],
362
- });
363
270
  const modelTagLine = model.tagParse().tag;
364
271
  expect(modelTagLine.has('propertyTag')).toBeTruthy();
272
+ expect(model.getTaglines(/^##"/)).toEqual(['##" Doc String\n']);
365
273
  });
366
274
  });
367
275
  describe('tags in results', () => {
368
276
  test('nameless query', async () => {
369
277
  const loaded = runtime.loadQuery(
370
278
  `
279
+ ## modelDef=ok
371
280
  sql: one is {connection: "duckdb" select: """SELECT 1 as one"""}
372
281
  # b4query
373
- query: # afterQuery
282
+ query: # afterQuery import=$(modelDef)
374
283
  from_sql(one) -> { project: * }`
375
284
  );
285
+ const qTag = {b4query: {}, afterQuery: {}, import: {eq: 'ok'}};
376
286
  const query = await loaded.getPreparedQuery();
377
287
  expect(query).toBeDefined();
378
- const wantTags = ['# b4query\n', '# afterQuery\n'];
379
- expect(query.getTags().getTagList()).toEqual(wantTags);
288
+ expect(query.tagParse().tag).tagsAre(qTag);
380
289
  const result = await loaded.run();
381
- expect(result.getTags().getTagList()).toEqual(wantTags);
382
- const queryTags = result.tagParse().tag;
383
- expect(queryTags).tagsAre({b4query: {}, afterQuery: {}});
290
+ expect(result.tagParse().tag).tagsAre(qTag);
384
291
  });
385
- const wantTags = ['# BQ\n', '# AQ\n', '# Bis\n', '# Ais\n'];
386
- const wantTag = {BQ: {}, AQ: {}, Bis: {}, Ais: {}};
292
+ const wantTag = {BQ: {}, AQ: {}, Bis: {}, Ais: {}, import: {eq: 'ok'}};
387
293
  test('named query', async () => {
388
294
  const loaded = runtime.loadQuery(
389
295
  `
390
296
  sql: one is {connection: "duckdb" select: """SELECT 1 as one"""}
297
+ ## modelDef=ok
391
298
  # BQ
392
299
  query: # AQ
300
+ # import=$(modelDef)
393
301
  theName
394
302
  # Bis
395
303
  is
@@ -399,17 +307,17 @@ describe('tags in results', () => {
399
307
  );
400
308
  const query = await loaded.getPreparedQuery();
401
309
  expect(query).toBeDefined();
402
- expect(query.getTags().getTagList()).toEqual(wantTags);
310
+ expect(query.tagParse().tag).tagsAre(wantTag);
403
311
  const result = await loaded.run();
404
- expect(result.getTags().getTagList()).toEqual(wantTags);
405
312
  expect(result.tagParse().tag).tagsAre(wantTag);
406
313
  });
407
314
  test('turtle query', async () => {
408
315
  const loaded = runtime.loadQuery(
409
316
  `
317
+ ## modelDef=ok
410
318
  sql: one is {connection: "duckdb" select: """SELECT 1 as one"""}
411
319
  query: from_sql(one) + {
412
- # BQ
320
+ # BQ import=$(modelDef)
413
321
  query: # AQ
414
322
  in_one
415
323
  # Bis
@@ -421,20 +329,18 @@ describe('tags in results', () => {
421
329
  );
422
330
  const query = await loaded.getPreparedQuery();
423
331
  expect(query).toBeDefined();
424
- expect(query.getTags().getTagList()).toEqual(wantTags);
425
332
  expect(query.tagParse().tag).tagsAre(wantTag);
426
333
  const result = await loaded.run();
427
- const tl = result.getTags().getTagList();
428
- expect(tl).toEqual(wantTags);
429
334
  expect(result.tagParse().tag).tagsAre(wantTag);
430
335
  });
431
336
  test('atomic field has tag', async () => {
432
337
  const loaded = runtime.loadQuery(
433
338
  `
339
+ ## modelDef=ok
434
340
  sql: one is {connection: "duckdb" select: """SELECT 1 as one"""}
435
341
  query: from_sql(one) -> {
436
342
  project:
437
- # note1
343
+ # note1 import=$(modelDef)
438
344
  one
439
345
  }`
440
346
  );
@@ -442,12 +348,14 @@ describe('tags in results', () => {
442
348
  const shape = result.resultExplore;
443
349
  const one = shape.getFieldByName('one');
444
350
  expect(one).toBeDefined();
445
- expect(one.getTags().getTagList()).toEqual(['# note1\n']);
446
- expect(one.tagParse().tag).tagsAre({note1: {}});
351
+ const tp = one.tagParse();
352
+ expect(tp.log).toEqual([]);
353
+ expect(tp.tag).tagsAre({note1: {}, import: {eq: 'ok'}});
447
354
  });
448
355
  test('nested query has tag', async () => {
449
356
  const loaded = runtime.loadQuery(
450
357
  `
358
+ ## modelDef=ok
451
359
  sql: one is {connection: "duckdb" select: """SELECT 1 as one"""}
452
360
  source: malloy_one is from_sql(one) + {
453
361
  query: in_one is {
@@ -457,7 +365,7 @@ describe('tags in results', () => {
457
365
  group_by: one
458
366
  # note1
459
367
  nest:
460
- # note2
368
+ # note2 import=$(modelDef)
461
369
  in_one
462
370
  }
463
371
  }
@@ -467,8 +375,11 @@ describe('tags in results', () => {
467
375
  const shape = result.resultExplore;
468
376
  const one = shape.getFieldByName('in_one');
469
377
  expect(one).toBeDefined();
470
- expect(one.getTags().getTagList()).toEqual(['# note1\n', '# note2\n']);
471
- expect(one.tagParse().tag).tagsAre({note1: {}, note2: {}});
378
+ expect(one.tagParse().tag).tagsAre({
379
+ note1: {},
380
+ note2: {},
381
+ import: {eq: 'ok'},
382
+ });
472
383
  });
473
384
  test('render usage test case', async () => {
474
385
  const loaded = runtime.loadQuery(
@@ -501,14 +412,32 @@ describe('tags in results', () => {
501
412
  const height = shape.getFieldByName('height');
502
413
  const age = shape.getFieldByName('age');
503
414
  const name = shape.getFieldByName('name');
504
- expect(height.getTags().getMalloyTags()).toMatchObject({
505
- properties: {barchart: true},
506
- });
507
415
  expect(height.tagParse().tag).tagsAre({barchart: {}});
508
- expect(age.getTags().getMalloyTags()).toMatchObject({
509
- properties: {barchart: true},
510
- });
511
416
  expect(age.tagParse().tag).tagsAre({barchart: {}});
512
417
  expect(name.tagParse().tag).tagsAre({name: {}});
513
418
  });
419
+ test('User defines scopes nest properly', async () => {
420
+ const loaded = runtime.loadQuery(
421
+ `
422
+ ## scope=model
423
+ sql: one is {connection: "duckdb" select: """SELECT 1 as one"""}
424
+ query: from_sql(one) -> {
425
+ project:
426
+ # valueFrom=$(scope)
427
+ one
428
+ }`
429
+ );
430
+ const result = await loaded.run();
431
+ const shape = result.resultExplore;
432
+ const field = shape.getFieldByName('one');
433
+ expect(field).toBeDefined();
434
+ let tp = field.tagParse().tag;
435
+ expect(tp).tagsAre({valueFrom: {eq: 'model'}});
436
+ const sessionScope = Tag.fromTagline('# scope=session', undefined).tag;
437
+ tp = field.tagParse({scopes: [sessionScope]}).tag;
438
+ expect(tp).tagsAre({valueFrom: {eq: 'session'}});
439
+ const globalScope = Tag.fromTagline('# scope=global', undefined).tag;
440
+ tp = field.tagParse({scopes: [globalScope, sessionScope]}).tag;
441
+ expect(tp).tagsAre({valueFrom: {eq: 'global'}});
442
+ });
514
443
  });