Skip to content

Commit 5d5bf7f

Browse files
committed
FEAT: implemented query on date values
So one can query multiple date parts with one call, for example: ``` >> query/mode now [year day month time timezone] == [2020 8 4 12:24:54 2:00] ``` If set words are used, the result is like: ``` >> query/mode now [year: month:] == [ year: 2020 month: 4 ] ``` Simple `query now` would return object with all possible fields.
1 parent ea3818e commit 5d5bf7f

File tree

3 files changed

+107
-1
lines changed

3 files changed

+107
-1
lines changed

src/boot/sysobj.r

+18
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,24 @@ standard: context [
299299
none
300300
]
301301

302+
date-info: context [
303+
year:
304+
month:
305+
day:
306+
time:
307+
zone:
308+
date:
309+
weekday:
310+
julian:
311+
yearday:
312+
utc:
313+
hour:
314+
minute:
315+
second:
316+
timezone:
317+
none
318+
]
319+
302320
midi-info: context [
303321
devices-in:
304322
devices-out:

src/core/t-date.c

+72-1
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,22 @@
487487
return TRUE;
488488
}
489489

490+
/***********************************************************************
491+
**
492+
*/ static REBOOL Query_Date_Field(REBVAL *data, REBVAL *select, REBVAL *ret)
493+
/*
494+
** Set a value with date data according specified mode
495+
**
496+
***********************************************************************/
497+
{
498+
REBPVS pvs;
499+
pvs.value = data;
500+
pvs.select = select;
501+
pvs.setval = 0;
502+
pvs.store = ret;
503+
504+
return (PE_USE == PD_Date(&pvs));
505+
}
490506

491507
/***********************************************************************
492508
**
@@ -509,7 +525,7 @@
509525

510526
// !zone! - adjust date by zone (unless /utc given)
511527

512-
if (IS_WORD(arg)) {
528+
if (IS_WORD(arg) || IS_SET_WORD(arg)) {
513529
//!!! change this to an array!?
514530
switch (VAL_WORD_CANON(arg)) {
515531
case SYM_YEAR: i = 0; break;
@@ -718,6 +734,7 @@
718734
REBVAL *val;
719735
REBVAL *arg = NULL;
720736
REBINT num;
737+
REBVAL *spec;
721738

722739
val = D_ARG(1);
723740
if (IS_DATE(val)) {
@@ -829,6 +846,60 @@
829846

830847
case A_ABSOLUTE:
831848
goto setDate;
849+
850+
case A_REFLECT:
851+
if (SYM_SPEC == VAL_WORD_SYM(D_ARG(2))) {
852+
return R_ARG1;
853+
}
854+
if(!Query_Date_Field(val, D_ARG(2), D_RET)) {
855+
Trap_Reflect(VAL_TYPE(val), D_ARG(2));
856+
}
857+
return R_RET;
858+
case A_QUERY:
859+
spec = Get_System(SYS_STANDARD, STD_DATE_INFO);
860+
if (!IS_OBJECT(spec)) Trap_Arg(spec);
861+
if (D_REF(2)) { // query/mode refinement
862+
REBVAL *field = D_ARG(3);
863+
if(IS_WORD(field)) {
864+
if (SYM_SPEC == VAL_WORD_CANON(field)) {
865+
return R_ARG1;
866+
}
867+
if (!Query_Date_Field(val, field, D_RET))
868+
Trap_Reflect(VAL_TYPE(val), field); // better error?
869+
}
870+
else if (IS_BLOCK(field)) {
871+
REBVAL *out = D_RET;
872+
REBSER *values = Make_Block(2 * BLK_LEN(VAL_SERIES(field)));
873+
REBVAL *word = VAL_BLK_DATA(field);
874+
for (; NOT_END(word); word++) {
875+
if (ANY_WORD(word)) {
876+
if (IS_SET_WORD(word)) {
877+
// keep the set-word in result
878+
out = Append_Value(values);
879+
*out = *word;
880+
VAL_SET_LINE(out);
881+
}
882+
out = Append_Value(values);
883+
if (!Query_Date_Field(val, word, out))
884+
Trap1(RE_INVALID_ARG, word);
885+
}
886+
else Trap1(RE_INVALID_ARG, word);
887+
}
888+
Set_Series(REB_BLOCK, D_RET, values);
889+
}
890+
else {
891+
Set_Block(D_RET, Get_Object_Words(spec));
892+
}
893+
} else {
894+
REBSER *obj = CLONE_OBJECT(VAL_OBJ_FRAME(spec));
895+
REBSER *words = VAL_OBJ_WORDS(spec);
896+
REBVAL *word = BLK_HEAD(words);
897+
for (num=0; NOT_END(word); word++,num++) {
898+
Query_Date_Field(val, word, OFV(obj, num));
899+
}
900+
SET_OBJECT(D_RET, obj);
901+
}
902+
return R_RET;
832903
}
833904
}
834905
Trap_Action(REB_DATE, action);

src/tests/units/date-test.r3

+17
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,21 @@ Rebol [
134134

135135
===end-group===
136136

137+
138+
===start-group=== "QUERY date"
139+
date: 8-Apr-2020/12:04:32+2:00
140+
--test-- "query date"
141+
--assert object? o: query date
142+
--assert o/date = 8-Apr-2020
143+
144+
--test-- "query/mode date"
145+
all-date-words: words-of system/standard/date-info
146+
--assert all-date-words = query/mode date none
147+
--assert date/time = query/mode date 'time
148+
--assert [2020 4] = query/mode now [year month]
149+
--assert [month: 4 year: 2020] = query/mode now [month: year:]
150+
--assert [2020 4 8 12:04:32 2:00 8-Apr-2020 3 99 99 8-Apr-2020/10:04:32 12 4 32 2:00] = query/mode date all-date-words
151+
152+
===end-group===
153+
137154
~~~end-file~~~

0 commit comments

Comments
 (0)