tuple是有序的collection type
,但其內可以含有不同的型別。例如:
select ('Apple', 7);
{('Apple', 7)}
請注意,此query返回結果依然是EdgeDBSet
。
相對於array
可以使用[]
來索引,tuple
則可以使用.
來取得元素,且可以分為unnamed
及named
兩種。
unnamed tuple
利用.
搭配數字(一樣由0開始)來取得元素。例如:
select ('Apple', 7).0;
{'Apple'}
named tuple
除了可以如unnamed tuple
一樣,利用.
搭配數字來取得元素。例如:
select (fruit:='Apple', n:=7).0;
{'Apple'}
也可以利用.
搭配str
來取得元素。例如:
select (fruit:='Apple', n:=7).fruit;
{'Apple'}
tuple
一般用於整理外部所收集的資訊,來供後續的bulk operation
使用。以下舉了兩種使用情況,希望能幫助大家熟悉tuple
的使用。
考慮schema如下:
type Todo {
priority: int64;
note: str
}
假設此時我們想insert
兩個Todo object
,除了一個一個insert
外,可以巧妙運用tuple
進行bulk inserts
:
with todos:= {(10, "check emails"),
(3, "code review")}
for todo in todos
union (
insert Todo {
priority:= todo.0,
note:= todo.1
}
);
又或者:
with todos:= {(priority:=10, note:="check emails"),
(priority:=3, note:="code review")}
for todo in todos
union (
insert Todo {
priority:= todo.priority,
note:= todo.note
}
);
以上可以看出,我們在with
區塊內使用tuple
來幫忙整理資訊,供後續bulk inserts
時使用,這是個非常典型的用法。
考慮schema如下:
type Remark {
required location: str {
constraint exclusive
}
multi todos: tuple<priority:int64, note: str>
}
可以觀察到tuple
直接定義在multi todos property
中。
假設此時我們想insert
兩個Remark object
,可以這麼寫:
with works:= {("office", (10, "check emails"), (3, "code review")),
("home", (7, "do the laundry"), (9, "clean the bathroom"))}
for work in works
union (
insert Remark {
location:= work.0,
todos:= work.1 union work.2
}
);
又或者:
with works:= {(location:="office",
todo1:= (10, "check emails"),
todo2:= (3, "code review")),
(location:="home",
todo1:= (7, "do the laundry"),
todo2:= (9, "clean the bathroom"))}
for work in works
union (
insert Remark {
location:= work.location,
todos:= work.todo1 union work.todo2
}
);
以上可以看出,將tuple
使用於schema內,可有效收集不同型別在同一個property
中。
range()像是一個產生器,可以用來產生整數、浮點數及與時間相關的scalar type
。
range
與range
間可以進行運算,例如:
select range(1, 10) + range(5, 15);
{range(1, 15)}
一般常用的情況為使用range_unpack()來得到一連串的數字或時間。例如:
select range_unpack(range(1, 10));
{1, 2, 3, 4, 5, 6, 7, 8, 9}
或是:
select range_unpack(range(
<cal::local_date>'2024-08-01',
<cal::local_date>'2024-08-05'));
{
<cal::local_date>'2024-08-01',
<cal::local_date>'2024-08-02',
<cal::local_date>'2024-08-03',
<cal::local_date>'2024-08-04',
}
以上可以觀察出,range()
預設是包含下界但不包含上界的。但我們可以使用inc_lower
及inc_upper
兩個參數來改變這個設定。例如:
select range_unpack(range(1, 10, inc_lower:=false, inc_upper:=true));
{2, 3, 4, 5, 6, 7, 8, 9, 10}
與預設結果相比,我們少了1卻多了10。
multirange()可以將多個range()
區段視為一個整體,例如:
select multirange([range(8, 10), range(1, 4), range(2, 5)]);
{[range(1, 5), range(8, 10)]}
請留意這裡range(1, 4)
與range(2, 5)
合併為range(1, 5)
。如果我們使用multirange_unpack()與range_unpack()
,可以觀察到裡面所含的元素:
with mr_unpack:= multirange_unpack(
multirange(
[range(8, 10), range(1, 4), range(2, 5)]
)
)
select range_unpack(mr_unpack);
{1, 2, 3, 4, 8, 9}
一般常用的情況為使用contains()來判斷某個值、某個range
甚至某個multirange
是不是在一個multirange
內。
select contains(
multirange([range(1, 4), range(7)]),
multirange([range(1, 2), range(8, 10)]),
);
{true}
其結果為true
。這是因為multirange([range(1, 4), range(7)])
可以涵蓋multirange([range(1, 2), range(8, 10)])
。其中range(1, 4)
涵蓋了range(1, 2)
且range(7)
(下界為7,上界unbounded)涵蓋了range(8, 10)
。
或是:
select contains(
multirange([range(
<cal::local_date>'2024-01-01',
<cal::local_date>'2024-07-01'),
range(
<cal::local_date>'2024-08-01',
<cal::local_date>'2025-01-01')]),
<cal::local_date>'2024-07-01'
);
{false}
其結果為false
,因為range()
預設是包含下界但不包含上界,所以2024-07-01
並不在範圍內。