Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 53 additions & 50 deletions integration-tests/admin/test/index.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { after, before, describe } from 'node:test';

Copy link
Contributor Author

@demariadaniel demariadaniel Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Heads up that multiple files include simple prettier cleanup changes to clear up the repo (mostly order of imports, whitespace, & falsy handling) or Typescript updates to declutter the repo.

The main change is the creation of a SearchClient which replaces instances of ElasticSearch Client.

import { Client } from '@elastic/elasticsearch';
import express from 'express';

import Arranger, { adminGraphql } from '../../../modules/server/dist';
import ajax from '../../../modules/server/dist/utils/ajax';
import addProject from './addProject';
import Arranger, { adminGraphql } from '../../../modules/server/dist/index.js';
import ajax from '../../../modules/server/dist/utils/ajax.js';

import addProject from './addProject.js';

const file_centric_mapppings = require('./assets/file_centric.mappings.json');

Expand All @@ -19,58 +22,58 @@ const app = express();

const api = ajax(`http://localhost:${port}`);
const esClient = new Client({
...(useAuth && {
auth: {
username: esUser,
password: esPwd,
},
}),
node: esHost,
...(useAuth && {
auth: {
username: esUser,
password: esPwd,
},
}),
node: esHost,
});

const cleanup = () =>
Promise.all([
esClient.indices.delete({
index: esIndex,
}),
esClient.indices.delete({
index: 'arranger-projects*',
}),
]);
Promise.all([
esClient.indices.delete({
index: esIndex,
}),
esClient.indices.delete({
index: 'arranger-projects*',
}),
]);

describe('@arranger/admin', () => {
let server;
const adminPath = '/admin/graphql';
before(async () => {
console.log('===== Initializing Elasticsearch data =====');
try {
await cleanup();
} catch (err) {}
await esClient.indices.create({
index: esIndex,
body: file_centric_mapppings,
});
let server;
const adminPath = '/admin/graphql';
before(async () => {
console.log('===== Initializing Elasticsearch data =====');
try {
await cleanup();
} catch (err) {}
await esClient.indices.create({
index: esIndex,
body: file_centric_mapppings,
});

console.log('===== Starting arranger app for test =====');
const router = await Arranger({ esHost, enableAdmin: false });
const adminApp = await adminGraphql({ esHost });
adminApp.applyMiddleware({ app, path: adminPath });
app.use(router);
await new Promise((resolve) => {
server = app.listen(port, () => {
resolve();
});
});
});
after(async () => {
server?.close();
await cleanup();
});
console.log('===== Starting arranger app for test =====');
const router = await Arranger({ esHost, enableAdmin: false });
const adminApp = await adminGraphql({ esHost });
adminApp.applyMiddleware({ app, path: adminPath });
app.use(router);
await new Promise((resolve) => {
server = app.listen(port, () => {
resolve();
});
});
});
after(async () => {
server?.close();
await cleanup();
});

const env = {
api,
esIndex,
adminPath,
};
addProject(env);
const env = {
api,
esIndex,
adminPath,
};
addProject(env);
});
3 changes: 2 additions & 1 deletion modules/server/.env.schema
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ MAX_RESULTS_WINDOW=10000
PING_MS=2200
PING_PATH=/ping
PORT=5050
ROW_ID_FIELD_NAME=id
ROW_ID_FIELD_NAME=id
SEARCH_CLIENT=''
3 changes: 2 additions & 1 deletion modules/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@
"watch": "npm run clear:dist && npm run build -- --watch"
},
"dependencies": {
"@graphql-tools/merge": "^9.0.4",
"@elastic/elasticsearch": "^7.17.14",
"@graphql-tools/merge": "^9.0.4",
"@graphql-tools/schema": "^9.0.17",
"@graphql-tools/utils": "^10.2.2",
"@opensearch-project/opensearch": "^3.5.1",
"@overture-stack/sqon-builder": "^1.1.0",
"apollo-server": "^3.10.3",
"apollo-server-core": "^3.10.3",
Expand Down
163 changes: 81 additions & 82 deletions modules/server/src/admin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,100 +2,99 @@
import { addMocksToSchema } from '@graphql-tools/mock';
import { mergeSchemas } from '@graphql-tools/schema';
import { ApolloServer } from 'apollo-server-express';
import { Client } from '@elastic/elasticsearch';
import { type GraphQLSchema } from 'graphql';
import { print } from 'graphql/language/printer';
import { GraphQLSchema } from 'graphql';

import { type SearchClient } from '#searchClient/types.js';

import {
createAggsStateByIndexResolver,
createColumnsStateByIndexResolver,
createExtendedMappingsByIndexResolver,
createIndexByProjectResolver,
createIndicesByProjectResolver,
createMatchBoxStateByIndexResolver,
} from './resolvers';
import { createSchema as createProjectSchema } from './schemas/ProjectSchema';
import { createSchema as createIndexSchema } from './schemas/IndexSchema';
import { createSchema as createAggsStateSchema } from './schemas/AggsState';
import { createSchema as createMatchboxStateSchema } from './schemas/MatchboxState';
import { createSchema as createColumnsStateSchema } from './schemas/ColumnsState';
import { createSchema as createExtendedMappingSchema } from './schemas/ExtendedMapping';
import mergedTypeDefs from './schemaTypeDefs';
import { constants } from './services/constants';
import { createClient as createElasticsearchClient } from './services/elasticsearch';
import { AdminApiConfig, IQueryContext } from './types';
createAggsStateByIndexResolver,
createColumnsStateByIndexResolver,
createExtendedMappingsByIndexResolver,
createIndexByProjectResolver,
createIndicesByProjectResolver,
createMatchBoxStateByIndexResolver,
} from './resolvers.js';
import { createSchema as createAggsStateSchema } from './schemas/AggsState/index.js';
import { createSchema as createColumnsStateSchema } from './schemas/ColumnsState/index.js';
import { createSchema as createExtendedMappingSchema } from './schemas/ExtendedMapping/index.js';
import { createSchema as createIndexSchema } from './schemas/IndexSchema/index.js';
import { createSchema as createMatchboxStateSchema } from './schemas/MatchboxState/index.js';
import { createSchema as createProjectSchema } from './schemas/ProjectSchema/index.js';
import mergedTypeDefs from './schemaTypeDefs.js';
import { constants } from './services/constants.js';
import { createClient as createElasticsearchClient } from './services/elasticsearch/index.js';
import { type AdminApiConfig, type IQueryContext } from './types.js';

const createSchema = async () => {
const typeDefs = mergedTypeDefs;
const typeDefs = mergedTypeDefs;

const projectSchema = await createProjectSchema();
const aggsStateSchema = await createAggsStateSchema();
const collumnsStateSchema = await createColumnsStateSchema();
const extendedMappingShema = await createExtendedMappingSchema();
const matchBoxStateSchema = await createMatchboxStateSchema();
const indexSchema = await createIndexSchema();
const projectSchema = await createProjectSchema();
const aggsStateSchema = await createAggsStateSchema();
const collumnsStateSchema = await createColumnsStateSchema();
const extendedMappingShema = await createExtendedMappingSchema();
const matchBoxStateSchema = await createMatchboxStateSchema();
const indexSchema = await createIndexSchema();

const mergedSchema = mergeSchemas({
schemas: [
projectSchema,
indexSchema,
aggsStateSchema,
collumnsStateSchema,
extendedMappingShema,
matchBoxStateSchema,
print(typeDefs) as unknown as GraphQLSchema, // TODO: this type coercion is smelly
],
resolvers: {
Project: {
index: createIndexByProjectResolver(indexSchema),
indices: createIndicesByProjectResolver(indexSchema),
},
Index: {
extended: createExtendedMappingsByIndexResolver(extendedMappingShema),
columnsState: createColumnsStateByIndexResolver(collumnsStateSchema),
aggsState: createAggsStateByIndexResolver(aggsStateSchema),
matchBoxState: createMatchBoxStateByIndexResolver(matchBoxStateSchema),
},
},
});
addMocksToSchema({ schema: mergedSchema, preserveResolvers: true });
return mergedSchema;
const mergedSchema = mergeSchemas({
schemas: [
projectSchema,
indexSchema,
aggsStateSchema,
collumnsStateSchema,
extendedMappingShema,
matchBoxStateSchema,
print(typeDefs) as unknown as GraphQLSchema, // TODO: this type coercion is smelly
],
resolvers: {
Project: {
index: createIndexByProjectResolver(indexSchema),
indices: createIndicesByProjectResolver(indexSchema),
},
Index: {
extended: createExtendedMappingsByIndexResolver(extendedMappingShema),
columnsState: createColumnsStateByIndexResolver(collumnsStateSchema),
aggsState: createAggsStateByIndexResolver(aggsStateSchema),
matchBoxState: createMatchBoxStateByIndexResolver(matchBoxStateSchema),
},
},
});
addMocksToSchema({ schema: mergedSchema, preserveResolvers: true });
return mergedSchema;
};

function buildElasticsearchClient(config: AdminApiConfig) {
return createElasticsearchClient(config.esHost, config.esUser, config.esPass);
return createElasticsearchClient(config.esHost, config.esUser, config.esPass);
}

const initialize = (config: AdminApiConfig): Promise<Client> =>
new Promise(async (resolve, reject) => {
console.info('Initializing Elasticsearch Client for host: ' + config.esHost);
const esClient = buildElasticsearchClient(config);
try {
console.info(
'Checking if index ' + constants.ARRANGER_PROJECT_INDEX + ' exists in Elasticsearch',
);
const exists = await esClient.indices.exists({
index: constants.ARRANGER_PROJECT_INDEX,
});
if (!exists) {
esClient.indices.create({
index: constants.ARRANGER_PROJECT_INDEX,
});
}
resolve(esClient);
} catch (err) {
setTimeout(() => {
initialize(config).then(() => resolve(esClient));
}, 1000);
}
});
const initialize = async (config: AdminApiConfig): Promise<SearchClient | undefined> => {
console.info('Initializing Elasticsearch Client for host: ' + config.esHost);
const esClient = await buildElasticsearchClient(config);
try {
console.info('Checking if index ' + constants.ARRANGER_PROJECT_INDEX + ' exists in Elasticsearch');
const exists = await esClient.indices.exists({
index: constants.ARRANGER_PROJECT_INDEX,
});
if (!exists) {
esClient.indices.create({
index: constants.ARRANGER_PROJECT_INDEX,
});
}
return esClient;
} catch (err) {
setTimeout(async () => {
return await initialize(config);
}, 1000);
}
};

export default async (config: AdminApiConfig) => {
const esClient = await initialize(config);
return new ApolloServer({
schema: await createSchema(),
context: (): IQueryContext => ({
es: esClient,
}),
});
const esClient = await initialize(config);
if (!esClient) throw new Error('Could not initialize esClient');
return new ApolloServer({
schema: await createSchema(),
context: (): IQueryContext => ({
es: esClient,
}),
});
};
15 changes: 8 additions & 7 deletions modules/server/src/admin/schemas/AggsState/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import resolvers from './resolvers';
import typeDefs from './schemaTypeDefs';
import { makeExecutableSchema } from 'graphql-tools';

import resolvers from './resolvers.js';
import typeDefs from './schemaTypeDefs.js';

export const createSchema = async () => {
const schema = makeExecutableSchema({
typeDefs: await typeDefs(),
resolvers,
});
return schema;
const schema = makeExecutableSchema({
typeDefs: await typeDefs(),
resolvers,
});
return schema;
};
Loading