engineering docs

Tips

Type References

Int

Field yang membutuhkan bilangan bulat tanpa bagian desimal (tanpa koma atau titik), baik bernilai positif, negatif, maupun nol.

Seperti: limit, sort, rate, level, count, year, minutes, stock, quantity, total, etc.

Contoh penulisan: 10, -5, 0, 1994

Kapasitas: Berukuran 4 byte dengan rentang nilai dari -2.147.483.648 hingga 2.147.483.647

BigInt

Field yang membutuhkan bilangan bulat berukuran sangat besar, tanpa komponen desimal.

Seperti: monetary amount (pecahan uang), sold, etc.

Contoh penulisan: 9223372036854775807, -100000000000

Kapasitas: Berukuran 8 byte dengan rentang nilai jauh lebih luas, dari -9.223.372.036.854.775.808 hingga 9.223.372.036.854.775.807 (untuk versi signed).

BigInt didukung untuk MongoDB pada Prisma v6. BigInt dipetakan ke tipe MongoDB long. (Prisma) Namun ada batasan penting: nilai yang terlalu besar (melebihi batas 64-bit signed integer) tidak dapat disimpan, karena MongoDB Long memiliki batas tersebut. Jika nilai terlalu besar, disarankan untuk menyimpannya sebagai String.

Float

Field yang membutuhkan angka pecahan atau desimal dengan presisi perkiraan (menggunakan titik . sebagai pemisah desimal).

Seperti: percentage, rating, weight, width, height, length, latitude, longitude, etc.

Contoh penulisan: 3.14, -0.05, 1.23E4 (artinya (1,23 × 10^4))

Karakteristik: Bersifat aproksimasi (mendekati nilai asli), kurang disarankan untuk data keuangan yang menuntut keakuratan mutlak.


Application-level Invariant

Prisma 6 + MongoDB tidak menyediakan Decimal; dokumentasi Prisma 6 secara eksplisit menyatakan Decimal belum didukung pada MongoDB (Prisma). Gunakan String sebagai pengganti Decimal untuk sementara. baru kemudian melakukan konversi secara manual di aplikasi (misalnya menggunakan library seperti decimal.js) saat membaca atau menulis nilai tersebut.

Karena Prisma + MongoDB tidak memberikan constraint relational sekuat relational SQL, beberapa aturan tidak boleh dianggap sebagai tanggung jawab schema saja.

Contohnya:

OrderItem:
  type = product
  → productId atau variantId harus ada
 
OrderItem:
  type = service
  → serviceId harus ada

Demikian pula:

PaymentAllocation.amount
    <= Payment remaining amount
 
PaymentAllocation.amount
    <= Invoice remaining balance

dan:

ShipmentItem.quantity
    <= OrderItem.fulfilled-remaining quantity

serta:

Refund total
    <= Payment total

Ini harus dijaga oleh Commerce domain service / transaction logic, bukan mengandalkan Prisma schema.


Units

Perbedaan Int, BigInt, Float, dan Decimal.

TipeDeskripsiMongoDBPostgreSQLPrisma Client JS
IntInteger 32-bitintintegernumber
BigIntInteger 64-bitlongbigintBigInt
FloatBilangan desimal floating-pointdoubledouble precisionnumber
DecimalBilangan desimal presisi tinggi❌ Tidak didukungdecimal(65,30)Decimal (Decimal.js)

Detail:

  • Int — Untuk bilangan bulat biasa (32-bit). Cocok untuk ID, jumlah, dll.
  • BigInt — Untuk bilangan bulat yang sangat besar (64-bit). Gunakan ini jika nilai bisa melebihi batas Int (~2 miliar). Di Prisma Client, direpresentasikan sebagai tipe JavaScript BigInt. [BigInt reference]
  • Float — Untuk bilangan desimal dengan floating-point. Tidak cocok untuk menyimpan nilai uang karena tidak bisa merepresentasikan desimal secara eksak (bisa terjadi pembulatan). [data modeling]
  • Decimal — Untuk bilangan desimal dengan presisi tinggi (misalnya nilai uang). Di Prisma Client menggunakan library Decimal.js. Namun, Decimal tidak didukung di MongoDB. [Decimal reference] [special fields]

Pilihan terbaik: Jika presisi sangat penting (misalnya nilai keuangan), gunakan String. Jika perlu query langsung di DB dan presisi tidak kritis, gunakan Float.


Perbandingan Pendekatan untuk Nilai Uang di MongoDB

PendekatanPresisiBatas NilaiQuery DBCocok untuk
BigInt (satuan terkecil)✅ Aman⚠️ Maks 64-bit✅ Bisa sort/filterNilai tidak terlalu besar
String + Decimal.js✅ Aman✅ Tidak terbatas❌ TerbatasNilai sangat besar / presisi tinggi
Float⚠️ Berisiko✅ Fleksibel✅ Bisa sort/filterTidak disarankan untuk uang

Rekomendasi:

  • Gunakan BigInt jika nilai uang tidak melebihi batas 64-bit dan Anda butuh kemampuan sorting/filtering di database.
  • Jika bekerja dengan nilai crypto seperti wei Ethereum yang sangat besar, BigInt di MongoDB tidak cukup — gunakan pendekatan String + Decimal.js sebagai gantinya.

Decimal

Karena Decimal tidak tersedia untuk MongoDB pada Prisma 6, sehingga menyesuaikan beberapa field diganti String atau BigInt.

String

Menangani Nilai Decimal yang Disimpan sebagai String di MongoDB.

Karena Decimal tidak didukung di MongoDB, Anda bisa menggunakan Prisma Client Extensions untuk mengkonversi nilai String ↔ Decimal secara otomatis saat membaca/menulis data.

Pendekatan: Prisma Client Extension (Result Extension)

Konversi dilakukan otomatis saat data dibaca dari database:

import { PrismaClient, Prisma } from '@prisma/client';
 
const prisma = new PrismaClient().$extends({
  result: {
    product: {
      price: {
        needs: { price: true },
        compute(product) {
          // konversi String → Decimal saat membaca
          return new Prisma.Decimal(product.price);
        }
      }
    }
  }
});

Saat menulis ke database, konversi Decimal → String secara manual:

await prisma.product.create({
  data: {
    price: new Prisma.Decimal('24.99').toString() // simpan sebagai String
  }
});

Saat membaca, nilai sudah otomatis menjadi Decimal:

const product = await prisma.product.findFirst();
console.log(product.price); // Prisma.Decimal("24.99")
 
// bisa langsung pakai operasi Decimal.js
const tax = product.price.times('0.11');
const total = product.price.plus(tax);
console.log(total.toString()); // "27.7389"

Keuntungan Pendekatan Ini:

  • ✅ Nilai tetap presisi (tidak ada floating-point error)
  • ✅ Bisa langsung pakai operasi Decimal.js seperti .plus(), .times(), .minus(), dll.
  • ✅ Konversi terpusat, tidak perlu konversi manual di setiap query

Keterbatasan:

  • ⚠️ Tidak bisa sorting/filtering berdasarkan nilai numerik langsung di MongoDB (karena tersimpan sebagai String)
  • ⚠️ Untuk nested/relational queries, perlu mendefinisikan extension di setiap model yang relevan.

Contoh Operasi Aritmatika dengan Decimal.js:

const product = await prisma.product.findFirst();
 
// price sudah bertipe Prisma.Decimal
const harga = product.price; // Decimal("24.99")
const diskon = new Prisma.Decimal('0.10');
const hargaAkhir = harga.minus(harga.times(diskon));
 
console.log(hargaAkhir.toString()); // "22.491"

Ini adalah pendekatan paling aman untuk menjaga presisi nilai uang sambil menunggu dukungan resmi Decimal128 di Prisma untuk MongoDB.

Int

BigInt

Menggunakan BigInt untuk Nilai Uang di MongoDB dengan Prisma.

Pendekatan ini umum digunakan di aplikasi web3/crypto (misalnya menyimpan nilai dalam satuan terkecil seperti wei untuk Ethereum), di mana nilai uang direpresentasikan sebagai bilangan bulat tanpa desimal.

Strategi: Simpan dalam Satuan Terkecil. Misalnya, daripada menyimpan Rp 24.500,50, simpan dalam sen/satuan terkecil: 2450050 sebagai BigInt.

model Product {
  id    String @id @default(auto()) @map("_id") @db.ObjectId
  price BigInt // dalam satuan sen/wei/satuan terkecil
}

Batasan Penting di MongoDB BigInt di MongoDB dipetakan ke tipe Long (64-bit signed integer), dengan batas:

-9.223.372.036.854.775.808 sampai +9.223.372.036.854.775.807

Jika nilai melebihi batas ini (misalnya nilai wei Ethereum seperti 21049200000000000000), akan muncul error:

A number used in the query does not fit into a 64 bit signed integer.

Contoh Penggunaan Menulis data:

await prisma.product.create({
  data: {
    price: BigInt('2450050') // Rp 24.500,50 dalam satuan sen
  }
});

Membaca dan mengkonversi kembali:

const product = await prisma.product.findFirst();
 
// konversi kembali ke nilai desimal untuk ditampilkan
const hargaDesimal = Number(product.price) / 100;
console.log(hargaDesimal); // 24500.50

Serialisasi ke JSON (perlu penanganan khusus):

JSON.stringify(product, (key, value) => (typeof value === 'bigint' ? value.toString() : value));

Ketika menangani invoice/order dengan nilai besar, aggregate, enterprise purchasing, dan sebagainya, batas tersebut terlalu rendah.

Contoh:

unitPrice        BigInt
subtotalAmount   BigInt
taxAmount        BigInt
grandTotalAmount BigInt

Ada masalah dengan Int dalam menangani monetary amount:

Int32 max ≈ 2.1 billion

Representasinya adalah minor/smallest monetary unit yang ditetapkan oleh application layer.

Untuk IDR:

Rp150.000
  → 150000n

Untuk currency yang memiliki minor unit:

USD 10.50
  → 1050n

Jangan pernah:

price = 100000.50

Dengan demikian kita memperoleh:

  • tidak ada floating-point money
  • tidak bergantung pada Decimal
  • tidak dibatasi Int32
  • aman untuk aggregate financial besar
  • tetap compatible dengan Prisma 6 + MongoDB

Penggunaan BigInt di Prisma Client:

import { PrismaClient } from '@prisma/client';
 
const newRecord = await prisma.sample.create({
  data: {
    revenue: BigInt(534543543534)
  }
});

Catatan: Jika menggunakan JSON.stringify pada objek yang mengandung BigInt, akan terjadi error. Gunakan serialisasi kustom:

JSON.stringify(this, (key, value) => (typeof value === 'bigint' ? value.toString() : value));

BigInt tentu memiliki konsekuensi bahwa serialisasi ke JSON perlu ditangani application layer.


Float

Float dipetakan ke double di MongoDB. Ini lebih mudah untuk query, namun berisiko kehilangan presisi (misalnya 0.1 + 0.2 ≠ 0.3).

⚠️ Prisma sendiri tidak merekomendasikan ini untuk nilai yang membutuhkan presisi tinggi (seperti nilai uang), karena bisa menyebabkan precision errors.

quantity = 1.5
unitPrice = 100000n

Karena commerce tidak selalu menjual hanya unit integer.

Misal:

1.5   kg
2.5   meter
0.75  hour
1.25  liter

Jika bisnis tertentu hanya mengizinkan integer quantity, application/domain validation dapat menetapkan:

quantity % 1 === 0

"Mengakali" Penggunaan Decimal di MongoDB dengan Prisma v6 Karena Decimal tidak didukung secara native di MongoDB pada Prisma, berikut beberapa pendekatan yang disebutkan dalam knowledge sources:

  1. Gunakan String sebagai pengganti Decimal (Rekomendasi Resmi) Prisma secara resmi menyarankan penggunaan String sebagai alternatif sementara:
model Product {
  id    String @id @default(auto()) @map("_id") @db.ObjectId
  price String // simpan nilai desimal sebagai string
}

Kekurangan: tidak bisa melakukan filtering/sorting/aggregasi langsung di database.


Tabel Rekomendasi Tipe Field Prisma

⚠️ Tabel ini dibuat berdasarkan knowledge sources yang tersedia. Beberapa rekomendasi (terutama untuk latitude, longitude, weight, height, length) tidak disebutkan secara eksplisit dalam knowledge sources — saya akan menandainya dengan asumsi berdasarkan karakteristik tipe data.

Nilai Uang (Money / Price)

DatabaseTipe PrismaAlasan
PostgreSQLDecimal (@db.Money atau @db.Decimal(p,s))Presisi tinggi, tidak ada floating-point error [Decimal reference]
MySQLDecimal (@db.Decimal(p,s))Sama seperti PostgreSQL, presisi terjamin [Decimal reference]
MongoDBString + Decimal.js atau BigInt (satuan terkecil)Decimal tidak didukung MongoDB [MongoDB mapping]
SQLiteDecimalDipetakan ke DECIMAL [Decimal reference]

Weight / Height / Length (Berat, Tinggi, Panjang)

⚠️ Tidak disebutkan secara eksplisit dalam knowledge sources. Rekomendasi berikut berdasarkan karakteristik tipe data Prisma.

DatabaseTipe PrismaAlasan
PostgreSQLDecimal (@db.Decimal(p,s))Presisi tinggi untuk nilai fisik (misal: 72.500 kg) [Decimal reference]
MySQLDecimal (@db.Decimal(p,s))Sama seperti PostgreSQL [Decimal reference]
MongoDBFloat (jika presisi tidak kritis) atau String + Decimal.jsDecimal tidak didukung [MongoDB mapping]
SQLiteDecimalDipetakan ke DECIMAL [Decimal reference]

Count / Quantity / Order (Jumlah, Kuantitas)

DatabaseTipe PrismaAlasan
PostgreSQLIntJumlah barang tidak perlu desimal, 32-bit cukup untuk kebanyakan kasus [Int reference]
MySQLIntSama seperti PostgreSQL [Int reference]
MongoDBIntDipetakan ke int MongoDB [MongoDB mapping]
SQLiteIntDipetakan ke INTEGER [Int reference]

Jika jumlah bisa sangat besar (misal total transaksi global), gunakan BigInt.

Sort / Urutan (Sort Order)

DatabaseTipe PrismaAlasan
PostgreSQLIntNilai urutan biasanya bilangan bulat kecil [Int reference]
MySQLIntSama seperti PostgreSQL [Int reference]
MongoDBIntDipetakan ke int MongoDB [MongoDB mapping]
SQLiteIntDipetakan ke INTEGER [Int reference]

Latitude / Longitude (Koordinat GPS)

⚠️ Tidak disebutkan secara eksplisit dalam knowledge sources. Rekomendasi berikut berdasarkan karakteristik tipe data Prisma.

DatabaseTipe PrismaAlasan
PostgreSQLFloat (@db.DoublePrecision)Koordinat GPS butuh ~15 digit presisi, double precision cukup. Tipe point belum didukung Prisma [PostgreSQL mapping]
MySQLFloatDipetakan ke DOUBLE
MongoDBFloatDipetakan ke double MongoDB [MongoDB mapping]
SQLiteFloatDipetakan ke REAL

Year (Tahun)

DatabaseTipe PrismaAlasan
PostgreSQLInt atau DateTimeInt jika hanya butuh tahun saja; DateTime jika butuh perbandingan/sorting waktu [PostgreSQL mapping]
MySQLInt (@db.Year)MySQL punya tipe native YEAR yang dipetakan ke Int [Int reference]
MongoDBIntTidak ada tipe YEAR native, Int paling sesuai [MongoDB mapping]
SQLiteIntDipetakan ke INTEGER [Int reference]

Ringkasan

Use CasePostgreSQLMySQLMongoDBSQLite
Nilai uangDecimalDecimalString/BigIntDecimal
Berat/Tinggi/PanjangDecimalDecimalFloat/StringDecimal
Count/QuantityIntIntIntInt
Sort orderIntIntIntInt
Latitude/LongitudeFloatFloatFloatFloat
TahunInt/DateTimeInt (@db.Year)IntInt