@prisma/language-server
Version:
Prisma Language Server
1,797 lines (1,728 loc) • 121 kB
text/typescript
import dedent from 'ts-dedent'
import { expect, describe, test } from 'vitest'
import {
CompletionList,
CompletionParams,
CompletionTriggerKind,
CompletionItemKind,
CompletionItem,
} from 'vscode-languageserver'
import { handleCompletionRequest } from '../../lib/MessageHandler'
import { PrismaSchema } from '../../lib/Schema'
import { findCursorPosition, CURSOR_CHARACTER } from '../helper'
import { TextDocument } from 'vscode-languageserver-textdocument'
type DatasourceProvider = 'sqlite' | 'postgresql' | 'mysql' | 'mongodb' | 'sqlserver' | 'cockroachdb'
const baseSchema = (provider?: DatasourceProvider, previewFeatures?: string[]) => {
if (!provider && previewFeatures?.length === 0) {
throw new Error(`provider and/or previewFeatures is required.`)
}
let base = ''
if (provider) {
base = /* Prisma */ `
datasource db {
provider = "${provider}"
}`
}
if (previewFeatures?.length) {
base += /* Prisma */ `
generator js {
provider = "prisma-client-js"
previewFeatures = ["${previewFeatures.join('","')}"]
}`
}
return dedent(base)
}
function assertCompletion({
provider,
previewFeatures,
schema,
expected,
}: {
provider?: DatasourceProvider
previewFeatures?: string[]
schema: string
expected: CompletionList
}): void {
// Remove indentation
schema = dedent(schema)
if (provider || previewFeatures) {
schema = `
${baseSchema(provider, previewFeatures)}
${schema}
`
}
const position = findCursorPosition(schema)
const document: TextDocument = TextDocument.create(
'file:///completions/none.prisma',
'prisma',
1,
schema.replace(CURSOR_CHARACTER, ''),
)
const completionParams: CompletionParams = {
textDocument: document,
position,
context: {
triggerKind: CompletionTriggerKind.Invoked,
},
}
const completionResult: CompletionList | undefined = handleCompletionRequest(
PrismaSchema.singleFile(document),
document,
completionParams,
)
expect(completionResult).not.toBeUndefined()
expect(
completionResult?.isIncomplete,
`Line ${position.line} - Character ${position.character}
Expected isIncomplete to be '${expected.isIncomplete}' but got '${completionResult?.isIncomplete}'`,
).toStrictEqual(expected.isIncomplete)
expect(
completionResult?.items.map((item) => item.label),
`Line ${position.line} - Character ${position.character}
mapped items => item.label`,
).toStrictEqual(expected.items.map((item) => item.label))
expect(
completionResult?.items.map((item) => item.kind),
`Line ${position.line} - Character ${position.character}
mapped items => item.kind`,
).toStrictEqual(expected.items.map((item) => item.kind))
// TODO: This is missing the output of `expected.items` so one can compare
expect(
completionResult?.items.length,
`Line ${position.line} - Character ${position.character}
Expected ${expected.items.length} suggestions and got ${completionResult?.items.length}: ${JSON.stringify(
completionResult?.items,
undefined,
2,
)}`,
).toStrictEqual(expected.items.length)
}
describe('Completions', function () {
// used in more than 1 describe
//#region types
const fieldProvider = {
label: 'provider',
kind: CompletionItemKind.Field,
}
const staticValueTrue = {
label: 'true',
kind: CompletionItemKind.Value,
}
const staticValueFalse = {
label: 'false',
kind: CompletionItemKind.Value,
}
const fieldsProperty = {
label: 'fields',
kind: CompletionItemKind.Property,
}
const mapProperty = {
label: 'map',
kind: CompletionItemKind.Property,
}
const sortProperty = {
label: 'sort',
kind: CompletionItemKind.Property,
}
const nameProperty = {
label: 'name',
kind: CompletionItemKind.Property,
}
//#endregion
describe('BASE BLOCKS', () => {
test('Diagnoses block type suggestions for empty file', () => {
assertCompletion({
schema: /* Prisma */ `|`,
expected: {
isIncomplete: false,
items: [
{ label: 'datasource', kind: CompletionItemKind.Class },
{ label: 'generator', kind: CompletionItemKind.Class },
{ label: 'model', kind: CompletionItemKind.Class },
{ label: 'enum', kind: CompletionItemKind.Class },
],
},
})
})
test('Diagnoses block type suggestions with sqlite as provider', () => {
assertCompletion({
schema: /* Prisma */ `
datasource db {
provider = "sqlite"
}
|
`,
expected: {
isIncomplete: false,
items: [
{ label: 'datasource', kind: CompletionItemKind.Class },
{ label: 'generator', kind: CompletionItemKind.Class },
{ label: 'model', kind: CompletionItemKind.Class },
],
},
})
})
test('Diagnoses block type suggestions with mongodb as provider', () => {
assertCompletion({
schema: /* Prisma */ `
datasource db {
provider = "mongodb"
}
|
`,
expected: {
isIncomplete: false,
items: [
{ label: 'datasource', kind: CompletionItemKind.Class },
{ label: 'generator', kind: CompletionItemKind.Class },
{ label: 'model', kind: CompletionItemKind.Class },
{ label: 'enum', kind: CompletionItemKind.Class },
{ label: 'type', kind: CompletionItemKind.Class },
],
},
})
})
test('Diagnoses block type suggestions for view preview', () => {
assertCompletion({
schema: /* Prisma */ `
generator client {
provider = "prisma-client-js"
// ! Assures we are reading the correct previewFeatures section.
// previewFeatures = []
previewFeatures = ["views"]
}
|
`,
expected: {
isIncomplete: false,
items: [
{ label: 'datasource', kind: CompletionItemKind.Class },
{ label: 'generator', kind: CompletionItemKind.Class },
{ label: 'model', kind: CompletionItemKind.Class },
{ label: 'enum', kind: CompletionItemKind.Class },
{ label: 'view', kind: CompletionItemKind.Class },
],
},
})
})
})
describe('DATABASE BLOCK', () => {
const fieldRelationMode = {
label: 'relationMode',
kind: CompletionItemKind.Field,
}
const fieldPostgresqlExtensions = {
label: 'extensions',
kind: CompletionItemKind.Field,
}
const fieldSchemas = {
label: 'schemas',
kind: CompletionItemKind.Field,
}
const sqlite = { label: 'sqlite', kind: CompletionItemKind.Constant }
const mysql = { label: 'mysql', kind: CompletionItemKind.Constant }
const postgresql = {
label: 'postgresql',
kind: CompletionItemKind.Constant,
}
const sqlserver = {
label: 'sqlserver',
kind: CompletionItemKind.Constant,
}
const mongodb = { label: 'mongodb', kind: CompletionItemKind.Constant }
const cockroachdb = {
label: 'cockroachdb',
kind: CompletionItemKind.Constant,
}
const relationModeForeignKeys = {
label: 'foreignKeys',
kind: CompletionItemKind.Field,
}
const relationModePrisma = {
label: 'prisma',
kind: CompletionItemKind.Field,
}
const relationModeForeignKeysWithQuotes = {
label: '"foreignKeys"',
kind: CompletionItemKind.Field,
}
const relationModePrismaWithQuotes = {
label: '"prisma"',
kind: CompletionItemKind.Field,
}
const quotationMarks = {
label: '""',
kind: CompletionItemKind.Property,
}
test('Diagnoses datasource field suggestions in empty block', () => {
assertCompletion({
schema: /* Prisma */ `
datasource db {
|
}`,
expected: {
isIncomplete: false,
items: [fieldProvider, fieldRelationMode],
},
})
})
test('Diagnoses datasource field suggestions with existing field', () => {
assertCompletion({
schema: /* Prisma */ `
datasource db {
provider = "sqlite"
|
}`,
expected: {
isIncomplete: false,
items: [fieldRelationMode],
},
})
assertCompletion({
schema: /* Prisma */ `
datasource db {
|
}`,
expected: {
isIncomplete: false,
items: [fieldProvider, fieldRelationMode],
},
})
})
test('Diagnoses field extensions availability', () => {
assertCompletion({
schema: /* Prisma */ `
generator client {
provider = "prisma-client-js"
previewFeatures = ["postgresqlExtensions"]
}
datasource db {
provider = "postgresql"
|
}
`,
expected: {
isIncomplete: false,
items: [fieldRelationMode, fieldPostgresqlExtensions, fieldSchemas],
},
})
})
test('Diagnoses field schemas', () => {
assertCompletion({
schema: /* Prisma */ `
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "cockroachdb"
|
}
`,
expected: {
isIncomplete: false,
items: [fieldRelationMode, fieldSchemas],
},
})
})
test('provider = "|"', () => {
assertCompletion({
schema: /* Prisma */ `
datasource db {
provider = "|"
}`,
expected: {
isIncomplete: true,
items: [mysql, postgresql, sqlite, sqlserver, mongodb, cockroachdb],
},
})
})
test('provider = |', () => {
assertCompletion({
schema: /* Prisma */ `
datasource db {
provider = |
}`,
expected: {
isIncomplete: true,
items: [quotationMarks],
},
})
})
test('relationMode = "|"', () => {
assertCompletion({
schema: /* Prisma */ `
datasource db {
provider = "sqlite"
relationMode = "|"
}`,
expected: {
isIncomplete: false,
items: [relationModeForeignKeys, relationModePrisma],
},
})
})
test('relationMode = |', () => {
assertCompletion({
schema: /* Prisma */ `
datasource db {
relationMode = |
}`,
expected: {
isIncomplete: false,
items: [relationModeForeignKeysWithQuotes, relationModePrismaWithQuotes],
},
})
})
})
describe('GENERATOR BLOCK', () => {
// fieldProvider defined above already
//#region types
const fieldOutput = { label: 'output', kind: CompletionItemKind.Field }
const fieldPreviewFeatures = {
label: 'previewFeatures',
kind: CompletionItemKind.Field,
}
const fieldRuntime = {
label: 'runtime',
kind: CompletionItemKind.Field,
}
const fieldModuleFormat = {
label: 'moduleFormat',
kind: CompletionItemKind.Field,
}
const fieldGeneratedFileExtension = {
label: 'generatedFileExtension',
kind: CompletionItemKind.Field,
}
const fieldImportFileExtension = {
label: 'importFileExtension',
kind: CompletionItemKind.Field,
}
const fieldCompilerBuild = {
label: 'compilerBuild',
kind: CompletionItemKind.Field,
}
//#endregion
test('Diagnoses generator field suggestions in empty block', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
|
}`,
expected: {
isIncomplete: false,
items: [fieldProvider],
},
})
})
describe('no generator', () => {
test('with output defined', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
output = "../generated/prisma"
|
}`,
expected: {
isIncomplete: false,
items: [fieldProvider],
},
})
})
test('with preview features defined', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
previewFeatures = []
|
}`,
expected: {
isIncomplete: false,
items: [fieldProvider],
},
})
})
})
describe('prisma-client', () => {
test('Diagnoses generator field suggestions with existing fields', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
provider = "prisma-client"
|
}`,
expected: {
isIncomplete: false,
items: [
fieldPreviewFeatures,
fieldOutput,
fieldRuntime,
fieldModuleFormat,
fieldGeneratedFileExtension,
fieldImportFileExtension,
fieldCompilerBuild,
],
},
})
})
test('runtime = |', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
provider = "prisma-client"
runtime = |
}`,
expected: {
isIncomplete: true,
items: [
{
label: '""',
kind: CompletionItemKind.Property,
},
],
},
})
})
test('runtime = "|"', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
provider = "prisma-client"
runtime = "|"
}`,
expected: {
isIncomplete: true,
items: [
{
label: 'nodejs',
kind: CompletionItemKind.Constant,
},
{
label: 'deno',
kind: CompletionItemKind.Constant,
},
{
label: 'bun',
kind: CompletionItemKind.Constant,
},
{
label: 'workerd',
kind: CompletionItemKind.Constant,
},
{
label: 'cloudflare',
kind: CompletionItemKind.Constant,
},
{
label: 'vercel-edge',
kind: CompletionItemKind.Constant,
},
{
label: 'edge-light',
kind: CompletionItemKind.Constant,
},
{
label: 'react-native',
kind: CompletionItemKind.Constant,
},
],
},
})
})
test('moduleFormat = |', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
provider = "prisma-client"
moduleFormat = |
}`,
expected: {
isIncomplete: true,
items: [
{
label: '""',
kind: CompletionItemKind.Property,
},
],
},
})
})
test('moduleFormat = "|"', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
provider = "prisma-client"
moduleFormat = "|"
}`,
expected: {
isIncomplete: true,
items: [
{
label: 'esm',
kind: CompletionItemKind.Constant,
},
{
label: 'cjs',
kind: CompletionItemKind.Constant,
},
],
},
})
})
test('generatedFileExtension = |', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
provider = "prisma-client"
generatedFileExtension = |
}`,
expected: {
isIncomplete: true,
items: [
{
label: '""',
kind: CompletionItemKind.Property,
},
],
},
})
})
test('generatedFileExtension = "|"', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
provider = "prisma-client"
generatedFileExtension = "|"
}`,
expected: {
isIncomplete: true,
items: [
{
label: 'ts',
kind: CompletionItemKind.Constant,
},
{
label: 'mts',
kind: CompletionItemKind.Constant,
},
{
label: 'cts',
kind: CompletionItemKind.Constant,
},
],
},
})
})
test('importFileExtension = |', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
provider = "prisma-client"
importFileExtension = |
}`,
expected: {
isIncomplete: true,
items: [
{
label: '""',
kind: CompletionItemKind.Property,
},
],
},
})
})
test('importFileExtension = "|"', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
provider = "prisma-client"
importFileExtension = "|"
}`,
expected: {
isIncomplete: true,
items: [
{
label: 'ts',
kind: CompletionItemKind.Constant,
},
{
label: 'mts',
kind: CompletionItemKind.Constant,
},
{
label: 'cts',
kind: CompletionItemKind.Constant,
},
{
label: 'js',
kind: CompletionItemKind.Constant,
},
{
label: 'mjs',
kind: CompletionItemKind.Constant,
},
{
label: 'cjs',
kind: CompletionItemKind.Constant,
},
{
label: '',
kind: CompletionItemKind.Constant,
},
],
},
})
})
test('compilerBuild = "|"', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
provider = "prisma-client"
compilerBuild = "|"
}`,
expected: {
isIncomplete: true,
items: [
{
label: 'fast',
kind: CompletionItemKind.Constant,
},
{
label: 'small',
kind: CompletionItemKind.Constant,
},
],
},
})
})
})
describe('prisma-client-js', () => {
test('Diagnoses generator field suggestions with existing fields', () => {
assertCompletion({
schema: /* Prisma */ `
generator asd {
provider = "prisma-client-js"
|
}`,
expected: {
isIncomplete: false,
items: [fieldPreviewFeatures, fieldOutput, fieldCompilerBuild],
},
})
})
test('compilerBuild = "|"', () => {
assertCompletion({
schema: /* Prisma */ `
generator gen {
provider = "prisma-client-js"
compilerBuild = "|"
}`,
expected: {
isIncomplete: true,
items: [
{
label: 'fast',
kind: CompletionItemKind.Constant,
},
{
label: 'small',
kind: CompletionItemKind.Constant,
},
],
},
})
})
})
})
describe('BLOCK ATTRIBUTES', () => {
//#region types
const blockAttributeId = {
label: '@@id',
kind: CompletionItemKind.Property,
}
const blockAttributeMap = {
label: '@@map',
kind: CompletionItemKind.Property,
}
const blockAttributeUnique = {
label: '@@unique',
kind: CompletionItemKind.Property,
}
const blockAttributeIndex = {
label: '@@index',
kind: CompletionItemKind.Property,
}
const blockAttributeFulltextIndex = {
label: '@@fulltext',
kind: CompletionItemKind.Property,
}
const blockAttributeIgnore = {
label: '@@ignore',
kind: CompletionItemKind.Property,
}
const blockAttributeSchema = {
label: '@@schema',
kind: CompletionItemKind.Property,
}
const blockAttributeShardKey = {
label: '@@shardKey',
kind: CompletionItemKind.Property,
}
const typeProperty = {
label: 'type',
kind: CompletionItemKind.Property,
}
const namespaceOne = {
label: 'one',
kind: CompletionItemKind.Property,
}
const namespaceTwo = {
label: 'two',
kind: CompletionItemKind.Property,
}
//#endregion
test('@@id([|])', () => {
assertCompletion({
schema: /* Prisma */ `
model ThirdUser {
firstName String
lastName String
isAdmin Boolean @default(false)
@@id([|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'firstName', kind: CompletionItemKind.Field },
{ label: 'lastName', kind: CompletionItemKind.Field },
{ label: 'isAdmin', kind: CompletionItemKind.Field },
],
},
})
})
describe('First in a line', () => {
test('Empty model', () => {
assertCompletion({
schema: /* Prisma */ `
model user {
|
}`,
expected: {
isIncomplete: false,
items: [
blockAttributeMap,
blockAttributeId,
blockAttributeUnique,
blockAttributeIndex,
blockAttributeIgnore,
],
},
})
})
test('Model', () => {
assertCompletion({
schema: /* Prisma */ `
model User {
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)
|
}`,
expected: {
isIncomplete: false,
items: [
blockAttributeMap,
blockAttributeId,
blockAttributeUnique,
blockAttributeIndex,
blockAttributeIgnore,
],
},
})
assertCompletion({
schema: /* Prisma */ `
model Post {
id Int @id @default()
email String? @unique
name String
|
}`,
expected: {
isIncomplete: false,
items: [blockAttributeMap, blockAttributeUnique, blockAttributeIndex, blockAttributeIgnore],
},
})
})
test('View', () => {
assertCompletion({
schema: /* Prisma */ `
view User {
firstName String
lastName String
email String @unique
isAdmin Boolean @default(false)
|
}
`,
expected: {
isIncomplete: false,
items: [
blockAttributeMap,
blockAttributeId,
blockAttributeUnique,
blockAttributeIndex,
blockAttributeIgnore,
],
},
})
})
describe('fullTextIndex', () => {
test('MySQL', () => {
assertCompletion({
provider: 'mysql',
previewFeatures: ['fullTextIndex'],
schema: /* Prisma */ `
model Fulltext {
id Int @id
title String @db.VarChar(255)
content String @db.Text
|
@@fulltext()
@@fulltext([title, content], )
}
`,
expected: {
isIncomplete: false,
items: [
blockAttributeMap,
// blockAttributeId,
blockAttributeUnique,
blockAttributeIndex,
blockAttributeFulltextIndex,
blockAttributeIgnore,
],
},
})
})
test('MongoDB', () => {
assertCompletion({
provider: 'mongodb',
previewFeatures: ['fullTextIndex'],
schema: /* Prisma */ `
model Fulltext {
id String @id @map("_id") @db.ObjectId
title String
content String
|
@@fulltext()
@@fulltext([title, content], )
}`,
expected: {
isIncomplete: false,
items: [
blockAttributeMap,
// blockAttributeId,
blockAttributeUnique,
blockAttributeIndex,
blockAttributeFulltextIndex,
blockAttributeIgnore,
],
},
})
})
test('PostgreSQL', () => {
assertCompletion({
provider: 'postgresql',
previewFeatures: ['fullTextIndex'],
schema: /* Prisma */ `
model A {
id Int @id
title String
content String
|
}
`,
expected: {
isIncomplete: false,
items: [
blockAttributeMap,
// blockAttributeId,
blockAttributeUnique,
blockAttributeIndex,
blockAttributeIgnore,
blockAttributeSchema,
],
},
})
})
})
})
describe('shardKey', () => {
test('MySQL', () => {
assertCompletion({
provider: 'mysql',
previewFeatures: ['shardKeys'],
schema: /* Prisma */ `
model Shard {
id Int @id
|
}
`,
expected: {
isIncomplete: false,
items: [
blockAttributeMap,
blockAttributeUnique,
blockAttributeIndex,
blockAttributeIgnore,
blockAttributeShardKey,
],
},
})
})
test('PostgreSQL', () => {
assertCompletion({
provider: 'postgresql',
previewFeatures: ['shardKeys'],
schema: /* Prisma */ `
model A {
id Int @id
|
}
`,
expected: {
isIncomplete: false,
items: [
blockAttributeMap,
blockAttributeUnique,
blockAttributeIndex,
blockAttributeIgnore,
blockAttributeSchema,
// blockAttributeShardKey,
],
},
})
})
})
describe('@@unique()', function () {
describe('No provider', function () {
test('@@unique([|])', () => {
assertCompletion({
schema: /* Prisma */ `
model SecondUser {
firstName String
lastName String
isAdmin Boolean @default(false)
@@unique([|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'firstName', kind: CompletionItemKind.Field },
{ label: 'lastName', kind: CompletionItemKind.Field },
{ label: 'isAdmin', kind: CompletionItemKind.Field },
],
},
})
})
test('@@unique(fields: [|])', () => {
assertCompletion({
schema: /* Prisma */ `
model SecondUser {
firstName String
lastName String
isAdmin Boolean @default(false)
@@unique(fields: [|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'firstName', kind: CompletionItemKind.Field },
{ label: 'lastName', kind: CompletionItemKind.Field },
{ label: 'isAdmin', kind: CompletionItemKind.Field },
],
},
})
})
})
describe('MongoDB', function () {
test('@@unique([|])', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@unique([|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'id', kind: CompletionItemKind.Field },
{ label: 'email', kind: CompletionItemKind.Field },
{ label: 'address', kind: CompletionItemKind.Field },
],
},
})
})
test('@@unique(fields: [|])', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@unique(fields: [|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'id', kind: CompletionItemKind.Field },
{ label: 'email', kind: CompletionItemKind.Field },
{ label: 'address', kind: CompletionItemKind.Field },
],
},
})
})
})
})
describe('@@index()', function () {
describe('No provider', function () {
test('@@index([|])', () => {
assertCompletion({
schema: /* Prisma */ `
model ThirdUser {
firstName String
lastName String
isAdmin Boolean @default(false)
@@index([|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'firstName', kind: CompletionItemKind.Field },
{ label: 'lastName', kind: CompletionItemKind.Field },
{ label: 'isAdmin', kind: CompletionItemKind.Field },
],
},
})
})
test('@@index(fields: [|])', () => {
assertCompletion({
schema: /* Prisma */ `
model ThirdUser {
firstName String
lastName String
isAdmin Boolean @default(false)
@@index(field: [|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'firstName', kind: CompletionItemKind.Field },
{ label: 'lastName', kind: CompletionItemKind.Field },
{ label: 'isAdmin', kind: CompletionItemKind.Field },
],
},
})
})
})
describe('MongoDB', function () {
test('@@index([|])', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@index([|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'id', kind: CompletionItemKind.Field },
{ label: 'email', kind: CompletionItemKind.Field },
{ label: 'address', kind: CompletionItemKind.Field },
],
},
})
})
test('@@index([a|])', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
}
model User {
id Int @id @map("_id")
email String
address Address
account Int
@@index([a|])
}`,
expected: {
isIncomplete: false,
items: [
// These are returned, but `onCompletionResolve` will only complete with the current match
// which means the completion will actually be
// address and account
// TODO create a test that shows that
{ label: 'id', kind: CompletionItemKind.Field },
{ label: 'email', kind: CompletionItemKind.Field },
{ label: 'address', kind: CompletionItemKind.Field },
{ label: 'account', kind: CompletionItemKind.Field },
],
},
})
})
test('@@index([address|])', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
}
model User {
id Int @id @map("_id")
email String
address Address
account Int
@@index([address|])
}`,
expected: {
isIncomplete: false,
items: [
// These are returned though the completion will actually be
// No suggestions
// TODO create a test that shows that
{ label: 'id', kind: CompletionItemKind.Field },
{ label: 'email', kind: CompletionItemKind.Field },
{ label: 'account', kind: CompletionItemKind.Field },
],
},
})
})
test('@@index([address,|])', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@index([address,|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'id', kind: CompletionItemKind.Field },
{ label: 'email', kind: CompletionItemKind.Field },
],
},
})
})
test('@@index([address, |])', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@index([address, |])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'id', kind: CompletionItemKind.Field },
{ label: 'email', kind: CompletionItemKind.Field },
],
},
})
})
test('@@index([address.|]) first position, with only one type', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@index([address.|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'street', kind: CompletionItemKind.Field },
{ label: 'number', kind: CompletionItemKind.Field },
],
},
})
})
test('@@index([address.|]) with composite type suggestion 1', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
alpha Alpha
}
type Alpha {
bravo Bravo
helloA Int
}
type Bravo {
something String
helloBravo Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@index([address.|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'street', kind: CompletionItemKind.Field },
{ label: 'number', kind: CompletionItemKind.Field },
{ label: 'alpha', kind: CompletionItemKind.Field },
],
},
})
})
test('@@index([address.a|]) with composite type suggestion 1', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
alpha Alpha
}
type Alpha {
bravo Bravo
helloA Int
}
type Bravo {
something String
helloBravo Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@index([address.a|])
}`,
expected: {
isIncomplete: false,
// TODO, see if we can have better suggestions here, should suggest `alpha`
items: [],
},
})
})
test('@@index([email,address.|]) with composite type suggestion, depth 1', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
alpha Alpha
}
type Alpha {
bravo Bravo
helloA Int
}
type Bravo {
something String
helloBravo Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@index([email,address.|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'street', kind: CompletionItemKind.Field },
{ label: 'number', kind: CompletionItemKind.Field },
{ label: 'alpha', kind: CompletionItemKind.Field },
],
},
})
})
test('@@index([email, address.|]) with composite type suggestion, depth 1', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
alpha Alpha
}
type Alpha {
bravo Bravo
helloA Int
}
type Bravo {
something String
helloBravo Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@index([email, address.|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'street', kind: CompletionItemKind.Field },
{ label: 'number', kind: CompletionItemKind.Field },
{ label: 'alpha', kind: CompletionItemKind.Field },
],
},
})
})
test('@@index([email, address.alpha.|]) with composite type suggestion, depth 2', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
alpha Alpha
}
type Alpha {
bravo Bravo
helloA Int
}
type Bravo {
something String
helloBravo Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@index([email, address.alpha.|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'bravo', kind: CompletionItemKind.Field },
{ label: 'helloA', kind: CompletionItemKind.Field },
],
},
})
})
test('@@index([email, address.alpha.bravo.|]) with composite type suggestion, depth 3', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
alpha Alpha
}
type Alpha {
bravo Bravo
helloA Int
}
type Bravo {
something String
helloBravo Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@index([email, address.alpha.bravo.|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'something', kind: CompletionItemKind.Field },
{ label: 'helloBravo', kind: CompletionItemKind.Field },
],
},
})
})
test('@@index([email, address.alpha.bravo.hello|]) with composite type suggestion, depth 3', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
alpha Alpha
}
type Alpha {
bravo Bravo
helloA Int
}
type Bravo {
something String
helloBravo Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@index([email, address.alpha.bravo.hello||])
}`,
expected: {
isIncomplete: false,
// TODO, see if we can have better suggestions here, should suggest `helloBravo`
items: [],
},
})
})
test('@@index(fields: [|])', () => {
assertCompletion({
provider: 'mongodb',
schema: /* Prisma */ `
type Address {
street String
number Int
}
model User {
id Int @id @map("_id")
email String
address Address
@@index(fields: [|])
}`,
expected: {
isIncomplete: false,
items: [
{ label: 'id', kind: CompletionItemKind.Field },
{ label: 'email', kind: CompletionItemKind.Field },
{ label: 'address', kind: CompletionItemKind.Field },
],
},
})
})
})
describe('extendedIndexes - PostgreSQL', function () {
test('@@index(|)', () => {
assertCompletion({
provider: 'postgresql',
schema: /* Prisma */ `
model A {
id Int @id
title String
content String
@@index(|)
}
`,
expected: {
isIncomplete: false,
items: [fieldsProperty, mapProperty, typeProperty],
},
})
})
test('@@index([title], |) - postgresql', () => {
assertCompletion({
provider: 'postgresql',
schema: /* Prisma */ `
model A {
id Int @id
title String
content String
@@index([title], |)
}
`,
expected: {
isIncomplete: false,
items: [fieldsProperty, mapProperty, typeProperty],
},
})
})
test('@@index([title], type: |) - postgresql', () => {
assertCompletion({
provider: 'postgresql',
schema: /* Prisma */ `
model A {
id Int @id
title String
content String
@@index([title], type: |)
}
`,
expected: {
isIncomplete: false,
items: [
{ label: 'BTree', kind: CompletionItemKind.Enum },
{ label: 'Hash', kind: CompletionItemKind.Enum },
{ label: 'Gist', kind: CompletionItemKind.Enum },
{ label: 'Gin', kind: CompletionItemKind.Enum },
{ label: 'SpGist', kind: CompletionItemKind.Enum },
{ label: 'Brin', kind: CompletionItemKind.Enum },
],
},
})
})
test('@@index([title], type: Hash, |) - postgresql', () => {
assertCompletion({
provider: 'postgresql',
schema: /* Prisma */ `
model A {
id Int @id
title String
content String
@@index([title], type: Hash, |)
}
`,
expected: {
isIncomplete: false,
items: [fieldsProperty, mapProperty],
},
})
})
test('@@index([title(|)]) - postgresql', () => {
assertCompletion({
provider: 'postgresql',
schema: /* Prisma */ `
model A {
id Int @id
title String
content String
@@index([title(|)])
}
`,
expected: {
isIncomplete: false,
items: [
{ label: 'ops', kind: CompletionItemKind.Property },
{ label: 'sort', kind: CompletionItemKind.Property },
],
},
})
})
test('@@index([title(ops: |)]) - postgresql', () => {
assertCompletion({
provider: 'postgresql',
schema: /* Prisma */ `
model A {
id Int @id
title String @db.Inet
content String
@@index([title(ops: |)])
}
`,
expected: {
isIncomplete: false,
items: [{ label: 'raw', kind: CompletionItemKind.Function }],
},
})
})
test('@@index([title(ops: |)], type: Gist) - postgresql', () => {
assertCompletion({
provider: 'postgresql',
schema: /* Prisma */ `
model A {
id Int @id
title String @db.Inet
content String
@@index([title(ops: |)], type: Gist)
}
`,
expected: {
isIncomplete: false,
items: [
{ label: 'InetOps', kind: CompletionItemKind.Enum },
{ label: 'raw', kind: CompletionItemKind.Function },
],
},
})
})
})
})
describe('@@fulltext()', function () {
test('@@fulltext(|) - mysql', () => {
assertCompletion({
provider: 'mysql',
previewFeatures: ['fullTextIndex'],
schema: /* Prisma */ `
model Fulltext {
id Int @id
title String @db.VarChar(255)
content String @db.Text
@@fulltext(|)
@@fulltext([title, content], )
}
`,
expected: {
isIncomplete: false,
items: [fieldsProperty, mapProperty],
},
})
})
test('@@fulltext([title, content], |) - mysql', () => {
assertCompletion({
provider: 'mysql',
previewFeatures: ['fullTextIndex'],
schema: /* Prisma */ `
model Fulltext {
id Int @id
title String @db.VarChar(255)
content String @db.Text
@@fulltext()
@@fulltext([title, content], |)
}
`,
expected: {
isIncomplete: false,
items: [fieldsProperty, mapProperty],
},
})
})
test('@@fulltext(|) - mongodb', () => {
assertCompletion({
provider: 'mongodb',
previewFeatures: ['fullTextIndex'],
schema: /* Prisma */ `
model Fulltext {
id String @id @map("_id") @db.ObjectId
title String
content String
@@fulltext(|)
@@fulltext([title, content], )
}
// https://www.prisma.io/docs/concepts/components/prisma-schema/indexes#examples
// On MongoDB, the fullTextIndex and extendedIndexes preview features can be co