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 ​