2.48.0 • Published 4 months ago

@memberjunction/graphql-dataprovider v2.48.0

Weekly downloads
-
License
ISC
Repository
-
Last release
4 months ago

MemberJunction GraphQL Data Provider

A comprehensive GraphQL client for MemberJunction that provides a complete data access layer for connecting applications to MemberJunction APIs.

Overview

The @memberjunction/graphql-dataprovider package is a full-featured GraphQL client implementation for MemberJunction applications. It provides a standardized way to interact with MemberJunction's GraphQL API, handling queries, mutations, subscriptions, and complex operations like transaction groups and entity relationships.

This data provider is designed for both frontend and backend applications that need to communicate with a MemberJunction API server, offering a consistent interface regardless of the underlying database technology.

Installation

npm install @memberjunction/graphql-dataprovider

Key Features

  • Complete Entity Operations: CRUD operations for all MemberJunction entities
  • View and Report Execution: Run database views and reports with parameters
  • Query Execution: Execute custom queries with full parameter support
  • Transaction Support: Execute complex operations as atomic transactions
  • Action Execution: Execute entity actions and general actions through GraphQL
  • WebSocket Subscriptions: Real-time data updates via GraphQL subscriptions
  • Offline Caching: IndexedDB-based caching for offline functionality
  • Type Safety: Full TypeScript support with generated types
  • Authentication Integration: Works with MemberJunction's authentication system
  • Field Mapping: Automatic mapping between client and server field names
  • Session Management: Persistent session IDs with automatic storage
  • System User Client: Specialized client for server-to-server communication
  • Duplicate Detection: Built-in support for finding and merging duplicate records

Usage

Setting up the GraphQL Client

import { setupGraphQLClient, GraphQLProviderConfigData } from '@memberjunction/graphql-dataprovider';

// Create configuration
const config = new GraphQLProviderConfigData(
  'your-jwt-token',
  'https://api.example.com/graphql',
  'wss://api.example.com/graphql',
  async () => {
    // Refresh token function - called when JWT expires
    const newToken = await refreshAuthToken();
    return newToken;
  },
  '__mj', // Optional: MJ Core schema name (defaults to '__mj')
  ['schema1', 'schema2'], // Optional: Include only these schemas
  ['excluded_schema'], // Optional: Exclude these schemas
  'mj-api-key' // Optional: For server-to-server communication
);

// Setup the client (returns configured instance)
const dataProvider = await setupGraphQLClient(config);

// Or create and configure manually
const dataProvider = new GraphQLDataProvider();
await dataProvider.Config(config);

Working with Entities

import { GraphQLDataProvider } from '@memberjunction/graphql-dataprovider';

const dataProvider = new GraphQLDataProvider({
  graphQLEndpoint: 'https://api.example.com/graphql',
});

// Load an entity
async function getUserById(userId: number) {
  const result = await dataProvider.loadEntity('User', userId);
  return result.success ? result.entity : null;
}

// Create a new entity
async function createUser(userData: any) {
  const entityData = {
    ID: 0, // 0 indicates a new entity
    FirstName: userData.firstName,
    LastName: userData.lastName,
    Email: userData.email,
    // other fields...
  };
  
  const options = {
    IgnoreDirtyFields: false, // Save all fields
    SkipValidation: false // Run validation before save
  };
  
  const result = await dataProvider.SaveEntity(
    entityData,
    'User',
    options
  );
  return result;
}

// Update an existing entity
async function updateUser(userId: number, updatedData: any) {
  // Load the entity
  const entity = await dataProvider.GetEntityObject(
    'User',
    { ID: userId }
  );
  
  if (entity) {
    // Update fields
    Object.assign(entity.GetData(), updatedData);
    
    // Save changes
    const result = await dataProvider.SaveEntity(
      entity.GetData(),
      'User'
    );
    return result;
  }
  
  return { Success: false, Message: 'User not found' };
}

// Delete an entity
async function deleteUser(userId: number) {
  const options = {
    IgnoreWarnings: false // Show warnings if any
  };
  
  const result = await dataProvider.DeleteEntity(
    'User',
    { ID: userId },
    options
  );
  return result;
}

Executing Views and Reports

import { GraphQLDataProvider } from '@memberjunction/graphql-dataprovider';
import { RunViewParams } from '@memberjunction/core';

const dataProvider = new GraphQLDataProvider();

// Execute a view
async function getActiveUsers() {
  const params: RunViewParams = {
    EntityName: 'Users',
    ExtraFilter: "Status = 'Active'",
    OrderBy: 'LastName, FirstName',
    Fields: ['ID', 'FirstName', 'LastName', 'Email'], // Optional: specific fields
    IgnoreMaxRows: false,
    MaxRows: 50,
    ResultType: 'entity_object', // or 'simple' for raw data
    ForceAuditLog: true,
    AuditLogDescription: 'Loading active users for report'
  };
  
  const result = await dataProvider.RunView(params);
  return result.Success ? result.Results : [];
}

// Execute multiple views in parallel
async function getMultipleDatasets() {
  const viewParams: RunViewParams[] = [
    { EntityName: 'Users', ExtraFilter: "Status = 'Active'" },
    { EntityName: 'Orders', ExtraFilter: "OrderDate >= '2024-01-01'" }
  ];
  
  const results = await dataProvider.RunViews(viewParams);
  return results;
}

// Execute a report
async function getSalesReport(reportId: string) {
  const params = {
    ReportID: reportId
  };
  
  const result = await dataProvider.RunReport(params);
  return result.Success ? result.Results : [];
}

// Execute a query
async function runCustomQuery(queryId: string, parameters: any) {
  const params = {
    QueryID: queryId,
    Parameters: parameters
  };
  
  const result = await dataProvider.RunQuery(params);
  return result;
}

Using Transaction Groups

import { GraphQLDataProvider } from '@memberjunction/graphql-dataprovider';
import { TransactionGroupBase } from '@memberjunction/core';

const dataProvider = new GraphQLDataProvider({
  graphQLEndpoint: 'https://api.example.com/graphql',
});

// Define a transaction group
class OrderTransactionGroup extends TransactionGroupBase {
  constructor() {
    super('CreateOrderWithItems');
  }
}

// Use the transaction group
async function createOrderWithItems(orderData: any, items: any[]) {
  // Create transaction group
  const transaction = await dataProvider.CreateTransactionGroup();
  
  // Create order entity
  const orderEntity = await dataProvider.GetEntityObject('Order');
  orderEntity.NewRecord();
  orderEntity.Set('CustomerID', orderData.customerId);
  orderEntity.Set('OrderDate', new Date());
  orderEntity.Set('Status', 'New');
  
  // Add to transaction
  const orderItem = transaction.AddTransaction(orderEntity, 'create');
  
  // Add order items with references
  for (const item of items) {
    const itemEntity = await dataProvider.GetEntityObject('OrderItem');
    itemEntity.NewRecord();
    itemEntity.Set('ProductID', item.productId);
    itemEntity.Set('Quantity', item.quantity);
    itemEntity.Set('Price', item.price);
    
    // Reference the order using a variable
    const orderTransaction = transaction.AddTransaction(itemEntity, 'create');
    transaction.AddVariable(
      'orderID',
      'ID',
      'FieldValue',
      orderItem.BaseEntity,
      orderTransaction.BaseEntity,
      'OrderID'
    );
  }
  
  // Execute transaction
  const results = await transaction.Submit();
  return results;
}

Executing Actions

import { GraphQLActionClient } from '@memberjunction/graphql-dataprovider';
import { ActionParam } from '@memberjunction/actions-base';

const actionClient = new GraphQLActionClient(dataProvider);

// Execute a standalone action
async function runAction(actionId: string) {
  const params: ActionParam[] = [
    { Name: 'parameter1', Value: 'value1', Type: 'Input' },
    { Name: 'parameter2', Value: 123, Type: 'Input' }
  ];
  
  const result = await actionClient.RunAction(
    actionId,
    params,
    false // skipActionLog
  );
  
  if (result.Success) {
    console.log('Action result:', result.ResultCode);
  }
  return result;
}

// Execute an entity action
async function runEntityAction() {
  const params = {
    EntityAction: entityAction, // EntityActionEntity instance
    InvocationType: { Name: 'SingleRecord' },
    EntityObject: userEntity, // BaseEntity instance
    ContextUser: currentUser // UserInfo instance
  };
  
  const result = await actionClient.RunEntityAction(params);
  return result;
}

Field Mapping

import { FieldMapper } from '@memberjunction/graphql-dataprovider';

// The GraphQL provider automatically handles field mapping for system fields
// __mj_CreatedAt <-> _mj__CreatedAt
// __mj_UpdatedAt <-> _mj__UpdatedAt  
// __mj_DeletedAt <-> _mj__DeletedAt

// You can also use the FieldMapper directly
const mapper = new FieldMapper();

// Map fields in an object
const mappedData = mapper.MapFields({
  __mj_CreatedAt: '2024-01-01',
  Name: 'John Doe'
});
// Result: { _mj__CreatedAt: '2024-01-01', Name: 'John Doe' }

// Map individual field names
const mappedField = mapper.MapFieldName('__mj_CreatedAt');
// Result: '_mj__CreatedAt'

// Reverse mapping
const originalField = mapper.ReverseMapFieldName('_mj__CreatedAt');
// Result: '__mj_CreatedAt'

WebSocket Subscriptions

import { GraphQLDataProvider } from '@memberjunction/graphql-dataprovider';
import { Observable } from 'rxjs';

const dataProvider = new GraphQLDataProvider();

// Subscribe to record changes
function subscribeToRecordChanges() {
  const observable: Observable<RecordChange[]> = 
    await dataProvider.GetRecordChanges(
      'User',
      { ID: 123 },
      ['update', 'delete'], // Watch for these operations
      true // Return initial values
    );
  
  const subscription = observable.subscribe(changes => {
    console.log('Record changes:', changes);
    // Handle changes
  });
  
  // Later, unsubscribe
  subscription.unsubscribe();
}

System User Client

import { GraphQLSystemUserClient } from '@memberjunction/graphql-dataprovider';

// Create system user client for server-to-server communication
const systemClient = new GraphQLSystemUserClient(
  'https://api.example.com/graphql',
  '', // No JWT token needed
  'session-id',
  'mj-api-key' // Shared secret key
);

// Execute queries as system user
const queries = [
  'SELECT * FROM Users WHERE Active = 1',
  'SELECT COUNT(*) as Total FROM Orders'
];

const result = await systemClient.GetData(
  queries,
  'access-token' // Short-lived access token
);

if (result.Success) {
  console.log('Query results:', result.Results);
}

// Sync roles and users
const syncResult = await systemClient.SyncRolesAndUsers({
  Roles: [
    { ID: '1', Name: 'Admin', Description: 'Administrator role' }
  ],
  Users: [
    { 
      ID: '1',
      Name: 'john.doe',
      Email: 'john@example.com',
      Type: 'User',
      FirstName: 'John',
      LastName: 'Doe',
      Roles: [{ ID: '1', Name: 'Admin', Description: 'Administrator role' }]
    }
  ]
});

Key Classes and Types

Class/TypeDescription
GraphQLDataProviderMain class implementing IEntityDataProvider, IMetadataProvider, IRunViewProvider, IRunReportProvider, and IRunQueryProvider interfaces
GraphQLProviderConfigDataConfiguration class for setting up the GraphQL provider with authentication and connection details
GraphQLActionClientClient for executing actions and entity actions through GraphQL
GraphQLSystemUserClientSpecialized client for server-to-server communication using API keys
GraphQLTransactionGroupManages complex multi-entity transactions with variable support
FieldMapperHandles automatic field name mapping between client and server
setupGraphQLClientHelper function to quickly setup and configure the GraphQL client

API Documentation

Core Methods

Entity Operations

  • GetEntityObject(entityName: string, compositeKey?: CompositeKey) - Get an entity object instance
  • SaveEntity(entityData: any, entityName: string, options?: EntitySaveOptions) - Save entity data
  • DeleteEntity(entityName: string, compositeKey: CompositeKey, options?: EntityDeleteOptions) - Delete an entity
  • GetRecordChanges(entityName: string, compositeKey: CompositeKey, operations: string[], includeInitial: boolean) - Subscribe to entity changes

View and Query Operations

  • RunView(params: RunViewParams) - Execute a single view
  • RunViews(params: RunViewParams[]) - Execute multiple views in parallel
  • RunReport(params: RunReportParams) - Execute a report
  • RunQuery(params: RunQueryParams) - Execute a custom query

Transaction Operations

  • CreateTransactionGroup() - Create a new transaction group
  • ExecuteTransaction(transaction: TransactionGroupBase) - Execute a transaction group

Duplicate Detection

  • GetRecordDuplicates(request: PotentialDuplicateRequest) - Find potential duplicate records
  • MergeRecords(request: RecordMergeRequest) - Merge duplicate records

Metadata Operations

  • GetEntityRecordName(entityName: string, compositeKey: CompositeKey) - Get display name for a record
  • GetEntityRecordNames(info: EntityRecordNameInput[]) - Get display names for multiple records
  • GetEntityDependencies(entityName: string, compositeKey: CompositeKey) - Get record dependencies

Dependencies

  • @memberjunction/core - Core MemberJunction functionality
  • @memberjunction/core-entities - Entity definitions
  • @memberjunction/actions-base - Action system base classes
  • @memberjunction/global - Global utilities
  • graphql - GraphQL language and execution
  • graphql-request - Minimal GraphQL client
  • graphql-ws - GraphQL WebSocket client for subscriptions
  • @tempfix/idb - IndexedDB wrapper for offline storage
  • rxjs - Reactive extensions for subscriptions
  • uuid - UUID generation for session IDs

Requirements

  • Node.js 16+
  • Modern browser with WebSocket support (for subscriptions)
  • MemberJunction GraphQL API endpoint
  • Valid JWT token or MJ API key for authentication

License

ISC

2.23.2

8 months ago

2.46.0

5 months ago

2.23.1

8 months ago

2.34.0

6 months ago

2.19.4

9 months ago

2.19.5

9 months ago

2.19.2

9 months ago

2.19.3

9 months ago

2.19.0

9 months ago

2.19.1

9 months ago

2.34.2

6 months ago

2.34.1

6 months ago

2.45.0

5 months ago

2.22.1

9 months ago

2.22.0

9 months ago

2.22.2

9 months ago

2.33.0

6 months ago

2.18.3

9 months ago

2.18.1

9 months ago

2.18.2

9 months ago

2.18.0

9 months ago

2.21.0

9 months ago

2.44.0

5 months ago

2.29.0

8 months ago

2.29.2

8 months ago

2.29.1

8 months ago

2.32.0

7 months ago

2.32.2

7 months ago

2.32.1

7 months ago

2.17.0

9 months ago

2.43.0

5 months ago

2.20.2

9 months ago

2.20.3

9 months ago

2.20.0

9 months ago

2.20.1

9 months ago

2.28.0

8 months ago

2.31.0

7 months ago

2.39.0

5 months ago

2.16.1

9 months ago

2.16.0

9 months ago

2.42.1

5 months ago

2.42.0

5 months ago

2.27.1

8 months ago

2.27.0

8 months ago

2.30.0

7 months ago

2.15.2

9 months ago

2.15.0

9 months ago

2.15.1

9 months ago

2.38.0

5 months ago

2.41.0

5 months ago

2.26.1

8 months ago

2.26.0

8 months ago

2.37.1

6 months ago

2.37.0

6 months ago

2.14.0

10 months ago

2.40.0

5 months ago

2.25.0

8 months ago

2.48.0

4 months ago

2.13.4

10 months ago

2.36.0

6 months ago

2.13.2

11 months ago

2.13.3

10 months ago

2.13.0

11 months ago

2.36.1

6 months ago

2.13.1

11 months ago

2.47.0

4 months ago

2.24.1

8 months ago

2.24.0

8 months ago

2.12.0

12 months ago

2.35.1

6 months ago

2.35.0

6 months ago

2.23.0

8 months ago

2.11.0

12 months ago

2.10.0

12 months ago

2.9.0

12 months ago

2.8.0

1 year ago

2.7.0

1 year ago

2.7.1

1 year ago

2.6.1

1 year ago

2.6.0

1 year ago

2.5.2

1 year ago

1.6.1

1 year ago

1.6.0

1 year ago

2.4.1

1 year ago

2.4.0

1 year ago

1.5.3

1 year ago

1.5.2

1 year ago

1.5.1

1 year ago

1.5.0

1 year ago

2.3.0

1 year ago

2.3.2

1 year ago

2.3.1

1 year ago

2.3.3

1 year ago

1.4.1

1 year ago

1.4.0

1 year ago

2.2.1

1 year ago

2.2.0

1 year ago

1.3.3

1 year ago

1.3.2

1 year ago

1.3.1

1 year ago

1.3.0

1 year ago

2.1.2

1 year ago

2.1.1

1 year ago

2.1.4

1 year ago

2.1.3

1 year ago

2.1.5

1 year ago

2.1.0

1 year ago

2.0.0

1 year ago

1.8.1

1 year ago

1.8.0

1 year ago

1.7.1

1 year ago

1.7.0

1 year ago

2.5.0

1 year ago

2.5.1

1 year ago

1.2.2

1 year ago

1.2.1

1 year ago

1.2.0

1 year ago

1.1.1

1 year ago

1.1.0

1 year ago

1.1.3

1 year ago

1.1.2

1 year ago

1.0.11

1 year ago

1.0.9

2 years ago

1.0.7-next.0

2 years ago

1.0.8

2 years ago

1.0.7

2 years ago

1.0.8-next.6

2 years ago

1.0.8-next.5

2 years ago

1.0.8-next.4

2 years ago

1.0.8-next.3

2 years ago

1.0.8-next.2

2 years ago

1.0.8-next.1

2 years ago

1.0.8-next.0

2 years ago

1.0.8-beta.0

2 years ago

1.0.6

2 years ago

1.0.4

2 years ago

1.0.3

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago

0.9.206

2 years ago

0.9.205

2 years ago

0.9.202

2 years ago

0.9.204

2 years ago

0.9.200

2 years ago

0.9.201

2 years ago

0.9.199

2 years ago

0.9.198

2 years ago

0.9.197

2 years ago

0.9.196

2 years ago

0.9.195

2 years ago

0.9.194

2 years ago

0.9.193

2 years ago

0.9.192

2 years ago

0.9.191

2 years ago

0.9.189

2 years ago

0.9.187

2 years ago

0.9.188

2 years ago

0.9.186

2 years ago

0.9.185

2 years ago

0.9.184

2 years ago

0.9.182

2 years ago

0.9.181

2 years ago

0.9.183

2 years ago

0.9.179

2 years ago

0.9.178

2 years ago

0.9.177

2 years ago

0.9.175

2 years ago

0.9.174

2 years ago

0.9.173

2 years ago

0.9.172

2 years ago

0.9.171

2 years ago

0.9.170

2 years ago

0.9.169

2 years ago

0.9.168

2 years ago

0.9.167

2 years ago

0.9.165

2 years ago

0.9.164

2 years ago

0.9.166

2 years ago

0.9.160

2 years ago

0.9.163

2 years ago

0.9.162

2 years ago

0.9.159

2 years ago

0.9.158

2 years ago

0.9.157

2 years ago

0.9.154

2 years ago

0.9.153

2 years ago

0.9.156

2 years ago

0.9.155

2 years ago

0.9.152

2 years ago

0.9.151

2 years ago

0.9.150

2 years ago

0.9.149

2 years ago

0.9.148

2 years ago

0.9.147

2 years ago

0.9.146

2 years ago

0.9.145

2 years ago

0.9.144

2 years ago

0.9.143

2 years ago

0.9.142

2 years ago

0.9.135

2 years ago

0.9.128

2 years ago

0.9.125

2 years ago

0.9.124

2 years ago

0.9.127

2 years ago

0.9.110

2 years ago

0.9.112

2 years ago

0.9.111

2 years ago

0.9.114

2 years ago

0.9.113

2 years ago

0.9.115

2 years ago

0.9.101

2 years ago

0.9.100

2 years ago

0.9.96

2 years ago

0.9.97

2 years ago

0.9.98

2 years ago

0.9.99

2 years ago

0.9.107

2 years ago

0.9.106

2 years ago

0.9.109

2 years ago

0.9.94

2 years ago

0.9.108

2 years ago

0.9.95

2 years ago

0.9.103

2 years ago

0.9.102

2 years ago

0.9.105

2 years ago

0.9.104

2 years ago

0.9.90

2 years ago

0.9.91

2 years ago

0.9.89

2 years ago

0.9.86

2 years ago

0.9.87

2 years ago

0.9.88

2 years ago

0.9.85

2 years ago

0.9.81

2 years ago

0.9.82

2 years ago

0.9.83

2 years ago

0.9.84

2 years ago

0.9.80

2 years ago

0.9.78

2 years ago

0.9.79

2 years ago

0.9.77

2 years ago

0.9.75

2 years ago

0.9.76

2 years ago

0.9.74

2 years ago

0.9.70

2 years ago

0.9.71

2 years ago

0.9.72

2 years ago

0.9.73

2 years ago

0.9.69

2 years ago

0.9.68

2 years ago

0.9.67

2 years ago

0.9.66

2 years ago

0.9.64

2 years ago

0.9.65

2 years ago

0.9.63

2 years ago

0.9.62

2 years ago

0.9.61

2 years ago

0.9.60

2 years ago

0.9.59

2 years ago

0.9.58

2 years ago

0.9.57

2 years ago

0.9.56

2 years ago

0.9.55

2 years ago

0.9.54

2 years ago

0.9.53

2 years ago

0.9.52

2 years ago

0.9.51

2 years ago

0.9.50

2 years ago

0.9.49

2 years ago

0.9.48

2 years ago

0.9.47

2 years ago

0.9.46

2 years ago

0.9.45

2 years ago

0.9.44

2 years ago

0.9.43

2 years ago

0.9.41

2 years ago

0.9.40

2 years ago

0.9.39

2 years ago

0.9.38

2 years ago

0.9.37

2 years ago

0.9.36

2 years ago

0.9.35

2 years ago

0.9.34

2 years ago

0.9.33

2 years ago

0.9.32

2 years ago

0.9.31

2 years ago

0.9.30

2 years ago

0.9.29

2 years ago

0.9.28

2 years ago

0.9.27

2 years ago

0.9.26

2 years ago

0.9.25

2 years ago

0.9.24

2 years ago

0.9.23

2 years ago

0.9.22

2 years ago

0.9.21

2 years ago

0.9.20

2 years ago

0.9.19

2 years ago

0.9.18

2 years ago

0.9.17

2 years ago

0.9.16

2 years ago

0.9.15

2 years ago

0.9.14

2 years ago

0.9.13

2 years ago

0.9.12

2 years ago

0.9.11

2 years ago

0.9.10

2 years ago

0.9.9

2 years ago

0.9.8

2 years ago

0.9.7

2 years ago

0.9.6

2 years ago

0.9.5

2 years ago

0.9.4

2 years ago

0.9.3

2 years ago

0.9.2

2 years ago

0.9.1

2 years ago

0.9.0

2 years ago