Bỏ qua, đến nội dung

@digiforce-nc/data-source-manager

npm@digiforce-nc/data-source-manager
Importimport { DataSourceManager, DataSource, SequelizeDataSource } from '@digiforce-nc/data-source-manager'
RuntimeNode.js

Tổng quan

@digiforce-nc/data-source-manager cho phép hệ thống kết nối đồng thời nhiều database / data source. Mỗi data source có pipeline riêng biệt gồm:

  • CollectionManager - quản lý schema (collection/field)
  • ResourceManager - xử lý HTTP action routing
  • ACL - kiểm soát quyền truy cập

Request được route tới đúng data source thông qua header x-data-source:


Class hierarchy


DataSourceManager API

Core methods

MethodMô tả
add(dataSource, options?)Thêm data source. Chạy beforeAddHooks, load data source, emit afterAddDataSource.
get(name)Lấy DataSource instance theo tên.
getList()Lấy tất cả data source đã đăng ký.

Middleware

MethodMô tả
use(middleware, options?)Đăng ký middleware cấp manager - chạy cho tất cả data source.
middleware()Trả về Koa middleware. Middleware này đọc header x-data-source để route request tới đúng data source pipeline.

Lifecycle

Auto-cleanup

Constructor DataSourceManager bind app.on('beforeStop', ...) để đóng tất cả data source khi app stop. Không cần cleanup thủ công.

Ví dụ sử dụng

typescript
const dsm = app.dataSourceManager;

// Thêm data source từ external database
dsm.add(new SequelizeDataSource({
  name: 'crm-db',
  database: {
    dialect: 'mysql',
    host: 'crm-server',
    port: 3306,
    database: 'crm',
    username: 'reader',
    password: 'secret',
  },
}));

// Lấy data source
const crmDS = dsm.get('crm-db');
const contacts = await crmDS.collectionManager
  .getCollection('contacts')
  .repository
  .find({ filter: { status: 'active' } });

DataSource API

DataSource là abstract class - mọi data source cụ thể đều kế thừa nó.

Lifecycle methods

MethodMô tả
init(options?)Khởi tạo ACL, ResourceManager, CollectionManager. Đăng ký default action handlers.
load(options?)Load collections, sync schema nếu cần.
createCollectionManager()Factory method - tạo CollectionManager instance. Override trong subclass.
createResourceManager()Factory method - tạo ResourceManager instance.

Properties

PropertyKiểuMô tả
namestringTên unique của data source
collectionManagerCollectionManagerQuản lý collection schema
resourceManagerResourceManagerQuản lý resource routing
aclACLAccess control cho data source này

Init flow chi tiết


SequelizeDataSource

Concrete implementation dùng Sequelize/Database làm backend.

FeatureMô tả
databaseInstance Database - full ORM access
SequelizeCollectionManagerCollectionManager wrapper trên Database, hỗ trợ Sequelize-specific features
Auto-syncCó thể tự đồng bộ schema khi load

collectionToResourceMiddleware

Middleware tự động tạo Resource cho mỗi Collection trong data source. Khi CollectionManager define một collection, middleware này đảm bảo có resource tương ứng trong ResourceManager.

Điều này có nghĩa: khi bạn define collection, hệ thống tự động tạo REST API tương ứng mà không cần viết route thủ công.

typescript
// Chỉ cần define collection
db.collection({
  name: 'products',
  fields: [
    { type: 'string', name: 'name' },
    { type: 'decimal', name: 'price' },
  ],
});

// Tự động có các endpoint:
// GET    /api/products:list
// GET    /api/products:get?filterByTk=1
// POST   /api/products:create
// POST   /api/products:update?filterByTk=1
// POST   /api/products:destroy?filterByTk=1

loadDefaultActions

Hàm loadDefaultActions() đăng ký bộ action handler CRUD chuẩn cho mỗi data source:

ActionHandlerMô tả
listactions.listTìm nhiều records với filter, sort, pagination
getactions.getLấy một record theo primary key
createactions.createTạo record mới
updateactions.updateCập nhật record
destroyactions.destroyXóa record
addactions.addThêm association (BelongsToMany)
removeactions.removeGỡ association
setactions.setSet association (HasOne, BelongsTo)
toggleactions.toggleToggle association
moveactions.moveThay đổi sort order
firstOrCreateactions.firstOrCreateTìm hoặc tạo
updateOrCreateactions.updateOrCreateTìm cập nhật hoặc tạo

DatabaseIntrospector

DatabaseIntrospector (trong DatabaseDataSource) cho phép đọc schema từ database thực tế - hữu ích khi kết nối tới database đã có sẵn data.

MethodMô tả
readTables()Đọc danh sách tables từ DB schema thực tế
loadTables()Tạo Collection cho mỗi table đọc được
syncFieldsFromDatabase()Đồng bộ field definition từ schema thực tế
mergeWithLoadedCollections()Gộp collections từ introspection với collections đã define

Use case

Khi kết nối tới CRM database có sẵn, dùng introspector để tự động tạo collections từ existing tables mà không cần define từng collection thủ công.


x-data-source header routing

Khi client cần truy cập data source khác (không phải main), thêm header x-data-source:

typescript
// Client request tới external data source
const response = await apiClient.request({
  url: '/api/contacts:list',
  headers: {
    'x-data-source': 'external-crm',
  },
});

Routing flow

Bảo mật

Mỗi data source có ACL riêng. Khi route tới external data source, ACL của data source đó quyết định quyền truy cập, không phải ACL của main data source.


Ví dụ tổng hợp

Đăng ký multiple data sources

typescript
import { Application } from '@digiforce-nc/server';
import { SequelizeDataSource } from '@digiforce-nc/data-source-manager';

const app = new Application({
  database: {
    dialect: 'postgres',
    host: 'localhost',
    database: 'main_app',
    username: 'admin',
    password: 'secret',
  },
});

// Main data source được tạo tự động

// Thêm external CRM database
app.dataSourceManager.add(new SequelizeDataSource({
  name: 'crm',
  database: {
    dialect: 'mysql',
    host: 'crm-host',
    database: 'crm_db',
    username: 'reader',
    password: 'crm-pass',
  },
  collections: [
    {
      name: 'contacts',
      fields: [
        { type: 'string', name: 'firstName' },
        { type: 'string', name: 'lastName' },
        { type: 'string', name: 'email' },
        { type: 'string', name: 'phone' },
      ],
    },
  ],
}));

// Thêm analytics database (read-only)
app.dataSourceManager.add(new SequelizeDataSource({
  name: 'analytics',
  database: {
    dialect: 'postgres',
    host: 'analytics-host',
    database: 'analytics_db',
    username: 'readonly',
    password: 'analytics-pass',
  },
  acl: false, // Không dùng ACL cho analytics
}));

Truy cập data source trong plugin

typescript
class MyCRMPlugin extends Plugin {
  async load() {
    // Đăng ký custom action trên external data source
    const crmDS = this.app.dataSourceManager.get('crm');
    crmDS.resourceManager.registerActionHandler('contacts:import', async (ctx, next) => {
      // import logic
      await next();
    });

    // Middleware cho tất cả data sources
    this.app.dataSourceManager.use(async (ctx, next) => {
      console.log(`Data source: ${ctx.dataSource.name}`);
      await next();
    });
  }
}

Dependencies

PackageVai trò
@digiforce-nc/databaseDatabase/Sequelize cho SequelizeDataSource
@digiforce-nc/resourcerResourceManager per data source
@digiforce-nc/aclACL per data source
@digiforce-nc/actionsDefault CRUD action handlers

Xem thêm