Skip to content

Commit 063f2a9

Browse files
committed
add mock helpers for tables
1 parent 5e0f8a9 commit 063f2a9

1 file changed

Lines changed: 124 additions & 114 deletions

File tree

Lines changed: 124 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { complete } from '../../src/complete'
22

3-
const SIMPLE_SCHEMA = {
3+
const simpleSchema = {
44
tables: [
55
{
66
catalog: null,
@@ -24,24 +24,102 @@ const SIMPLE_SCHEMA = {
2424
],
2525
}
2626

27+
interface MockTableData {
28+
catalog: string | null
29+
columns: { columnName: string; description: string }[]
30+
database: string | null
31+
tableName: string
32+
}
33+
34+
function mockSchema(...tableDefinitions: MockTableData[]) {
35+
return {
36+
functions: [],
37+
tables: tableDefinitions,
38+
}
39+
}
40+
41+
function table(name: string): MockTableData {
42+
const demoTables: Record<string, string[]> = {
43+
actor: ['actor_id', 'first_name', 'last_name', 'last_update'],
44+
actor_info: ['actor_id', 'first_name', 'last_name', 'film_info'],
45+
address: [
46+
'address_id',
47+
'address',
48+
'address2',
49+
'district',
50+
'city_id',
51+
'postal_code',
52+
'phone',
53+
'last_update',
54+
],
55+
customer: [
56+
'customer_id',
57+
'store_id',
58+
'first_name',
59+
'last_name',
60+
'email',
61+
'address_id',
62+
'activebool',
63+
'create_date',
64+
'last_update',
65+
'active',
66+
],
67+
film: [
68+
'film_id',
69+
'title',
70+
'description',
71+
'release_year',
72+
'language_id',
73+
'original_language_id',
74+
'rental_duration',
75+
'rental_rate',
76+
'length',
77+
'replacement_cost',
78+
'rating',
79+
'last_update',
80+
'special_features',
81+
'fulltext',
82+
],
83+
notes: ['id', 'note', 'last_modified'],
84+
staff: [
85+
'staff_id',
86+
'first_name',
87+
'last_name',
88+
'address_id',
89+
'email',
90+
'store_id',
91+
'active',
92+
'username',
93+
'password',
94+
'last_update',
95+
'picture',
96+
],
97+
users: ['id', 'name', 'email', 'password'],
98+
}
99+
100+
return {
101+
catalog: null,
102+
columns: (demoTables[name] || []).map((columnName) => ({
103+
columnName,
104+
description: '',
105+
})),
106+
database: 'demo',
107+
tableName: name,
108+
}
109+
}
110+
27111
describe('TableName completion', () => {
28112
test('complete function keyword', () => {
29-
const result = complete(
30-
'SELECT arr',
31-
{ line: 0, column: 10 },
32-
SIMPLE_SCHEMA
33-
)
113+
const result = complete('SELECT arr', { line: 0, column: 10 }, simpleSchema)
114+
34115
expect(result.candidates.length).toEqual(2)
35116
expect(result.candidates[0].label).toEqual('array_concat()')
36117
expect(result.candidates[1].label).toEqual('array_contains()')
37118
})
38119

39120
test('complete function keyword', () => {
40-
const result = complete(
41-
'SELECT ARR',
42-
{ line: 0, column: 10 },
43-
SIMPLE_SCHEMA
44-
)
121+
const result = complete('SELECT ARR', { line: 0, column: 10 }, simpleSchema)
122+
45123
expect(result.candidates.length).toEqual(2)
46124
expect(result.candidates[0].label).toEqual('ARRAY_CONCAT()')
47125
expect(result.candidates[1].label).toEqual('ARRAY_CONTAINS()')
@@ -51,8 +129,9 @@ describe('TableName completion', () => {
51129
const result = complete(
52130
'SELECT T FROM TABLE1',
53131
{ line: 0, column: 8 },
54-
SIMPLE_SCHEMA
132+
simpleSchema
55133
)
134+
56135
expect(result.candidates.length).toEqual(1)
57136
expect(result.candidates[0].label).toEqual('TABLE1')
58137
})
@@ -61,8 +140,9 @@ describe('TableName completion', () => {
61140
const result = complete(
62141
'SELECT ta FROM TABLE1 as tab',
63142
{ line: 0, column: 9 },
64-
SIMPLE_SCHEMA
143+
simpleSchema
65144
)
145+
66146
expect(result.candidates.length).toEqual(3)
67147
expect(result.candidates).toEqual(
68148
expect.arrayContaining([expect.objectContaining({ label: 'tab' })])
@@ -72,8 +152,9 @@ describe('TableName completion', () => {
72152
const result = complete(
73153
'SELECT FROM TABLE1',
74154
{ line: 0, column: 6 },
75-
SIMPLE_SCHEMA
155+
simpleSchema
76156
)
157+
77158
expect(result.candidates.length).toEqual(2)
78159
expect(result.candidates[0].label).toEqual('Select all columns from TABLE1')
79160
expect(result.candidates[0].insertText).toEqual(
@@ -88,8 +169,9 @@ describe('TableName completion', () => {
88169
const result = complete(
89170
'SELEC FROM TABLE1',
90171
{ line: 0, column: 5 },
91-
SIMPLE_SCHEMA
172+
simpleSchema
92173
)
174+
93175
expect(result.candidates.length).toEqual(2)
94176
expect(result.candidates[0].label).toEqual('SELECT')
95177
expect(result.candidates[1].label).toEqual('Select all columns from TABLE1')
@@ -102,7 +184,7 @@ describe('TableName completion', () => {
102184
const result = complete(
103185
'SELECT FROM TABLE1',
104186
{ line: 0, column: 7 },
105-
SIMPLE_SCHEMA
187+
simpleSchema
106188
)
107189
const expected = [
108190
expect.objectContaining({
@@ -114,87 +196,46 @@ describe('TableName completion', () => {
114196
})
115197

116198
test('complete table name after FROM keyword with partial input', () => {
117-
const schema = {
118-
tables: [
119-
{
120-
catalog: null,
121-
database: null,
122-
tableName: 'notes',
123-
columns: [{ columnName: 'id', description: '' }],
124-
},
125-
{
126-
catalog: null,
127-
database: null,
128-
tableName: 'users',
129-
columns: [{ columnName: 'name', description: '' }],
130-
},
131-
],
132-
functions: [],
133-
}
199+
const schema = mockSchema(table('notes'), table('users'))
134200

135201
const result = complete(
136202
'SELECT * FROM not',
137203
{ line: 0, column: 17 },
138204
schema
139205
)
140206

141-
// Should suggest table names
142207
const labels = result.candidates.map((c) => c.label)
208+
143209
expect(labels).toContain('notes')
144210

145-
// Should NOT include any column suggestions (even if qualified)
146211
expect(labels).not.toEqual(expect.arrayContaining(['id', 'name']))
147212

148-
// All candidates should be tables (CompletionItemKind.Constant = 21)
149-
const TABLE_KIND = 21
150-
expect(result.candidates.every((c) => c.kind === TABLE_KIND)).toBe(true)
213+
expect(result.candidates.every((c) => c.kind === 21)).toBe(true)
151214
})
152215

153216
test('complete table name with database-qualified tables', () => {
154-
const schema = {
155-
tables: [
156-
{
157-
catalog: null,
158-
database: 'squeal',
159-
tableName: 'actor',
160-
columns: [{ columnName: 'actor_id', description: '' }],
161-
},
162-
{
163-
catalog: null,
164-
database: 'squeal',
165-
tableName: 'actor_info',
166-
columns: [{ columnName: 'actor_id', description: '' }],
167-
},
168-
{
169-
catalog: null,
170-
database: 'squeal',
171-
tableName: 'film',
172-
columns: [{ columnName: 'film_id', description: '' }],
173-
},
174-
],
175-
functions: [],
176-
}
217+
const schema = mockSchema(
218+
table('actor'),
219+
table('actor_info'),
220+
table('film')
221+
)
177222

178223
// Test: typing 'a' after FROM should match 'actor' and 'actor_info'
179224
const result = complete('SELECT * FROM a', { line: 0, column: 15 }, schema)
180225

181226
const labels = result.candidates.map((c) => c.label)
182-
expect(labels).toContain('actor')
183-
expect(labels).toContain('actor_info')
184-
expect(labels).not.toContain('film')
227+
228+
expect(labels).toEqual(['actor', 'actor_info'])
185229
})
186230

187231
test('complete table name when SQL parses successfully', () => {
188232
// This tests the case when the parser treats partial table name as valid
189233
// See https://github.com/deepnote/sql-language-server/issues/24
190-
const schema = {
191-
tables: [
192-
{ catalog: null, database: null, tableName: 'actor', columns: [] },
193-
{ catalog: null, database: null, tableName: 'actor_info', columns: [] },
194-
{ catalog: null, database: null, tableName: 'film', columns: [] },
195-
],
196-
functions: [],
197-
}
234+
const schema = mockSchema(
235+
table('actor'),
236+
table('actor_info'),
237+
table('film')
238+
)
198239

199240
const result = complete(
200241
'SELECT * FROM act',
@@ -203,47 +244,18 @@ describe('TableName completion', () => {
203244
)
204245

205246
const labels = result.candidates.map((c) => c.label)
206-
expect(labels).toContain('actor')
207-
expect(labels).toContain('actor_info')
208-
expect(labels).not.toContain('film')
247+
248+
expect(labels).toEqual(['actor', 'actor_info'])
209249
})
210250

211251
test('complete table name with partial input after typing more characters', () => {
212-
const schema = {
213-
tables: [
214-
{
215-
catalog: null,
216-
database: 'squeal',
217-
tableName: 'actor',
218-
columns: [],
219-
},
220-
{
221-
catalog: null,
222-
database: 'squeal',
223-
tableName: 'actor_info',
224-
columns: [],
225-
},
226-
{
227-
catalog: null,
228-
database: 'squeal',
229-
tableName: 'film',
230-
columns: [],
231-
},
232-
{
233-
catalog: null,
234-
database: 'squeal',
235-
tableName: 'film_actor',
236-
columns: [],
237-
},
238-
{
239-
catalog: null,
240-
database: 'squeal',
241-
tableName: 'customer',
242-
columns: [],
243-
},
244-
],
245-
functions: [],
246-
}
252+
const schema = mockSchema(
253+
table('actor'),
254+
table('actor_info'),
255+
table('customer'),
256+
table('film'),
257+
table('film_actor')
258+
)
247259

248260
// Test: typing 'fil' should match 'film' and 'film_actor'
249261
const result = complete(
@@ -253,9 +265,7 @@ describe('TableName completion', () => {
253265
)
254266

255267
const labels = result.candidates.map((c) => c.label)
256-
expect(labels).toContain('film')
257-
expect(labels).toContain('film_actor')
258-
expect(labels).not.toContain('actor')
259-
expect(labels).not.toContain('customer')
268+
269+
expect(labels).toEqual(['film', 'film_actor'])
260270
})
261271
})

0 commit comments

Comments
 (0)