@memberjunction/server 0.9.75 → 0.9.77

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,156 +1,156 @@
1
- import { MJGlobal, RegisterClass } from "@memberjunction/global";
2
- import { BaseEntity, EntityInfo, LogError, Metadata } from "@memberjunction/core";
3
- import { UserViewEntityExtended } from '@memberjunction/core-entities'
4
- import { BaseLLM, BaseModel, ChatParams, IChat, OpenAILLM } from "@memberjunction/ai";
5
-
6
- @RegisterClass(BaseEntity, 'User Views', 3) // high priority to ensure this is used ahead of the UserViewEntityExtended in the @memberjunction/core-entities package (which has priority of 2)
7
- export class UserViewEntity_Server extends UserViewEntityExtended {
8
- /**
9
- * This property is hard-coded to true in this class because we DO support smart filters in this class. If you want to disable smart filters for a specific view you can override this property in your subclass and set it to false.
10
- */
11
- protected override get SmartFilterImplemented(): boolean {
12
- return true;
13
- }
14
-
15
- /**
16
- * This method will use AI to return a valid WHERE clause based on the provided prompt. This is automatically called at the right time if the view has SmartFilterEnabled turned on and the SmartFilterPrompt is set. If you want
17
- * to call this directly to get back a WHERE clause for other purposes you can call this method directly and provide both a prompt and the entity that the view is based on.
18
- * @param prompt
19
- */
20
- public async GenerateSmartFilterWhereClause(prompt: string, entityInfo: EntityInfo): Promise<{whereClause: string, userExplanation: string}> {
21
- try {
22
- const llm = <IChat> new OpenAILLM(); // for now, hardcoded to use OpenAI
23
-
24
- const chatParams: ChatParams = {
25
- model: 'gpt-4',
26
- systemPrompt: this.GenerateSysPrompt(entityInfo),
27
- userMessage: '',
28
- messages: [
29
- {
30
- role: 'user',
31
- content: `${prompt}`,
32
- },
33
- ],
34
- }
35
- const result = await llm.ChatCompletion(chatParams);
36
- if (result && result.data) {
37
- const llmResponse = result.data.choices[0].message.content;
38
- if (llmResponse) {
39
- // try to parse it as JSON
40
- try {
41
- const parsed = JSON.parse(llmResponse);
42
- if (parsed.whereClause && parsed.whereClause.length > 0) {
43
- // we have the where clause. Sometimes the LLM prefixes it with WHERE and somtimes not, we need to strip WHERE if it is there
44
- const trimmed = parsed.whereClause.trim();
45
- let ret: string = '';
46
- if (trimmed.toLowerCase().startsWith('where '))
47
- ret = trimmed.substring(6);
48
- else
49
- ret = parsed.whereClause;
50
-
51
- return {
52
- whereClause: ret,
53
- userExplanation: parsed.userExplanationMessage
54
- };
55
- }
56
- else if (parsed.whereClause !== undefined && parsed.whereClause !== null) {
57
- return {
58
- whereClause: '', // empty string is valid, it means no where clause
59
- userExplanation: parsed.userExplanationMessage
60
- };
61
- }
62
- else {
63
- // if we get here, no whereClause property was provided by the LLM, that is an error
64
- throw new Error('Invalid response from AI, no whereClause property found in response: ' + llmResponse);
65
- }
66
- }
67
- catch (e) {
68
- LogError(e);
69
- throw new Error('Error parsing JSON response from AI: ' + llmResponse);
70
- }
71
- }
72
- else
73
- throw new Error('Null response from AI');
74
- }
75
- else
76
- throw new Error('No result returned from AI');
77
- }
78
- catch (e) {
79
- LogError(e);
80
- throw e;
81
- }
82
- }
83
-
84
- public GenerateSysPrompt(entityInfo: EntityInfo): string {
85
- const processedViews: string[] = [entityInfo.BaseView];
86
- const md = new Metadata();
87
- const gptSysPrompt: string = `You are an expert in SQL and Microsoft SQL Server.
88
- You will be provided a user prompt representing how they want to filter the data.
89
- You may *NOT* use JOINS, only sub-queries for related tables.
90
-
91
- I am a bot and can only understand JSON. Your response must be parsable into this type:
92
- const returnType = {
93
- whereClause: string,
94
- orderByClause: string
95
- userExplanationMessage: string
96
- };
97
-
98
- The view that the user is querying is called ${entityInfo.BaseView} and has these fields:
99
- ${entityInfo.Fields.map(f => {
100
- let ret: string = `${f.Name} (${f.Type})`;
101
- if (f.RelatedEntity) {
102
- ret += ` (fkey to ${f.RelatedEntityBaseView})`;
103
- }
104
- return ret;
105
- }).join(',')}`
106
-
107
- const fkeyFields = entityInfo.Fields.filter(f => f.RelatedEntity && f.RelatedEntity.length > 0);
108
- const fkeyBaseViewsDistinct = fkeyFields.map(f => f.RelatedEntityBaseView).filter((v, i, a) => a.indexOf(v) === i);
109
- const relationships: string = `
110
- In addition, ${entityInfo.BaseView} has links to other views, as shown here, you can use these views in sub-queries to achieve the request from the user.
111
- If there are multiple filters related to a single related view, attempt to combine them into a single sub-query for efficiency.
112
- ${
113
- // this part returns a list of all the related views and the fields that are related to the current view via fkeys in the current view
114
- fkeyBaseViewsDistinct.map(v => {
115
- if (processedViews.indexOf(v) === -1) {
116
- const e = md.Entities.find(e => e.BaseView === v);
117
- if (e) {
118
- processedViews.push(v); // already processed this view now, so we won't repeat it
119
- return `* ${e.BaseView}: ${e.Fields.map(ef => {
120
- return ef.Name + ' (' + ef.Type + ')';
121
- }).join(',') }`
122
- }
123
- else
124
- return '';
125
- }
126
- else
127
- return ''; // already did this at some point
128
- }).join('\n')
129
- }
130
- ${
131
- // this part returns a list of all the related views and the fields that are related to the current view fkeys in THOSE views
132
- entityInfo.RelatedEntities.map(r => {
133
- const e = md.Entities.find(e => e.Name === r.RelatedEntity);
134
- if (e) {
135
- if (processedViews.indexOf(e.BaseView) === -1) {
136
- processedViews.push(e.BaseView); // note that we are processing this view now, so we won't repeat it
137
- return `* ${e.BaseView}: ${e.Fields.map(ef => {
138
- let ret: string = `${ef.Name} (${ef.Type})`;
139
- if (ef.RelatedEntity) {
140
- ret += ` (fkey to ${ef.RelatedEntityBaseView})`;
141
- }
142
- return ret;
143
- }).join(',') }`
144
- }
145
- else
146
- return ''; // already did this at some point
147
- }
148
- else
149
- return '';
150
- }).join('\n')
151
- }`
152
-
153
- return gptSysPrompt + (processedViews.length > 1 /*we always have 1 from the entity base view*/ ? relationships : '') + `
154
- **** REMEMBER **** I am a BOT, do not return anything other than JSON to me or I will choke on your response!`;
155
- }
156
- }
1
+ import { MJGlobal, RegisterClass } from "@memberjunction/global";
2
+ import { BaseEntity, EntityInfo, LogError, Metadata } from "@memberjunction/core";
3
+ import { UserViewEntityExtended } from '@memberjunction/core-entities'
4
+ import { BaseLLM, BaseModel, ChatParams, IChat, OpenAILLM } from "@memberjunction/ai";
5
+
6
+ @RegisterClass(BaseEntity, 'User Views', 3) // high priority to ensure this is used ahead of the UserViewEntityExtended in the @memberjunction/core-entities package (which has priority of 2)
7
+ export class UserViewEntity_Server extends UserViewEntityExtended {
8
+ /**
9
+ * This property is hard-coded to true in this class because we DO support smart filters in this class. If you want to disable smart filters for a specific view you can override this property in your subclass and set it to false.
10
+ */
11
+ protected override get SmartFilterImplemented(): boolean {
12
+ return true;
13
+ }
14
+
15
+ /**
16
+ * This method will use AI to return a valid WHERE clause based on the provided prompt. This is automatically called at the right time if the view has SmartFilterEnabled turned on and the SmartFilterPrompt is set. If you want
17
+ * to call this directly to get back a WHERE clause for other purposes you can call this method directly and provide both a prompt and the entity that the view is based on.
18
+ * @param prompt
19
+ */
20
+ public async GenerateSmartFilterWhereClause(prompt: string, entityInfo: EntityInfo): Promise<{whereClause: string, userExplanation: string}> {
21
+ try {
22
+ const llm = <IChat> new OpenAILLM(); // for now, hardcoded to use OpenAI
23
+
24
+ const chatParams: ChatParams = {
25
+ model: 'gpt-4',
26
+ systemPrompt: this.GenerateSysPrompt(entityInfo),
27
+ userMessage: '',
28
+ messages: [
29
+ {
30
+ role: 'user',
31
+ content: `${prompt}`,
32
+ },
33
+ ],
34
+ }
35
+ const result = await llm.ChatCompletion(chatParams);
36
+ if (result && result.data) {
37
+ const llmResponse = result.data.choices[0].message.content;
38
+ if (llmResponse) {
39
+ // try to parse it as JSON
40
+ try {
41
+ const parsed = JSON.parse(llmResponse);
42
+ if (parsed.whereClause && parsed.whereClause.length > 0) {
43
+ // we have the where clause. Sometimes the LLM prefixes it with WHERE and somtimes not, we need to strip WHERE if it is there
44
+ const trimmed = parsed.whereClause.trim();
45
+ let ret: string = '';
46
+ if (trimmed.toLowerCase().startsWith('where '))
47
+ ret = trimmed.substring(6);
48
+ else
49
+ ret = parsed.whereClause;
50
+
51
+ return {
52
+ whereClause: ret,
53
+ userExplanation: parsed.userExplanationMessage
54
+ };
55
+ }
56
+ else if (parsed.whereClause !== undefined && parsed.whereClause !== null) {
57
+ return {
58
+ whereClause: '', // empty string is valid, it means no where clause
59
+ userExplanation: parsed.userExplanationMessage
60
+ };
61
+ }
62
+ else {
63
+ // if we get here, no whereClause property was provided by the LLM, that is an error
64
+ throw new Error('Invalid response from AI, no whereClause property found in response: ' + llmResponse);
65
+ }
66
+ }
67
+ catch (e) {
68
+ LogError(e);
69
+ throw new Error('Error parsing JSON response from AI: ' + llmResponse);
70
+ }
71
+ }
72
+ else
73
+ throw new Error('Null response from AI');
74
+ }
75
+ else
76
+ throw new Error('No result returned from AI');
77
+ }
78
+ catch (e) {
79
+ LogError(e);
80
+ throw e;
81
+ }
82
+ }
83
+
84
+ public GenerateSysPrompt(entityInfo: EntityInfo): string {
85
+ const processedViews: string[] = [entityInfo.BaseView];
86
+ const md = new Metadata();
87
+ const gptSysPrompt: string = `You are an expert in SQL and Microsoft SQL Server.
88
+ You will be provided a user prompt representing how they want to filter the data.
89
+ You may *NOT* use JOINS, only sub-queries for related tables.
90
+
91
+ I am a bot and can only understand JSON. Your response must be parsable into this type:
92
+ const returnType = {
93
+ whereClause: string,
94
+ orderByClause: string
95
+ userExplanationMessage: string
96
+ };
97
+
98
+ The view that the user is querying is called ${entityInfo.BaseView} and has these fields:
99
+ ${entityInfo.Fields.map(f => {
100
+ let ret: string = `${f.Name} (${f.Type})`;
101
+ if (f.RelatedEntity) {
102
+ ret += ` (fkey to ${f.RelatedEntityBaseView})`;
103
+ }
104
+ return ret;
105
+ }).join(',')}`
106
+
107
+ const fkeyFields = entityInfo.Fields.filter(f => f.RelatedEntity && f.RelatedEntity.length > 0);
108
+ const fkeyBaseViewsDistinct = fkeyFields.map(f => f.RelatedEntityBaseView).filter((v, i, a) => a.indexOf(v) === i);
109
+ const relationships: string = `
110
+ In addition, ${entityInfo.BaseView} has links to other views, as shown here, you can use these views in sub-queries to achieve the request from the user.
111
+ If there are multiple filters related to a single related view, attempt to combine them into a single sub-query for efficiency.
112
+ ${
113
+ // this part returns a list of all the related views and the fields that are related to the current view via fkeys in the current view
114
+ fkeyBaseViewsDistinct.map(v => {
115
+ if (processedViews.indexOf(v) === -1) {
116
+ const e = md.Entities.find(e => e.BaseView === v);
117
+ if (e) {
118
+ processedViews.push(v); // already processed this view now, so we won't repeat it
119
+ return `* ${e.BaseView}: ${e.Fields.map(ef => {
120
+ return ef.Name + ' (' + ef.Type + ')';
121
+ }).join(',') }`
122
+ }
123
+ else
124
+ return '';
125
+ }
126
+ else
127
+ return ''; // already did this at some point
128
+ }).join('\n')
129
+ }
130
+ ${
131
+ // this part returns a list of all the related views and the fields that are related to the current view fkeys in THOSE views
132
+ entityInfo.RelatedEntities.map(r => {
133
+ const e = md.Entities.find(e => e.Name === r.RelatedEntity);
134
+ if (e) {
135
+ if (processedViews.indexOf(e.BaseView) === -1) {
136
+ processedViews.push(e.BaseView); // note that we are processing this view now, so we won't repeat it
137
+ return `* ${e.BaseView}: ${e.Fields.map(ef => {
138
+ let ret: string = `${ef.Name} (${ef.Type})`;
139
+ if (ef.RelatedEntity) {
140
+ ret += ` (fkey to ${ef.RelatedEntityBaseView})`;
141
+ }
142
+ return ret;
143
+ }).join(',') }`
144
+ }
145
+ else
146
+ return ''; // already did this at some point
147
+ }
148
+ else
149
+ return '';
150
+ }).join('\n')
151
+ }`
152
+
153
+ return gptSysPrompt + (processedViews.length > 1 /*we always have 1 from the entity base view*/ ? relationships : '') + `
154
+ **** REMEMBER **** I am a BOT, do not return anything other than JSON to me or I will choke on your response!`;
155
+ }
156
+ }
package/src/index.ts CHANGED
@@ -1,111 +1,106 @@
1
- import dotenv from 'dotenv';
2
-
3
- dotenv.config();
4
-
5
- import { expressMiddleware } from '@apollo/server/express4';
6
- import { mergeSchemas } from '@graphql-tools/schema';
7
- import { Metadata } from '@memberjunction/core';
8
- import { setupSQLServerClient, SQLServerProviderConfigData } from '@memberjunction/sqlserver-dataprovider';
9
- import { json } from 'body-parser';
10
- import cors from 'cors';
11
- import express from 'express';
12
- import { globSync } from 'fast-glob';
13
- import { sep } from 'node:path';
14
- import { useServer } from 'graphql-ws/lib/use/ws';
15
- import { createServer } from 'node:http';
16
- import 'reflect-metadata';
17
- import { ReplaySubject } from 'rxjs';
18
- import { BuildSchemaOptions, buildSchemaSync, GraphQLTimestamp } from 'type-graphql';
19
- import { DataSource } from 'typeorm';
20
- import { WebSocketServer } from 'ws';
21
- import buildApolloServer from './apolloServer';
22
- import { configInfo, graphqlPort, graphqlRootPath, mj_core_schema, websiteRunFromPackage } from './config';
23
- import { contextFunction, getUserPayload } from './context';
24
- import { publicDirective } from './directives';
25
- import orm from './orm';
26
-
27
- const cacheRefreshInterval = configInfo.databaseSettings.metadataCacheRefreshInterval;
28
-
29
- export { MaxLength } from 'class-validator';
30
- export * from 'type-graphql';
31
- export { NewUserBase } from './auth/newUsers';
32
- export { configInfo } from './config';
33
- export * from './directives';
34
- export * from './types';
35
- export * from './entitySubclasses/userViewEntity.server'
36
-
37
- export const serve = async (resolverPaths: Array<string>) => {
38
- const replaceBackslashes = sep === '\\';
39
- const paths = resolverPaths.flatMap((path) => globSync(replaceBackslashes ? path.replace(/\\/g, '/') : globSync(path)));
40
- if (paths.length === 0) {
41
- console.warn(`No resolvers found in ${resolverPaths.join(', ')}`);
42
- console.log({ resolverPaths, paths, cwd: process.cwd() });
43
- }
44
-
45
- const dataSource = new DataSource(orm(paths));
46
- const setupComplete$ = new ReplaySubject(1);
47
- dataSource
48
- .initialize()
49
- .then(async () => {
50
- const config = new SQLServerProviderConfigData(dataSource, '', mj_core_schema, cacheRefreshInterval);
51
- await setupSQLServerClient(config); // datasource is already initialized, so we can setup the client right away
52
- const md = new Metadata();
53
- console.log(`Data Source has been initialized. ${md?.Entities ? md.Entities.length : 0} entities loaded.`);
54
-
55
- setupComplete$.next(true);
56
- })
57
- .catch((err) => {
58
- console.error('Error during Data Source initialization', err);
59
- });
60
-
61
- const dynamicModules = await Promise.all(paths.map((modulePath) => import(modulePath.replace(/\.[jt]s$/, ''))));
62
- const resolvers = dynamicModules.flatMap((module) =>
63
- Object.values(module).filter((value) => typeof value === 'function')
64
- ) as BuildSchemaOptions['resolvers'];
65
-
66
- const schema = publicDirective.transformer(
67
- mergeSchemas({
68
- schemas: [
69
- buildSchemaSync({
70
- resolvers,
71
- validate: false,
72
- scalarsMap: [{ type: Date, scalar: GraphQLTimestamp }],
73
- emitSchemaFile: websiteRunFromPackage !== 1,
74
- }),
75
- ],
76
- typeDefs: [publicDirective.typeDefs],
77
- })
78
- );
79
-
80
- const app = express();
81
- const httpServer = createServer(app);
82
-
83
- const webSocketServer = new WebSocketServer({ server: httpServer, path: graphqlRootPath });
84
- const serverCleanup = useServer(
85
- {
86
- schema,
87
- context: async ({ connectionParams }) => {
88
- const userPayload = await getUserPayload(String(connectionParams?.Authorization), undefined, dataSource);
89
- return { userPayload };
90
- },
91
- },
92
- webSocketServer
93
- );
94
-
95
- const apolloServer = buildApolloServer({ schema }, { httpServer, serverCleanup });
96
- await apolloServer.start();
97
-
98
- app.use(
99
- graphqlRootPath,
100
- cors<cors.CorsRequest>(),
101
- json(),
102
- expressMiddleware(apolloServer, {
103
- context: contextFunction({ setupComplete$, dataSource }),
104
- })
105
- );
106
-
107
- await new Promise<void>((resolve) => httpServer.listen({ port: graphqlPort }, resolve));
108
- console.log(`🚀 Server ready at http://localhost:${graphqlPort}/`);
109
- };
110
-
111
- export default serve;
1
+ import dotenv from 'dotenv';
2
+
3
+ dotenv.config();
4
+
5
+ import { expressMiddleware } from '@apollo/server/express4';
6
+ import { mergeSchemas } from '@graphql-tools/schema';
7
+ import { Metadata } from '@memberjunction/core';
8
+ import { setupSQLServerClient, SQLServerProviderConfigData } from '@memberjunction/sqlserver-dataprovider';
9
+ import { json } from 'body-parser';
10
+ import cors from 'cors';
11
+ import express from 'express';
12
+ import { globSync } from 'fast-glob';
13
+ import { useServer } from 'graphql-ws/lib/use/ws';
14
+ import { createServer } from 'node:http';
15
+ import { sep } from 'node:path';
16
+ import 'reflect-metadata';
17
+ import { ReplaySubject } from 'rxjs';
18
+ import { BuildSchemaOptions, buildSchemaSync, GraphQLTimestamp } from 'type-graphql';
19
+ import { DataSource } from 'typeorm';
20
+ import { WebSocketServer } from 'ws';
21
+ import buildApolloServer from './apolloServer';
22
+ import { configInfo, graphqlPort, graphqlRootPath, mj_core_schema, websiteRunFromPackage } from './config';
23
+ import { contextFunction, getUserPayload } from './context';
24
+ import { publicDirective } from './directives';
25
+ import orm from './orm';
26
+
27
+ const cacheRefreshInterval = configInfo.databaseSettings.metadataCacheRefreshInterval;
28
+
29
+ export { MaxLength } from 'class-validator';
30
+ export * from 'type-graphql';
31
+ export { NewUserBase } from './auth/newUsers';
32
+ export { configInfo } from './config';
33
+ export * from './directives';
34
+ export * from './entitySubclasses/userViewEntity.server';
35
+ export * from './types';
36
+
37
+ export const serve = async (resolverPaths: Array<string>) => {
38
+ const replaceBackslashes = sep === '\\';
39
+ const paths = resolverPaths.flatMap((path) => globSync(replaceBackslashes ? path.replace(/\\/g, '/') : path));
40
+ if (paths.length === 0) {
41
+ console.warn(`No resolvers found in ${resolverPaths.join(', ')}`);
42
+ console.log({ resolverPaths, paths, cwd: process.cwd() });
43
+ }
44
+
45
+ const dataSource = new DataSource(orm(paths));
46
+ const setupComplete$ = new ReplaySubject(1);
47
+ await dataSource.initialize();
48
+
49
+ const config = new SQLServerProviderConfigData(dataSource, '', mj_core_schema, cacheRefreshInterval);
50
+ await setupSQLServerClient(config); // datasource is already initialized, so we can setup the client right away
51
+ const md = new Metadata();
52
+ console.log(`Data Source has been initialized. ${md?.Entities ? md.Entities.length : 0} entities loaded.`);
53
+
54
+ setupComplete$.next(true);
55
+
56
+ const dynamicModules = await Promise.all(paths.map((modulePath) => import(modulePath.replace(/\.[jt]s$/, ''))));
57
+ const resolvers = dynamicModules.flatMap((module) =>
58
+ Object.values(module).filter((value) => typeof value === 'function')
59
+ ) as BuildSchemaOptions['resolvers'];
60
+
61
+ const schema = publicDirective.transformer(
62
+ mergeSchemas({
63
+ schemas: [
64
+ buildSchemaSync({
65
+ resolvers,
66
+ validate: false,
67
+ scalarsMap: [{ type: Date, scalar: GraphQLTimestamp }],
68
+ emitSchemaFile: websiteRunFromPackage !== 1,
69
+ }),
70
+ ],
71
+ typeDefs: [publicDirective.typeDefs],
72
+ })
73
+ );
74
+
75
+ const app = express();
76
+ const httpServer = createServer(app);
77
+
78
+ const webSocketServer = new WebSocketServer({ server: httpServer, path: graphqlRootPath });
79
+ const serverCleanup = useServer(
80
+ {
81
+ schema,
82
+ context: async ({ connectionParams }) => {
83
+ const userPayload = await getUserPayload(String(connectionParams?.Authorization), undefined, dataSource);
84
+ return { userPayload };
85
+ },
86
+ },
87
+ webSocketServer
88
+ );
89
+
90
+ const apolloServer = buildApolloServer({ schema }, { httpServer, serverCleanup });
91
+ await apolloServer.start();
92
+
93
+ app.use(
94
+ graphqlRootPath,
95
+ cors<cors.CorsRequest>(),
96
+ json(),
97
+ expressMiddleware(apolloServer, {
98
+ context: contextFunction({ setupComplete$, dataSource }),
99
+ })
100
+ );
101
+
102
+ await new Promise<void>((resolve) => httpServer.listen({ port: graphqlPort }, resolve));
103
+ console.log(`🚀 Server ready at http://localhost:${graphqlPort}/`);
104
+ };
105
+
106
+ export default serve;
package/src/orm.ts CHANGED
@@ -1,36 +1,36 @@
1
- import { DataSourceOptions } from 'typeorm';
2
- import { configInfo, dbDatabase, dbHost, dbPassword, dbPort, dbUsername, dbInstanceName, dbTrustServerCertificate } from './config';
3
-
4
- const orm = (entities: Array<string>): DataSourceOptions => {
5
- const ormConfig = {
6
- type: 'mssql' as const,
7
- entities,
8
- logging: false,
9
- host: dbHost,
10
- port: dbPort,
11
- username: dbUsername,
12
- password: dbPassword,
13
- database: dbDatabase,
14
- synchronize: false,
15
- requestTimeout: configInfo.databaseSettings.requestTimeout,
16
- connectionTimeout: configInfo.databaseSettings.connectionTimeout,
17
- options: {}
18
- };
19
- if (dbInstanceName !== null && dbInstanceName !== undefined && dbInstanceName.trim().length > 0) {
20
- ormConfig.options = {
21
- ...ormConfig.options,
22
- instanceName: dbInstanceName
23
- };
24
- }
25
- if (dbTrustServerCertificate !== null && dbTrustServerCertificate !== undefined) {
26
- ormConfig.options = {
27
- ...ormConfig.options,
28
- trustServerCertificate: dbTrustServerCertificate
29
- };
30
- }
31
-
32
- //console.log({ ormConfig: { ...ormConfig, password: '***' } });
33
- return ormConfig;
34
- };
35
-
36
- export default orm;
1
+ import { DataSourceOptions } from 'typeorm';
2
+ import { configInfo, dbDatabase, dbHost, dbPassword, dbPort, dbUsername, dbInstanceName, dbTrustServerCertificate } from './config';
3
+
4
+ const orm = (entities: Array<string>): DataSourceOptions => {
5
+ const ormConfig = {
6
+ type: 'mssql' as const,
7
+ entities,
8
+ logging: false,
9
+ host: dbHost,
10
+ port: dbPort,
11
+ username: dbUsername,
12
+ password: dbPassword,
13
+ database: dbDatabase,
14
+ synchronize: false,
15
+ requestTimeout: configInfo.databaseSettings.requestTimeout,
16
+ connectionTimeout: configInfo.databaseSettings.connectionTimeout,
17
+ options: {}
18
+ };
19
+ if (dbInstanceName !== null && dbInstanceName !== undefined && dbInstanceName.trim().length > 0) {
20
+ ormConfig.options = {
21
+ ...ormConfig.options,
22
+ instanceName: dbInstanceName
23
+ };
24
+ }
25
+ if (dbTrustServerCertificate !== null && dbTrustServerCertificate !== undefined) {
26
+ ormConfig.options = {
27
+ ...ormConfig.options,
28
+ trustServerCertificate: dbTrustServerCertificate
29
+ };
30
+ }
31
+
32
+ //console.log({ ormConfig: { ...ormConfig, password: '***' } });
33
+ return ormConfig;
34
+ };
35
+
36
+ export default orm;
package/src/types.ts CHANGED
@@ -1,19 +1,19 @@
1
- import { GraphQLSchema } from 'graphql';
2
- import { DataSource, QueryRunner } from 'typeorm';
3
-
4
- export type UserPayload = {
5
- email: string;
6
- userRecord: any;
7
- sessionId: string;
8
- };
9
-
10
- export type AppContext = {
11
- dataSource: DataSource;
12
- userPayload: UserPayload;
13
- queryRunner?: QueryRunner;
14
- };
15
-
16
- export type DirectiveBuilder = {
17
- typeDefs: string;
18
- transformer: (schema: GraphQLSchema) => GraphQLSchema;
19
- };
1
+ import { GraphQLSchema } from 'graphql';
2
+ import { DataSource, QueryRunner } from 'typeorm';
3
+
4
+ export type UserPayload = {
5
+ email: string;
6
+ userRecord: any;
7
+ sessionId: string;
8
+ };
9
+
10
+ export type AppContext = {
11
+ dataSource: DataSource;
12
+ userPayload: UserPayload;
13
+ queryRunner?: QueryRunner;
14
+ };
15
+
16
+ export type DirectiveBuilder = {
17
+ typeDefs: string;
18
+ transformer: (schema: GraphQLSchema) => GraphQLSchema;
19
+ };