iT邦幫忙

2024 iThome 鐵人賽

DAY 8
0
Software Development

一起看無間道學EdgeDB系列 第 8

[Day08] - 介紹tuple、range及multirange

  • 分享至 

  • xImage
  •  

tuple

tuple是有序的collection type,但其內可以含有不同的型別。例如:

select ('Apple', 7);
{('Apple', 7)}

請注意,此query返回結果依然是EdgeDBSet

相對於array可以使用[]來索引,tuple則可以使用.來取得元素,且可以分為unnamednamed兩種。

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的使用。

使用情況1

考慮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時使用,這是個非常典型的用法。

使用情況2

考慮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()

range()像是一個產生器,可以用來產生整數、浮點數及與時間相關的scalar type

rangerange間可以進行運算,例如:

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_lowerinc_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

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並不在範圍內。


上一篇
[Day07] - 介紹multi property及array
下一篇
[Day09] - EdgeQL牛刀小試
系列文
一起看無間道學EdgeDB30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言