Blog

  • Penghalang Itu Bernama Kufu

    Beberapa tahun yang lalu saat tengah malam menjelang pagi seperti biasanya kami berdiskusi banyak hal, dari topik random sampai serius. Mulai dari kabar, diskusi pada beberapa literasi kuno hingga berdiskusi teori silsilah bangsa Arab dan keturunan nabi karena kebetulan waktu itu kami ditemani oleh ustad ahmad wakid yang memiliki garis keturunan Arab.

    Pada akhir nya temanku menceritakan bagaimana dia ditolak oleh bekas mantan calon mertuanya yang memiliki garis keturunan spesial karena dianggap tidak selevel meskipun berasal dari keluarga terpandang. Saat itu aku hanya mengatakan kenapa dulu tidak didebat saja karena menurutku itu adalah salah satu pemahaman yang tidak masuk akal dan berbenturan dengan dalil yang termaktub di Qur’an.

    Dia hanya mengatakan bahwa dulu tidak terpikir untuk mendebat dengan cara tersebut. Menariknya beberapa lama kemudian temanku yang lain juga menghadapi penghalang yang mirip.

  • Optimize Postgres Cursor Pagination

    This query use to implement graphql cursor pagination (first, last, after, before, offset, order)

    
    
    WITH __l1__ AS(
      SELECT
        json_build_array(
          json_build_array('id', 'alpha_3'),
          json_build_array(id, alpha_3)
        ) :: TEXT AS __cursor__,
        *
      FROM
        countries
      ORDER BY
        id ASC,
        alpha_3 ASC
      LIMIT
        10 OFFSET 0
    ),
    __l2__ AS(
      SELECT
        EXISTS(
          SELECT
            true
          FROM
            countries
          WHERE
            json_build_array(
              json_build_array('id', 'alpha_3'),
              json_build_array(id, alpha_3)
            ) :: TEXT > (
              SELECT
                MAX(__cursor__)
              FROM
                __l1__
            )
        ) AS __has_prev_page__,
        EXISTS(
          SELECT
            true
          FROM
            countries
          WHERE
            json_build_array(
              json_build_array('id', 'alpha_3'),
              json_build_array(id, alpha_3)
            ) :: TEXT < (
              SELECT
                MIN(__cursor__)
              FROM
                __l1__
            )
        ) AS __has_next_page__
    )
    SELECT
      *
    FROM
      __l1__,
      __l2__
    ORDER BY
      ROW_NUMBER() OVER() DESC
    Rust code:
    query(after, before, first, last, |after, before, first, last| async move {
        let orders = orders.unwrap_or(vec![CountryOrder::IdAsc]);
        let is_desc = orders
            .first()
            .map(|order| OrderColumn::is_desc(order))
            .unwrap_or(false);
        let is_desc = if last.is_some() { is_desc } else { !is_desc };
    
        let mut filters = vec![];
        if let Some(keyword) = keyword {
            filters.push(format!(r#"id ~* '{k}' OR alpha_2 ~* '{k}' OR alpha_3 ~* '{k}' OR name ILIKE '%{k}%'"#, k = keyword));
        }
    
        let filters = if filters.len() > 0 {
            format!("WHERE {}", filters.iter().map(|filter| format!("({})", filter)).join(" AND "))
        } else { String::default() };
    
        let mut l1_orders = orders
            .iter()
            .map(|order| if is_desc {
                OrderColumn::query_string_flip(order)
            } else {
                OrderColumn::query_string(order)
            })
            .join(", ");
    
        let mut page_logic = ("<", ">");
        let mut page_fn = ("MIN", "MAX");
        let mut l3_order = "ASC";
        if is_desc {
            page_logic = (page_logic.1, page_logic.0);
            page_fn = (page_fn.1, page_fn.0);
            l3_order = "DESC";
        }
    
        let limit = first.unwrap_or_else(|| last.unwrap_or(1000));
    
        let q = format!(r#"WITH __l1__ AS(
            SELECT json_build_array(json_build_array({cursor_keys}), json_build_array({cursor_columns}))::TEXT AS __cursor__, *
            FROM {table_name}
            {filters}
            ORDER BY {l1_orders}
            LIMIT {limit}
            OFFSET {offset}
        ), __l2__ AS(
            SELECT EXISTS(
                SELECT true FROM {table_name} WHERE json_build_array(json_build_array({cursor_keys}), json_build_array({cursor_columns}))::TEXT {prev_page_logic} (
                    SELECT {prev_page_fn}(__cursor__) FROM __l1__
                )
            ) AS __has_prev_page__,
            EXISTS(
                SELECT true FROM {table_name} WHERE json_build_array(json_build_array({cursor_keys}), json_build_array({cursor_columns}))::TEXT {next_page_logic} (
                    SELECT {next_page_fn}(__cursor__) FROM __l1__
                )
            ) AS __has_next_page__
        )
        SELECT * FROM __l1__, __l2__ ORDER BY ROW_NUMBER() OVER() {l3_order}"#,
                        table_name = TABLE_NAME,
                        cursor_keys = orders.iter().map(|order| format!("'{}'", OrderColumn::column_name(order))).join(", "),
                        cursor_columns = orders.iter().map(|order| OrderColumn::column_name(order)).join(", "),
                        limit = limit,
                        filters = filters,
                        l1_orders = l1_orders,
                        offset = offset.unwrap_or(0),
                        prev_page_logic = page_logic.0,
                        prev_page_fn = page_fn.0,
                        next_page_logic = page_logic.1,
                        next_page_fn = page_fn.1,
                        l3_order = l3_order,
        );
    
        println!("{}", q);
    
        let mut has_prev_page = false;
        let mut has_next_page = false;
        let data = sqlx::query(q.as_str())
            .fetch(pool)
            .map_ok(|row| {
                has_prev_page = row.get("__has_prev_page__");
                has_next_page = row.get("__has_next_page__");
                let cursor: String = row.get("__cursor__");
    
                Edge::new(encode(cursor), Country {
                    id: row.get("id"),
                    alpha_2: row.get("alpha_2"),
                    alpha_3: row.get("alpha_3"),
                    name: row.get("name"),
                })
            })
            .map_err(Arc::new)
            .try_collect::<Vec<Edge<String, Country, EmptyFields>>>()
            .await?;
    
        let mut connection = Connection::new(has_prev_page, has_next_page);
        connection.append(data.into_iter());
        Ok::<_, Error>(connection)
    }).await
  • Turn Off Battery Notification in Ubuntu Focal

    Just use this commands

    cd /etc/UPower
    sudo nano UPower.conf

    Change UsePercentageForPolicy=true into UsePercentageForPolicy=false

    sudo systemctl restart upower
  • Bertemu

    Saat kemarin jadi bilang bahwa kau sedang ke Jogja,  jujur saja aku ingin sekali ke sana. Untuk bertemu denganmu, seseorang yang masuk ke dalam mimpiku. Orang yang tidak pernah aku kira datang di sana.

    Namun maafkan aku karena kita belum bisa bertemu untuk saat ini. 

  • Diam

    Aku tidak akan melakukannya lagi

    Sebuah kalimat

    Saat aku memintamu untuk tidak menghilang lagi

    Kalimat terakhir yang aku dengar langsung darimu

    Tapi itu hanya berlangsung 2 hari

    Dan sepertinya kau tidak mau tau penjelasan ku lagi

    Membuat ku merasakan sakit kepala yang sangat sakit

  • Continued

    Alhamdulillah,

    Pertarungan berlanjut

    Kita akan pergi memancing bersama

    Seperti janjiku padamu

    Insya Allah

    20181113
  • I’m Lost Without You

    I swear that I can go on forever again
    Please let me know that my one bad day will end 
    I will go down as your lover, your friend
    Give me your lips and with one kiss we beginAre you afraid of being alone
    Cause I am, I’m lost without you
    Are you afraid of leaving tonight
    Cause I am, I’m lost without youI’ll leave my room open till sunrise for you
    I’ll keep my eyes patiently focused on you
    Where are you now I can hear footsteps I’m dreaming
    And if you will, keep me from waking to believe thisI’m lost without you
    I’m lost without you

  • I Want to Grow Old with You

    Another day without your smile
    Another day justes by
    But now i know how much it means
    For you to stay right here with me
    The time we spent apart will make our love grow stronger
    But it hurts so bad i can’t take it any longerI want to grow old with you
    I want to die lying in your arms
    I want to grow old with you
    I want to be looking in your eyes
    I want to be there for you, sharing everything you do
    I want to grow old with youA thousand miles between us now
    It causes me to wonder how
    Our love tonight remains so strong
    It makes our risk right all along
    The time we spent apart will make our love grow stronger
    But it hurt so bad i can’t take it any longerI want to grow old with you
    I want to die lying in your arms
    I want to grow old with you
    I want to be looking in your eyes
    I want to be there for you, sharing everything you do
    I want to grow old with youThings can come and go
    I know but
    Baby I believe
    Something’s burning strong between us
    Makes it clear to meI want to grow old with you
    I want to die lying in your arms
    I want to grow old with you
    I want to be looking in your eyes
    I want to be there for you, sharing everything you do
    I want to grow old with you

    –Westlife

  • Don’t Look Back in Anger

    Slip inside the eye of your mind
    Don’t you know you might find
    A better place to play
    You said that you’d never been
    But all the things that you’ve seen
    Will slowly fade awaySo I start a revolution from my bed
    ‘Cause you said the brains I had went to my head.
    Step outside, summertime’s in bloom
    Stand up beside the fireplace
    Take that look from off your face
    You ain’t ever gonna burn my heart outAnd so Sally can wait, she knows it’s too late as we’re walking on by
    Her soul slides away, but don’t look back in anger I heard you sayTake me to the place where you go
    Where nobody knows if it’s night or day
    But please don’t put your life in the hands
    Of a Rock n Roll band
    Who’ll throw it all awayI’m gonna start a revolution from my bed
    ‘Cause you said the brains I had went to my head
    Step outside ’cause summertime’s in bloom
    Stand up beside the fireplace
    Take that look from off your face
    ‘Cause you ain’t ever gonna burn my heart outSo Sally can wait, she knows it’s too late as she’s walking on by
    My soul slides away, but don’t look back in anger I heard you saySo Sally can wait, she knows it’s too late as we’re walking on by
    Her soul slides away, but don’t look back in anger I heard you saySo Sally can wait
    She knows it’s too late as she’s walking on by
    My soul slides away
    But don’t look back in anger
    Don’t look back in anger
    I heard you sayAt least not today

  • Stop

    Namanya buatan manusia, bug pada aplikasi pasti akan ada. Butuh proses selama waktu tertentu untuk membuat aplikasi menjadi bug free. Bisa 1 hari,  1 minggu,  1 bulan, 1 tahun atau lebih.  Tergantung dari seberapa besar sistem yang di buat. 

    Pada akhirnya semuanya pasti akan selesai. Mulai dari bug yang bisa solve dalam hitungan menit hingga beberapa minggu, dari kesalahan penulisan kode program hingga query. Yang pasti itu membutuhkan waktu mulai dari reproduce, analisa, bug fixing, testing,  dan deployment.

    And now I’ve 1 checkbox, he will be checked or not at all. Then i can stop to finding.