-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* init * tests and types * Refactor index retrieval and add index service * lint fixes * Update API endpoints for index operations * Update API endpoint for creating indexes * Commented out unused database configurations * Add index provider test support and generate random domain and SPI indexes * Update import statement for IIndexProvider * Add logger to IndexProvider constructor * Fix index creation and error handling * Add IndexProvider to connection provider * Refactor test description to be more descriptive * Update supported operations for external databases * Refactor index creation and removal in MySQL index provider * Refactor index creation and removal in PostgresIndexProvider * Refactor index API response structure * Refactor index creation in PostgresIndexProvider * Add support for indexes in capabilities response * Add extractIndexFromIndexQueryForCollection function to postgres_utils * Fix index query for collection name * Refactor query for retrieving active index creation queries --------- Co-authored-by: Ido Kahlon <[email protected]>
- Loading branch information
Showing
30 changed files
with
976 additions
and
28 deletions.
There are no files selected for viewing
49 changes: 49 additions & 0 deletions
49
apps/velo-external-db/test/drivers/index_api_rest_matchers.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { indexSpi } from '@wix-velo/velo-external-db-core' | ||
const { IndexFieldOrder, IndexStatus } = indexSpi | ||
|
||
const indexWith = (index: indexSpi.Index, extraProps: Partial<indexSpi.Index>) => ({ | ||
...index, | ||
fields: index.fields.map(field => ({ | ||
...field, | ||
order: expect.toBeOneOf([IndexFieldOrder.ASC, IndexFieldOrder.DESC]), | ||
})), | ||
caseInsensitive: expect.any(Boolean), // TODO: remove this when we support case insensitive indexes | ||
...extraProps | ||
}) | ||
|
||
export const failedIndexCreationResponse = (index: indexSpi.Index) => ({ | ||
index: indexWith(index, { status: IndexStatus.FAILED }) | ||
}) | ||
|
||
|
||
export const listIndexResponseWithDefaultIndex = () => ({ | ||
indexes: expect.arrayContaining([toHaveDefaultIndex()]) | ||
}) | ||
|
||
export const listIndexResponseWith = (indexes: indexSpi.Index[]) => ({ | ||
indexes: expect.arrayContaining( | ||
[...indexes.map((index: indexSpi.Index) => indexWith(index, { status: IndexStatus.ACTIVE }))] | ||
) | ||
}) | ||
|
||
export const toHaveDefaultIndex = () => ({ | ||
name: expect.any(String), | ||
fields: expect.arrayContaining([ | ||
expect.objectContaining({ | ||
path: '_id', | ||
order: expect.toBeOneOf([IndexFieldOrder.ASC, IndexFieldOrder.DESC]) | ||
}) | ||
]), | ||
caseInsensitive: expect.any(Boolean), | ||
status: IndexStatus.ACTIVE, | ||
unique: true | ||
}) | ||
|
||
|
||
export const createIndexResponseWith = (index: indexSpi.Index) => ({ index: indexWith(index, { status: IndexStatus.BUILDING }) }) | ||
|
||
export const removeIndexResponse = () => (({})) | ||
|
||
export const listIndexResponseWithFailedIndex = (index: indexSpi.Index) => { | ||
return expect.arrayContaining([indexWith(index, { status: IndexStatus.FAILED })]) | ||
} |
30 changes: 30 additions & 0 deletions
30
apps/velo-external-db/test/drivers/index_api_rest_test_support.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import axios from 'axios' | ||
import waitUntil from 'async-wait-until' | ||
import { indexSpi } from '@wix-velo/velo-external-db-core' | ||
|
||
const axiosInstance = axios.create({ | ||
baseURL: 'http://localhost:8080/v3' | ||
}) | ||
|
||
export const givenIndexes = async(collectionName: string, indexes: indexSpi.Index[], auth: any) => { | ||
for (const index of indexes) { | ||
await axiosInstance.post('/indexes/create', { collectionId: collectionName, index } as indexSpi.CreateIndexRequest, auth) | ||
} | ||
await Promise.all(indexes.map(index => indexCreated(collectionName, index.name, auth))) | ||
} | ||
|
||
const indexCreated = async(collectionName: string, indexName: string, auth: any) => { | ||
await waitUntil(async() => { | ||
const { indexes } = await retrieveIndexesFor(collectionName, auth) as indexSpi.ListIndexesResponse | ||
return indexes.some(index => index.name === indexName) | ||
}) | ||
} | ||
|
||
export const createIndexFor = async(collectionName: string, index: indexSpi.Index, auth: any) => await | ||
axiosInstance.post('/indexes/create', { collectionId: collectionName, index } as indexSpi.CreateIndexRequest, auth).then(res => res.data) | ||
|
||
export const removeIndexFor = async(collectionName: string, indexName: string, auth: any) => await | ||
axiosInstance.post('/indexes/remove', { collectionId: collectionName, indexName } as indexSpi.RemoveIndexRequest, auth).then(res => res.data) | ||
|
||
export const retrieveIndexesFor = async(collectionName: string, auth: any) => await | ||
axiosInstance.post('/indexes/list', { collectionId: collectionName } as indexSpi.ListIndexesRequest, { transformRequest: auth.transformRequest }).then(res => res.data) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import Chance = require('chance') | ||
import { Uninitialized, testIfSupportedOperationsIncludes } from '@wix-velo/test-commons' | ||
import { authOwner } from '@wix-velo/external-db-testkit' | ||
import { initApp, teardownApp, dbTeardown, setupDb, currentDbImplementationName, supportedOperations } from '../resources/e2e_resources' | ||
import * as schema from '../drivers/schema_api_rest_test_support' | ||
import * as matchers from '../drivers/index_api_rest_matchers' | ||
import * as index from '../drivers/index_api_rest_test_support' | ||
import * as gen from '../gen' | ||
import axios from 'axios' | ||
const chance = new Chance() | ||
import { eventually } from '../utils/eventually' | ||
import { InputField, SchemaOperations } from '@wix-velo/velo-external-db-types' | ||
import { indexSpi } from '@wix-velo/velo-external-db-core' | ||
|
||
const { Indexing } = SchemaOperations | ||
|
||
const axiosServer = axios.create({ | ||
baseURL: 'http://localhost:8080/v3' | ||
}) | ||
|
||
|
||
describe(`Velo External DB Index API: ${currentDbImplementationName()}`, () => { | ||
beforeAll(async() => { | ||
await setupDb() | ||
await initApp() | ||
}) | ||
|
||
afterAll(async() => { | ||
await dbTeardown() | ||
}, 20000) | ||
|
||
testIfSupportedOperationsIncludes(supportedOperations, [Indexing])('list', async() => { | ||
await schema.givenCollection(ctx.collectionName, [ctx.column], authOwner) | ||
|
||
await expect(index.retrieveIndexesFor(ctx.collectionName, authOwner)).resolves.toEqual(matchers.listIndexResponseWithDefaultIndex()) | ||
}) | ||
|
||
testIfSupportedOperationsIncludes(supportedOperations, [Indexing])('list with multiple indexes', async() => { | ||
await schema.givenCollection(ctx.collectionName, [ctx.column], authOwner) | ||
await index.givenIndexes(ctx.collectionName, [ctx.index], authOwner) | ||
|
||
await expect(index.retrieveIndexesFor(ctx.collectionName, authOwner)).resolves.toEqual(matchers.listIndexResponseWith([ctx.index])) | ||
}) | ||
|
||
testIfSupportedOperationsIncludes(supportedOperations, [Indexing])('create', async() => { | ||
await schema.givenCollection(ctx.collectionName, [ctx.column], authOwner) | ||
|
||
// in-progress | ||
await expect(index.createIndexFor(ctx.collectionName, ctx.index, authOwner)).resolves.toEqual(matchers.createIndexResponseWith(ctx.index)) | ||
|
||
// active | ||
await eventually(async() => | ||
await expect(index.retrieveIndexesFor(ctx.collectionName, authOwner)).resolves.toEqual(matchers.listIndexResponseWith([ctx.index])) | ||
) | ||
}) | ||
|
||
testIfSupportedOperationsIncludes(supportedOperations, [Indexing])('create an index on a column that already has an existing index, should return the index with status failed', async() => { | ||
await schema.givenCollection(ctx.collectionName, [ctx.column], authOwner) | ||
await index.givenIndexes(ctx.collectionName, [ctx.index], authOwner) | ||
|
||
await eventually(async() => await expect(axiosServer.post('/indexes/create', { | ||
dataCollectionId: ctx.collectionName, | ||
index: ctx.index | ||
}, authOwner).then(res => res.data)).resolves.toEqual(matchers.failedIndexCreationResponse(ctx.index) | ||
)) | ||
}) | ||
|
||
testIfSupportedOperationsIncludes(supportedOperations, [Indexing])('creation of index with invalid column should return the index with status failed', async() => { | ||
await schema.givenCollection(ctx.collectionName, [ctx.column], authOwner) | ||
|
||
await eventually(async() => await expect(index.createIndexFor(ctx.collectionName, ctx.invalidIndex, authOwner)).resolves.toEqual(matchers.failedIndexCreationResponse(ctx.invalidIndex))) | ||
}) | ||
|
||
testIfSupportedOperationsIncludes(supportedOperations, [Indexing])('remove', async() => { | ||
await schema.givenCollection(ctx.collectionName, [ctx.column], authOwner) | ||
await index.givenIndexes(ctx.collectionName, [ctx.index], authOwner) | ||
|
||
await expect( index.removeIndexFor(ctx.collectionName, ctx.index.name, authOwner)).resolves.toEqual(matchers.removeIndexResponse()) | ||
|
||
await expect(index.retrieveIndexesFor(ctx.collectionName, authOwner)).resolves.not.toEqual(matchers.listIndexResponseWith([ctx.index])) | ||
}) | ||
|
||
afterAll(async() => { | ||
await teardownApp() | ||
}) | ||
|
||
interface Ctx { | ||
collectionName: string | ||
column: InputField | ||
index: indexSpi.Index | ||
invalidIndex: indexSpi.Index | ||
} | ||
|
||
const ctx: Ctx = { | ||
collectionName: Uninitialized, | ||
column: Uninitialized, | ||
index: Uninitialized, | ||
invalidIndex: Uninitialized, | ||
} | ||
|
||
beforeEach(() => { | ||
ctx.collectionName = chance.word() | ||
ctx.column = gen.randomColumn() | ||
ctx.index = gen.spiIndexFor(ctx.collectionName, [ctx.column.name]) | ||
ctx.invalidIndex = gen.spiIndexFor(ctx.collectionName, ['wrongColumn']) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import * as trier from 'trier-promise' | ||
|
||
const defaults = { | ||
timeout: 5000, | ||
interval: 200 | ||
} | ||
|
||
export const eventually = async(fn: any, opts?: { timeout?: number; interval?: number }) => { | ||
return Promise.resolve().then(() => { | ||
let error = null | ||
const action = () => Promise.resolve().then(fn).catch(err => { | ||
error = err | ||
throw err | ||
}) | ||
const options = Object.assign({ action }, defaults, opts) | ||
|
||
return trier(options).catch(() => { | ||
if (error !== null) { | ||
error.message = `Timeout of ${options.timeout} ms with: ` + error.message | ||
} | ||
throw error | ||
}) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,8 @@ | ||
import { AllSchemaOperations } from '@wix-velo/velo-external-db-commons' | ||
import { SchemaOperations } from '@wix-velo/velo-external-db-types' | ||
const notSupportedOperations = [SchemaOperations.AtomicBulkInsert] | ||
const notSupportedOperations = [ | ||
SchemaOperations.AtomicBulkInsert, | ||
SchemaOperations.Indexing, | ||
] | ||
|
||
export const supportedOperations = AllSchemaOperations.filter(op => !notSupportedOperations.includes(op)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,10 @@ | ||
import { AllSchemaOperations } from '@wix-velo/velo-external-db-commons' | ||
import { SchemaOperations } from '@wix-velo/velo-external-db-types' | ||
const notSupportedOperations = [SchemaOperations.QueryNestedFields, SchemaOperations.FindObject, SchemaOperations.NonAtomicBulkInsert] | ||
const notSupportedOperations = [ | ||
SchemaOperations.QueryNestedFields, | ||
SchemaOperations.FindObject, | ||
SchemaOperations.NonAtomicBulkInsert, | ||
SchemaOperations.Indexing, | ||
] | ||
|
||
export const supportedOperations = AllSchemaOperations.filter(op => !notSupportedOperations.includes(op)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.