æ供关系数æ®åº“查询æœåŠ¡ï¼Œç‹¬ç«‹äºŽå…³ç³»æ•°æ®åº“,åªæ供查询æœåŠ¡ã€‚
tables.json
文件的é…置内容,把需è¦æŸ¥è¯¢çš„æ•°æ®åŠ 载到内å˜ä¸ã€‚tables.json
文件é…置的对象关系,在内å˜ä¸å»ºç«‹å…³è”关系。query
目录下*.path
文件的查询过程。tables.json
文件用于é…置从数æ®åº“ä¸åŠ 载的内容,说明如下:
json
{
// æ•°æ®åº“连接
"conn": "mssql://sa:class123!@!@192.168.50.3/AFproduct_zhengshi",
// æ•°æ®åº“表声明
"tables": {
// 表å
"t_userinfo": {
// 主键,å¯ä»¥æ²¡æœ‰ï¼Œæœ‰ä¸»é”®ï¼Œä¼šæ ¹æ®ä¸»é”®å»ºç«‹Bæ ‘ï¼Œä»¥åŠ å¿«æŸ¥è¯¢
"key": "f_userinfo_id",
// è¦åŠ 载的å—段
"fields": {
// å—段å,åŠç±»åž‹ï¼ŒåŸºæœ¬ç±»åž‹æœ‰ï¼š[Int, String, Double, Datetime]
"f_userinfo_id": "Int",
"f_user_state": "String",
// 引用类型有:[OneToOne, OneToMany, ManyToOne],建立了引用类型,在pathä¸å°±å¯ä»¥æŒ‰å¯¹è±¡è·¯å¾„进行检索
// 引用类型å‚数:["引用表", "外键å—段"].
// 引用表: 在这个表上会建立外键,外键值为主表主键值
// 外键å—段: 从表外键,其值为主表主键值
"address": {"OneToOne": ["t_user_address", "f_userinfo_id"]},
"sellinggas": {"OneToMany": ["t_sellinggas", "f_userinfo_id"]},
}
},
// 被引用表的åå—
"t_sellinggas": {
"fields": {
"id": "Int",
// 从表外键
"f_userinfo_id": "Int",
// 浮点数用double,ä¸ç”¨ç®¡æ•°æ®åº“本身类型
"f_pregas": "Double",
// 日期型
"f_operate_date": "Datetime",
// 设置多对一关系,å‚æ•°["引用类型", “外键å—段â€]
"userinfo": {"ManyToOne":["t_userinfo", "f_userinfo_id"]}
}
}
}
}
query目录下å˜æ”¾æŸ¥è¯¢å†…容,查询在path.yaml
文件ä¸æ³¨å†Œã€‚pathè¯è¨€çš„查询说明如下:
```rust // å®¢æˆ·ç«¯ä¼ è¿‡æ¥çš„å‚数声明,客户端å‚数按json串æä¾› p { // å‚æ•°ååŠç±»åž‹ï¼Œç±»åž‹æœ‰[datetime, int, string, double] start: datetime, end: datetime }
// 这里g.
表示由rustè¯è¨€æ供的函数,这些函数怎么æ供,在设计文档里有说明
// p.
说明å–å‚数值。
// year函数也是rustæ供的
let y = g.year(p.start)
// æ ¹æ®å¼€å§‹æ—¶é—´å–å¾—æ¯ä¸ªæœˆå¼€å§‹åŠç»“æŸæ—¶é—´ // å‰é¢å®šä¹‰çš„å˜é‡å¯ä»¥ç›´æŽ¥ç”¨ï¼Œä¸ç”¨åŠ å‰ç¼€ let start1 = g.datestart(y, 1, 1) let end1 = g.dateend(y, 1, 31) let start2 = g.datestart(y, 2, 1) let end2 = g.dateend(y, 2, 28)
// pathè¯è¨€çš„æ ¸å¿ƒï¼Œæ²¿å¯¹è±¡è·¯å¾„æŸ¥è¯¢
// 从tuserinfo开始,ä¸æ‹¬å·é‡Œå†…容是过滤过程,å¯å¤šæ¬¡è¿‡æ»¤
// [1..100]是å–过滤åŽç¬¬1到100æ¡æ•°æ®ï¼Œç”¨äºŽå¤„ç†ç¿»é¡µ
// address.f_residential_area
就是沿一对一对象关系进行过滤了
// ç‚¹åŠ å°æ‹¬å·ï¼Œæ˜¯å–过滤åŽçš„内容
// æœ€ä¸Šå±‚è¡¨åŠ db
å‰ç¼€ï¼Œè¡¨ç¤ºå–æ•°æ®åº“表。
// p.saddress: 表示å‚æ•°address的原始å—符串形å¼ï¼Œè½¬æ¢åŽçš„内容为p.address
// 抽å–汇总åŠåˆ†é¡µçš„公共部分, path支æŒæŠŠå…¬å…±éƒ¨åˆ†è¿›è¡ŒæŠ½å– let search = db.tuserinfo[fuserstate != "销户" && (p.saddress == "" || address.fresidentialarea == p.address)]
// path支æŒifè¯å¥ï¼Œpagetotalæ˜¯ç³»ç»Ÿä¼ è¿‡æ¥çš„æ ‡å¿—ï¼Œçœ‹æ˜¯å¦æ±‚汇总 if pagetotal { // 求总和,total表示,åŽé¢çš„选择是èšé›†å‡½æ•°ã€‚ search.total(count() c) } else { // 分页查询内容 // pagestart, pageend: ä¼ é€’è¿‡æ¥çš„页开始åŠç»“æŸå‚数。 search[pagestart..pageend].( // å–用户编ç ,æ¯ä¸€ä¸ªé€‰æ‹©é¡¹éƒ½å¿…须有一个别å fuserinfoid fuserinfoid, // 沿一对一关系å–内容 address.fresidentialarea area, // 对于一对多关系,å¯ä»¥åœ¨å…³è”对象ä¸è¿›ä¸€æ¥è¿‡æ»¤ï¼Œè¿‡æ»¤åŽï¼Œè°ƒç”¨sum函数求和 // 下é¢è¿™å¥æ˜¯åœ¨æ—¶é—´æ®µå†…ï¼Œè¿™ä¸ªç”¨æˆ·çš„æ€»æ°”é‡ sellinggas[foperatedate >= p.start && foperatedate <= p.end].sum(fpregas) sumgas, // 进行两é过滤,在时间段过滤åŽï¼Œåœ¨å–出æ¯ä¸ªæœˆçš„æ°”é‡æ¥ sellinggas[foperatedate >= p.start && foperatedate <= p.end][foperatedate >= start1 && foperatedate <= end1].sum(fpregas) gas1, sellinggas[foperatedate >= p.start && foperatedate <= p.end][foperatedate >= start2 && foperatedate <= end2].sum(fpregas) gas2 ) } ```
æ¯æ¬¡ä¿®æ”¹é…置文件åŠpath程åºåŽï¼Œéƒ½å¿…é¡»é‡æ–°ç¼–译。为了迫使rust编译,把main程åºéšä¾¿æ”¹å˜ä¸‹ã€‚è¿è¡Œå¦‚下命令编译:
cargo build --release
编译完æˆåŽï¼Œå¯åŠ¨æœåŠ¡ï¼ŒæŠŠtarget release
ä¸‹çš„å†…å®¹æ·»åŠ åˆ°ç³»ç»Ÿpath
环境下,就å¯ä»¥è¿è¡Œå¦‚下命令å¯åŠ¨æœåŠ¡äº†ï¼š
search
æœåŠ¡é€šè¿‡æ”¯æŒpostå‘é€çš„postmanç‰å·¥å…·è¿›è¡Œè®¿é—®ï¼ŒæœåŠ¡å†…容有:
http://127.0.0.1:8000/monthgas.path
:直接执行查询。http://127.0.0.1:8000/monthgas.path/n
:求总和,将调用path的求总和部分。http://127.0.0.1:8000/monthgas.path/1/5
:求分页内容,结构为:/查询å/页å·-从1开始/æ¯é¡µæ•°æ®ä¸ºäº†æµ‹è¯•ä¸å—æ•°æ®åº“环境影å“,æ供了数æ®ç”Ÿæˆè¿‡ç¨‹ï¼Œæµ‹è¯•ç”¨ä¾‹ç¼–写过程如下:
在tests下建立jsonæ ¼å¼çš„æ•°æ®ç”Ÿæˆæ–‡ä»¶ï¼Œè¯´æ˜Žå¦‚下:
json
{
// è¦äº§ç”Ÿæµ‹è¯•æ•°æ®çš„表
"t_userinfo": {
// 产生记录的个数
"nums": 10,
// 产生记录的å—段说明
"fields": {
// 这个å—段从1å¼€å§‹ï¼Œä¸€ç›´ç´¯åŠ ï¼Œæ¯æ¬¡åŠ 1
"f_userinfo_id": {"from": 1},
// 这个å—段的内容,åªèƒ½æ˜¯ç»™å®šå†…容
"f_user_state": {"from": ["æ£å¸¸"]}
}
},
"t_user_address": {
"nums": 10,
"fields": {
"f_userinfo_id": {"from": 1},
"f_residential_area": {"from": ["西安软件å›"]}
}
},
"t_sellinggas": {
"nums": 100,
"fields": {
"id": {"from": 1},
// 这个å—段从1到10循环产生
"f_userinfo_id": {"from": 1, "to": 10},
// 这个å—段内容在[10.0, 10.5, 20.0]之ä¸å¾ªçŽ¯å–值
"f_pregas": {"from": [10.0, 10.5, 20.0]},
// 这个å—段是日期类型,æ¯æ¬¡åŠ 1秒
"f_operate_date": {"from": "2021-01-01T00:00:00"}
}
}
}
æ¯ä¸ªæµ‹è¯•ç”¨ä¾‹å†…容如下:
```rust // 所有测试用例,统一创建一éæµ‹è¯•æ•°æ® initialize();
// å¯åŠ¨æœåŠ¡
let client = Client::tracked(rocket()).expect("valid rocket instance");
// ä»Žå¤–éƒ¨ä¼ ç»™æŸ¥è¯¢çš„å‚æ•°
let str = "{\"start\":\"2021-01-01T00:00:00\", \"end\":\"2021-12-31T23:59:59\"}");
// 执行æŸä¸ªæŸ¥è¯¢
let response = client.post("/aggfilter").body(str).dispatch();
// 检查返回状æ€
asserteq!(response.status(), Status::Ok);
// 执行快照检查,如果没有快照,或者快照有问题,将产生åŽç¼€å为.new
的快照文件。
// 检查没问题åŽï¼ŒæŠŠ.new
åŽç¼€åŽ»æŽ‰ï¼Œåœ¨è¿è¡Œæµ‹è¯•è¿‡ç¨‹ï¼Œå°±é€šè¿‡äº†ã€‚
assertsnapshot!("testaggfilter", response.intostring().unwrap());
```
命令如下:
cargo test --release
å¯ä»¥å¯¹æŸ¥è¯¢æ€§èƒ½ä¼˜åŒ–进行测试,测试代ç 在benches
目录下,è¿è¡Œä¸‹é¢å‘½ä»¤è¿›è¡Œæ€§èƒ½æµ‹è¯•ï¼š
cargo bench
bin.rs
ä¸test_update
å’Œtest_update_search
用æ¥è¿›è¡Œå¹¶å‘测试,æ£å¸¸æµ‹è¯•ä¸ä¼šæ‰§è¡Œï¼Œç”¨ä¸‹é¢å‘½ä»¤æ‰§è¡Œã€‚
cargo test -- --ignored
下一版将å°è¯•åœ¨path程åºé‡Œå®šä¹‰å‡½æ•°ï¼Œå½¢å¼å¦‚下:
rust
let f x = x + 3
f(5)
对于一些基础函数,应该在rustè¯è¨€ä¸è¿›è¡Œæ·»åŠ ,具体ä½ç½®æ˜¯src/search/database.rs
æ–‡ä»¶ï¼Œè‡ªå·±å®šä¹‰çš„å‡½æ•°å»ºè®®æ·»åŠ åœ¨æ–‡ä»¶æœ«å°¾ã€‚æ·»åŠ å¥½åŽï¼Œåœ¨path程åºé‡Œé€šè¿‡g.函数调用
çš„æ–¹å¼è¿›è¡Œè°ƒç”¨ã€‚
ç›®å‰åªæ供了sqlserver的支æŒã€‚pathè¯è¨€ä¸Žæ•°æ®åº“æ— å…³ï¼Œæ•°æ®åº“åªç”¨äºŽåˆå§‹æ•°æ®çš„åŠ è½½è¿‡ç¨‹ã€‚è¿™æ®µä»£ç 在src/search/table.rs
ä¸ã€‚
æ•°æ®åº“çš„æ¯ä¸ªè¡¨å¢žåŠ s_timestamp
,å—段类型必须是timestamp
。这ç§å—段,在数æ®å‘生å˜åŒ–åŽï¼Œä¼šè‡ªåŠ¨å¢žåŠ ã€‚ç³»ç»Ÿæ ¹æ®è¿™ä¸ªå—段内容决定数æ®æ˜¯å¦å˜åŒ–。
è¯»å†™è¿‡ç¨‹æ²¡æœ‰åŠ ä»»ä½•é”,rust对基本数æ®åŠé›†åˆæ供了线程安全的读写æ“作,ä¸ç”¨åŠ é”。
u8
å½¢å¼å˜æ”¾ï¼Œåœ¨å—段声明时,把枚举的å—符串列出æ¥å³å¯ã€‚所有查询全部写在query目录下,查询在path.yamlä¸è¿›è¡Œæ³¨å†Œï¼Œpath.yaml
ä¸æœ‰æ³¨é‡Šè¯´æ˜Žã€‚