Skip to content

Build Apps

VinceZK edited this page Feb 21, 2021 · 4 revisions

With JOR, you can avoid write piles of server-side codes to handle tremendous data requests. As an example, to build a typical CRUD App like User Maintenance, you only need to implement 4 service calls in the client side. You don't need to touch any server-side codes to create the corresponding endpoints. JOR has already enabled generic endpoints like, search, query, save, and delete. You only need to compose different JSON messages and send them to the existing endpoints. It will save you a lot of the development effort and improve your efficiency.

/**
 * Search Users by USER_ID and USER_NAME. 
 * Return a list with columns USER_ID, USER_NAME, DISPLAY_NAME, LOCK, and PWD_STATE
 * Wildcard search is supported using '*' or '%'.
**/
searchUsers(userID: string, userName: string): Observable<UserList[] | Message[]> {
    const queryObject = new QueryObject();
    queryObject.ENTITY_ID = 'person';
    queryObject.RELATION_ID = 'r_user';
    queryObject.PROJECTION = ['USER_ID', 'USER_NAME', 'DISPLAY_NAME', 'LOCK', 'PWD_STATE'];
    queryObject.FILTER = [];
    if (userID) {
      if (userID.includes('*') || userID.includes('%')) {
        queryObject.FILTER.push({FIELD_NAME: 'USER_ID', OPERATOR: 'CN', LOW: userID});
      } else {
        queryObject.FILTER.push({FIELD_NAME: 'USER_ID', OPERATOR: 'EQ', LOW: userID});
      }
    }
    if (userName) {
      if (userName.includes('*')) {
        userName = userName.replace(/\*/gi, '%');
        queryObject.FILTER.push({FIELD_NAME: 'USER_NAME', OPERATOR: 'CN', LOW: userName});
      } else {
        queryObject.FILTER.push({FIELD_NAME: 'USER_NAME', OPERATOR: 'EQ', LOW: userName});
      }
    }
    queryObject.SORT = ['USER_ID'];
    return this.http.post<any>(this.originalHost + `/api/query`, queryObject, httpOptions).pipe(
      catchError(this.handleError<any>('searchObjects')));
}

/**
 * Get detail information of a user from USER_ID
 * Return information in Relations: r_user, r_employee, r_email, r_address, and r_personalization.
 * The relationship to user role is also inquired with information in Relation: r_role
**/
getUserDetail(userID: string): Observable<Entity | Message[]> {
    const pieceObject = {
      ID: { RELATION_ID: 'r_user', USER_ID: userID},
      piece: {RELATIONS: ['r_user', 'r_employee', 'r_email', 'r_address', 'r_personalization'],
              RELATIONSHIPS: [
                {
                  RELATIONSHIP_ID: 'rs_user_role',
                  PARTNER_ENTITY_PIECES: { RELATIONS: ['r_role'] }
                }]
      }
    };
    return this.http.post<Entity | Message[]>(
      this.originalHost + `/api/entity/instance/piece`, pieceObject, httpOptions).pipe(
      catchError(this.handleError<any>('getUserDetail')));
}

/**
 * Get user by User ID, only return information in Relations: r_user
 * This service call is mainly used to check whether the given USER_ID already exists
**/
getUserByUserID(userID: string): Observable<Entity | Message[]> {
    const pieceObject = {
      ID: { RELATION_ID: 'r_user', USER_ID: userID},
      piece: {RELATIONS: ['r_user']}
    };
    return this.http.post<Entity | Message[]>(
      this.originalHost + `/api/entity/instance/piece`, pieceObject, httpOptions).pipe(
      catchError(this.handleError<any>('getUserByUserID')));
}

/**
 * Save an entity to DB
 * A generic entity in JSON is given. If the JSON has attribute INSTANCE_GUID, it calls PUT, otherwise, POST
**/
save(entity: Entity): Observable<Entity | Message[]> {
    if (entity['INSTANCE_GUID']) {
      return this.http.put<Entity | Message[]>(
        this.originalHost + `/api/entity`, entity, httpOptions).pipe(
        catchError(this.handleError<any>('saveUser')));
    } else {
      return this.http.post<Entity | Message[]>(
        this.originalHost + `/api/entity`, entity, httpOptions).pipe(
        catchError(this.handleError<any>('save')));
    }
}

/**
 * Delete an entity from DB
 * A GUID of entity instance is given. After the call, the instance will be deleted permanently
**/
delete(instanceGUID: string): Observable<null | Message[]> {
    return this.http.delete<null | Message[]>(this.originalHost + `/api/entity/instance/` + instanceGUID, httpOptions).pipe(
      catchError(this.handleError<any>('delete'))
    );
}

With Angular

If you are using Angular to build your UI, then JOR provides much more benefits. Install the package 'JOR-Angular' (npm install jor-angular --save) to your Angular project, and you can use following services:

  1. Attribute UI Controls: Angular UI components that can be directly used to compose an object page;
  2. Search Help: A button close to an input field which pops up a dialog to allow user to search possible values and input it to the field;
  3. UI Mapper: Utility methods used to convert Angular AbstractControl to JOR JSON format;
  4. Entity Services: Generic services allow manipulations on entity instances and metas;
  5. Reusable Types: Reusable data types in JOR;

Read the https://github.com/VinceZK/json-on-relations/blob/master/projects/jor-angular/README.md for detail.