UNPKG

@prisma/language-server

Version:
1,797 lines (1,728 loc) • 121 kB
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