@qingu-x/msgraph-orm-js
v0.1.26
Published
Microsoft Graph JavaScript SDK for Qingu-X
Maintainers
Readme
@qingu-x/msgraph-orm-js
Microsoft Graph 的 ORM 封装,提供简洁、类型安全、符合 ORM 规范的 API 调用方式。
⚠️ 本项目包括文档大部分由 AI 完成,如遇到问题请提 Issue
✨ 特性
- 🏗️ 标准 ORM 架构: 仓储模式 + 服务层,职责清晰
- 🎯 类型安全: 100% TypeScript,完整的类型推导
- 🔗 关系映射: 支持实体关系的访问和管理
- 🌏 国家云支持: 全球版/中国版/美国政府版
- 🚀 95%+ API 覆盖: 覆盖 Graph v1.0 绝大多数常用接口
- 🔍 强大查询构建器: 支持复杂查询、分页、排序
- ⚡ 高级功能: Delta Query、批处理、Webhooks
- 📦 模块化设计: 按需使用仓储和服务
- 🐛 统一调试: 所有请求支持
getDebug()和getRaw()调试功能 - 🔧 自定义 Headers: 统一的自定义 header 管理
🆕 新版本亮点
清晰的三层架构
┌─────────────────────────────────────┐
│ GraphORM (入口层) │
│ 统一访问入口,管理仓储和服务 │
└─────────────────────────────────────┘
│ │
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ Repositories │ │ Services │
│ - UserRepository │ │ - FileService │
│ - GroupRepository │ │ - MailService │
│ - DeviceRepository│ │ - CalendarService│
│ ... │ │ ... │
└───────────────────┘ └───────────────────┘
│ │
└────────┬───────────┘
▼
┌──────────────────┐
│ QueryBuilder │
│ 查询构建器 │
└──────────────────┘📦 安装
npm install @qingu-x/msgraph-orm-js🚀 快速开始
import { GraphClient, defaultEndpoints, createGraphORM } from '@qingu-x/msgraph-orm-js';
// 1. 创建 Graph 客户端
const graphClient = new GraphClient(
{
tenantId: 'your-tenant-id',
clientId: 'your-client-id',
clientSecret: 'your-client-secret'
},
defaultEndpoints.global // 全球版端点
);
// 2. 获取底层 Graph Client
const client = graphClient.getGraphClient();
// 3. 创建 ORM 实例(可选:设置默认时区)
const orm = createGraphORM(client, 'Asia/Shanghai');
// 或者动态设置时区
// orm.setDefaultTimeZone('Asia/Shanghai');
// 4. 开始使用
// 用户管理(仓储)
const users = await orm.users
.query()
.where('department', 'eq', 'IT')
.select(['displayName', 'mail'])
.top(10)
.get();
// 调试信息(新功能)
const debugInfo = orm.users.query().getDebug();
console.log('请求调试信息:', debugInfo);
// 文件操作(服务)
await orm.files.uploadSmallFile('user-id', '/path/file.pdf', buffer);
// 邮件操作(服务)
await orm.mail.send('user-id', {
subject: '测试邮件',
toRecipients: [{ emailAddress: { address: '[email protected]' } }],
body: { contentType: 'Text', content: '邮件内容' }
});📚 核心概念
1. 仓储 (Repositories)
仓储负责实体的 CRUD 操作和关系访问:
// 用户仓储
const user = await orm.users.findById('user-id');
const userByEmail = await orm.users.findByEmail('[email protected]');
const exists = await orm.users.exists('user-id');
const count = await orm.users.count({ department: 'IT' });
// 关系访问
const userGroups = await orm.users.groups('user-id').findMany();
const userMessages = await orm.users.messages('user-id').findMany();
const manager = await orm.users.getManager('user-id');
// 组仓储
const group = await orm.groups.findById('group-id');
const members = await orm.groups.members('group-id').findMany();
await orm.groups.addMember('group-id', 'user-id');2. 服务 (Services)
服务负责特定领域的业务逻辑:
// 文件服务
const files = orm.files;
await files.uploadSmallFile(userId, path, content);
await files.createFolder(userId, parentId, 'Documents');
const items = await files.search(userId, 'report');
await files.createShareLink(userId, itemId, 'view', 'organization');
// 邮件服务
const mail = orm.mail;
await mail.send(userId, message);
const inbox = await mail.getInbox(userId);
await mail.reply(userId, messageId, '谢谢');
await mail.markAsRead(userId, messageId);
// 日历服务
const calendar = orm.calendar;
await calendar.createEvent(userId, event);
const view = await calendar.getCalendarView(userId, start, end);
await calendar.acceptEvent(userId, eventId);
const rooms = await calendar.findRooms(userId);3. 查询构建器
强大的链式查询:
const results = await orm.users
.query()
.where('department', 'eq', 'IT')
.and('city', 'Beijing')
.or('jobTitle', 'contains', 'Manager')
.select(['id', 'displayName', 'mail', 'jobTitle'])
.orderBy('displayName', 'asc')
.top(20)
.get();
// 分页迭代
for await (const user of orm.users.query().pagination()) {
console.log(user.displayName);
}
// 搜索
const searchResults = await orm.users
.query()
.search('displayName', 'John')
.get();🌟 常用场景
用户管理
// 查询和过滤
const itUsers = await orm.users
.query()
.where('department', 'eq', 'IT')
.orderBy('displayName')
.get();
// 创建用户
const newUser = await orm.users.create({
displayName: '张三',
userPrincipalName: '[email protected]',
mailNickname: 'zhangsan',
accountEnabled: true,
passwordProfile: {
password: 'TempPassword123!',
forceChangePasswordNextSignIn: true
}
});
// 更新用户
await orm.users.update('user-id', {
jobTitle: '高级工程师',
department: '技术部'
});
// 许可证管理
await orm.users.assignLicense('user-id', [
{ skuId: 'sku-id' }
], []);
// 用户关系(使用 Repository,支持查询构建器)
const groups = await orm.users.groups('user-id').findMany();
// 获取用户未读邮件
const unreadMessages = await orm.users.messages('user-id')
.query()
.where('isRead', 'eq', false)
.orderBy('receivedDateTime', 'desc')
.top(10)
.get();
// 获取用户本周事件
const thisWeekEvents = await orm.users.events('user-id')
.query()
.where('start/dateTime', 'ge', '2024-01-01T00:00:00Z')
.orderBy('start/dateTime', 'asc')
.get();组管理
// 创建组
const group = await orm.groups.create({
displayName: '技术部',
mailNickname: 'techteam',
mailEnabled: true,
securityEnabled: true,
groupTypes: ['Unified']
});
// 成员管理
await orm.groups.addMember('group-id', 'user-id');
await orm.groups.removeMember('group-id', 'user-id');
const isMember = await orm.groups.isMember('group-id', 'user-id');
// 获取成员和所有者
const members = await orm.groups.members('group-id').findMany();
const owners = await orm.groups.owners('group-id').findMany();文件操作
// === Repository 方式:使用查询构建器查询文件 ===
// 查询所有文件夹
const folders = await orm.users.driveItems('user-id')
.query()
.where('folder', 'ne', null)
.select(['id', 'name', 'folder'])
.get();
// 查询最近修改的文件
const recentFiles = await orm.users.driveItems('user-id')
.query()
.where('file', 'ne', null)
.orderBy('lastModifiedDateTime', 'desc')
.top(10)
.get();
// CRUD 操作
const item = await orm.users.driveItems('user-id').findById('item-id');
await orm.users.driveItems('user-id').update('item-id', { name: '新名称.pdf' });
await orm.users.driveItems('user-id').delete('item-id');
// === Service 方式:业务逻辑操作 ===
// 上传和下载
await orm.files.uploadSmallFile('user-id', '/Documents/report.pdf', buffer);
const downloadUrl = await orm.files.downloadFile('user-id', 'file-id');
// 文件夹管理
await orm.files.createFolder('user-id', 'root', '工作文档');
const children = await orm.files.listChildren('user-id', 'folder-id');
// 移动、复制
await orm.files.move('user-id', 'item-id', 'target-folder-id');
await orm.files.copy('user-id', 'item-id', 'target-folder-id');
// 共享和权限
const link = await orm.files.createShareLink('user-id', 'item-id', 'view', 'organization');
await orm.files.invite('user-id', 'item-id', ['[email protected]'], ['read']);
// 搜索
const results = await orm.files.search('user-id', '财务报告');邮件操作
// === Repository 方式:使用查询构建器查询邮件 ===
// 查询未读邮件
const unreadMails = await orm.users.messages('user-id')
.query()
.where('isRead', 'eq', false)
.orderBy('receivedDateTime', 'desc')
.select(['id', 'subject', 'from', 'receivedDateTime'])
.top(20)
.get();
// 查询重要邮件
const importantMails = await orm.users.messages('user-id')
.query()
.where('importance', 'eq', 'high')
.get();
// CRUD 操作
const message = await orm.users.messages('user-id').findById('message-id');
await orm.users.messages('user-id').update('message-id', { isRead: true });
await orm.users.messages('user-id').delete('message-id');
// 邮件特定操作(Repository 方法)
await orm.users.messages('user-id').reply('message-id', '收到');
await orm.users.messages('user-id').forward('message-id', recipients, '请查看');
await orm.users.messages('user-id').markAsRead('message-id');
// === Service 方式:业务逻辑操作 ===
// 发送邮件
await orm.mail.send('user-id', {
subject: '会议通知',
toRecipients: [
{ emailAddress: { address: '[email protected]', name: '同事' } }
],
body: {
contentType: 'HTML',
content: '<h1>会议通知</h1><p>明天下午2点开会</p>'
}
});
// 快捷访问常用文件夹
const inbox = await orm.mail.getInbox('user-id', 20);
const sent = await orm.mail.getSentItems('user-id', 20);
const drafts = await orm.mail.getDrafts('user-id');
// 文件夹管理
const folders = await orm.mail.getMailFolders('user-id');
await orm.mail.createMailFolder('user-id', '工作邮件');日历操作
// === Repository 方式:使用查询构建器查询事件 ===
// 查询本周事件
const thisWeekEvents = await orm.users.events('user-id')
.query()
.where('start/dateTime', 'ge', '2024-01-01T00:00:00Z')
.where('end/dateTime', 'le', '2024-01-07T23:59:59Z')
.orderBy('start/dateTime', 'asc')
.get();
// 查询包含特定关键词的会议
const meetings = await orm.users.events('user-id')
.query()
.where('subject', 'contains', '团队会议')
.get();
// CRUD 操作(自动应用默认时区)
const event = await orm.users.events('user-id').findById('event-id');
// 创建事件(自动应用 ORM 的默认时区)
await orm.users.events('user-id').create({
subject: '团队会议',
start: { dateTime: '2024-01-15T10:00:00' }, // 自动应用 Asia/Shanghai
end: { dateTime: '2024-01-15T11:00:00' } // 自动应用 Asia/Shanghai
});
// 或者手动指定时区(会覆盖默认时区)
await orm.users.events('user-id').create({
subject: '团队会议',
start: { dateTime: '2024-01-15T10:00:00', timeZone: 'America/New_York' },
end: { dateTime: '2024-01-15T11:00:00', timeZone: 'America/New_York' }
});
await orm.users.events('user-id').update('event-id', { subject: '更新的标题' });
await orm.users.events('user-id').delete('event-id');
// 事件特定操作(Repository 方法)
await orm.users.events('user-id').accept('event-id', '我会参加');
await orm.users.events('user-id').decline('event-id', '时间冲突');
await orm.users.events('user-id').cancel('event-id', '会议取消');
// === Service 方式:业务逻辑操作 ===
// 日历视图(特殊 API)
const calendarView = await orm.calendar.getCalendarView(
'user-id',
'2024-01-01T00:00:00Z',
'2024-01-31T23:59:59Z'
);
// 日历管理
const calendars = await orm.calendar.getCalendars('user-id');
await orm.calendar.createCalendar('user-id', { name: '工作日历' });
// 会议室查找
const rooms = await orm.calendar.findRooms('user-id');
const roomLists = await orm.calendar.findRoomLists('user-id');
// 查找会议时间
const suggestions = await orm.calendar.findMeetingTimes(
[{ emailAddress: { address: '[email protected]' }, type: 'required' }],
{ timeslots: [{ start: startTime, end: endTime }] },
'PT1H' // 1小时会议
);
// 忙闲时间表
const schedule = await orm.calendar.getSchedule(
['[email protected]', '[email protected]'],
startTime,
endTime
);⚡ 高级功能
调试和监控
// 获取请求调试信息
const query = orm.users.query().where('department', 'eq', 'IT');
const debugInfo = query.getDebug();
console.log('请求方法:', debugInfo.method);
console.log('请求 URL:', debugInfo.url);
console.log('请求头:', debugInfo.headers);
// 获取原始请求参数(不执行请求)
const rawParams = query.getRaw();
console.log('请求参数:', rawParams);
// 执行请求后获取调试信息
const users = await query.get();
const lastDebugInfo = query.getDebug();
console.log('最后请求的调试信息:', lastDebugInfo);自定义 Headers
// 为所有请求添加自定义 header
const query = orm.users.query()
.header('ConsistencyLevel', 'eventual')
.header('Prefer', 'outlook.timezone="Asia/Shanghai"')
.where('displayName', 'startswith', '张')
.get();
// 服务层也支持自定义 headers
await orm.mail.send('user-id', message, {
'X-Custom-Header': 'value'
});增量查询 (Delta Query)
// 首次查询
const delta = await orm.deltaUsers();
console.log('用户数:', delta.data.length);
// 保存 deltaLink
const deltaLink = delta.meta.deltaLink;
// 后续查询(只返回变化)
const changes = await orm.deltaUsers(deltaLink);
console.log('变化的用户:', changes.data);
// 其他资源
const groupDelta = await orm.deltaGroups();
const messageDelta = await orm.deltaMessages('user-id');
const eventDelta = await orm.deltaEvents('user-id');
const fileDelta = await orm.deltaDriveItems('user-id');批处理请求
const response = await orm.batch([
{ id: '1', method: 'GET', url: '/users/[email protected]' },
{ id: '2', method: 'GET', url: '/users/[email protected]' },
{
id: '3',
method: 'PATCH',
url: '/users/[email protected]',
body: { jobTitle: '工程师' }
}
]);
response.responses.forEach(res => {
console.log(`请求 ${res.id}: 状态 ${res.status}`);
});搜索 API
// 搜索用户
const userResults = await orm.searchUsers('John Doe', 10);
// 搜索邮件
const mailResults = await orm.searchMessages('project report', 20);
// 搜索文件
const fileResults = await orm.searchFiles('budget.xlsx', 10);
// 自定义搜索
const customSearch = await orm.search({
entityTypes: ['driveItem', 'message'],
query: { queryString: '财务报告' },
from: 0,
size: 25
});🌏 国家云支持
import { GraphClient, defaultEndpoints, createGraphORM } from '@qingu-x/msgraph-orm-js';
// 中国版(21Vianet)
const graphClientCN = new GraphClient(
{
tenantId: 'your-tenant-id',
clientId: 'your-client-id',
clientSecret: 'your-client-secret'
},
defaultEndpoints.cn // 中国版端点
);
// 美国政府版(GCC)
const graphClientGCC = new GraphClient(
{
tenantId: 'your-tenant-id',
clientId: 'your-client-id',
clientSecret: 'your-client-secret'
},
defaultEndpoints.usGCC // 美国政府版 GCC 端点
);
// 美国政府版(GCC High)
const graphClientGCCHigh = new GraphClient(
{
tenantId: 'your-tenant-id',
clientId: 'your-client-id',
clientSecret: 'your-client-secret'
},
defaultEndpoints.usGCCHigh // 美国政府版 GCC High 端点
);
// 美国政府版(DoD)
const graphClientDoD = new GraphClient(
{
tenantId: 'your-tenant-id',
clientId: 'your-client-id',
clientSecret: 'your-client-secret'
},
defaultEndpoints.usDOD // 美国政府版 DoD 端点
);
// 创建 ORM
const orm = createGraphORM(graphClientCN.getGraphClient());📖 文档
🤝 贡献
欢迎贡献代码!请查看 贡献指南。
📄 许可证
MIT © qingu-x
⚠️ 免责声明
本项目不是微软官方项目,仅为 Microsoft Graph API 的封装。使用前请确保:
- 具有适当的 API 权限
- 遵守微软 Graph API 的使用条款
- 了解国家云的功能限制
📮 反馈
遇到问题或有建议?请:
