الوثائق
قاعدة البيانات
استمرارية SQLite مع ملكية الاتصال المحددة النطاق، وفشل الاستعلام المكتوب، والنسخ الاحتياطية للترحيل، وتخزين المستندات المحلية.
مترجم تلقائيًا من الإنجليزية. عرض الأصل بالإنجليزية
نموذج الثبات
@cadcamfun/db يفتح SQLite من خلال bun:sqlite ويكشف عن قاعدة بيانات Drizzle داخل التأثير Database خدمة. يقوم Sidecar بتخزين قاعدة بيانات التطبيقات الخاصة به في <dataDir>/cadcamfun.db. يتيح الاتصال إمكانية تسجيل الكتابة المسبقة وفرض المفتاح الخارجي قبل تطبيق عمليات الترحيل.
تحتوي قاعدة البيانات على نسخة العمل من المشاريع والموارد ذات الصلة. يتم أيضًا تخزين كائنات التحكم في إصدار المشروع وطلبات السحب وعمليات سير العمل محليًا. تستخدم بيانات اعتماد موفر الذكاء الاصطناعي ملف JSON منفصلاً يمكن للمالك قراءته؛ يتم توفير الرمز المميز لحامل التطبيق عند الإطلاق بدلاً من استمراره كتفضيل.
المخطط ونقاط الدخول
packages/db/src/schema.ts يحدد الجداول والفهارس والعلاقات والافتراضيات وأنواع التحديد/الإدراج المستنتجة. src/index.ts صادرات Database, DatabaseError، الرذاذ Db النوع ومساحة اسم المخطط. src/upgrade.ts يمتلك تخطيط الترحيل والنسخ الاحتياطي وتطبيق المعاملات؛ src/migrate.ts هي نقطة دخول سطر الأوامر. يتم إنشاء SQL ومجلة الترحيل مباشرة packages/db/drizzle.
كل اتصال تم فتحه بواسطة packages/db/src/index.ts يقوم بتبديل SQLite إلى journal_mode = WAL ويتم تشغيله foreign_keys. إغلاق قاعدة البيانات يعمل wal_checkpoint(TRUNCATE) وبالتالي فإن الملف الرئيسي يكتمل عند انتهاء العملية. إذا كانت نقطة التفتيش مشغولة أو فاشلة، فسيتم تسجيل تحذير ويستمر إيقاف التشغيل.
القيم المخزنة
معرفات المجال الافتراضية هي UUIDs حيث يتم تكوينها بواسطة الجدول. يقوم Drizzle بتعيين أعمدة الطابع الزمني لتواريخ JavaScript وأعمدة JSON لأنواع السجلات المعلنة. تقوم مستودعات HTTP بتحويل التواريخ إلى تمثيلها السلكي والتحقق من صحة JSON عند حدود المجال. لا يثبت التعليق التوضيحي لنوع TypeScript في عمود JSON المُخزن في حد ذاته أن البيانات المستوردة أو الأقدم تطابق مخطط المجال الحالي.
مشاريع الرسومات والمكونات ومسارات الأدوات الخاصة. يمكن أن تشير مسارات الأدوات إلى الرسم والمواد والقاطع وتكوين الجهاز؛ هُم data يمكن أن يحمل الحقل وثيقة تصنيع محمولة. تحتفظ جداول إصدار الرسم والمكونات ومسار الأدوات المنفصلة بإصدارات الموارد بالإضافة إلى سجل Git للمشروع بأكمله.
الاستعلام من خلال الخدمة
Database.layer يقبل مسار الملف أو :memory:ومجلد ترحيل اختياري ودليل نسخ احتياطي اختياري. يكتسب مقبض SQLite لنطاق التأثير الخاص به. استخدام المتصلين query(operation, run) لتنفيذ عمل Drizzle المتزامن أو غير المتزامن؛ تصبح الاستثناءات الأجنبية DatabaseError مع اسم العملية والسبب الأصلي.
import { Database, schema } from "@cadcamfun/db"
import { Effect } from "effect"
const loadProjects = Effect.gen(function* () {
const database = yield* Database
return yield* database.query("projects.list", (db) =>
db.select().from(schema.projectTable).all())
}) تمتلك المستودعات قواعد الوصول وتفسير الصف؛ يوفر مساعد الاستعلام المشترك إسناد الفشل. ولا يسمح تلقائيًا باستعلام أو إنشاء معاملة حول تسلسل عشوائي لاستدعاءات الخدمة.
ترقية السلوك
يؤدي فتح طبقة بمجلد الترحيل إلى قراءة ملفات الترحيل ومقارنة أسمائها بها __drizzle_migrations. تتم إعادة تعبئة المجلة من التنسيق الأقدم عن طريق مطابقة الطوابع الزمنية للترحيل والتجزئة. تفشل دفتر يومية غير قابل للمطابقة في الترقية بدلاً من تخمين هوية الترحيل.
عندما تحتاج قاعدة بيانات موجودة على القرص إلى ترقية، تقوم الخدمة بإنشاء نسخة احتياطية من SQLite قبل الترحيل باستخدام VACUUM INTO. فهو يكتب إلى ملف جزئي، ويعيد تسمية اللقطة المكتملة، ويحتفظ بأحدث خمس نسخ احتياطية مطابقة لمرحلة ما قبل الترحيل. دليل النسخ الاحتياطي الافتراضي هو backups بجانب قاعدة البيانات. لا تحتاج قواعد البيانات الجديدة والموجودة في الذاكرة إلى هذا النسخ الاحتياطي للترقية المسبقة.
يتم تشغيل تغييرات دفتر اليومية وعبارات SQL المعلقة في معاملة فورية واحدة. تؤدي عملية الترحيل الفاشلة إلى إرجاع المعاملة مرة أخرى وفشل إنشاء الطبقة. يجب ألا يعلن التطبيق عن جاهزيته عند فشل تهيئة قاعدة البيانات.
أوامر الهجرة
bun run db:generate
bun run db:migrate توليد الهجرات بعد التغيير schema.ts، واحتفظ بـ SQL والمجلة التي تم إنشاؤها معًا. يستخدم واجهة سطر الأوامر (CLI) الخاصة بالترحيل DATABASE_URL عند توفيره، يزيل الأولي file: البادئة، ويفتح خلاف ذلك ./data/cadcamfun.db. يقوم برنامج تضمين الجذر بتشغيل هذا البرنامج النصي باستخدام packages/db كدليل العمل الخاص به، لذا فإن هدفه الافتراضي هو packages/db/data/cadcamfun.db. يستخدم ويب ستوديو data/cadcamfun.db في جذر المستودع. تستخدم السايدكار المعبأة CADCAMFUN_DATA_DIR. حدد مسارًا واضحًا لقاعدة البيانات عند تشغيل الصيانة حتى لا تعمل نقاط الإدخال هذه على ملفات مختلفة دون قصد.
بدون مجلد الترحيل، Database.layer يفتح قاعدة البيانات ولكن لا يقوم بإنشاء جداول التطبيق. تزود الاختبارات التي تحتاج إلى المخطط الكامل دليل الترحيل بقاعدة بيانات في الذاكرة.
مجالات البيانات
- الهوية والتعاون: المستخدمون، والحسابات، والجلسات، والمصادقون، ورموز التحقق، والاشتراكات، والمؤسسات، والعضوية، والدعوات، والمحادثات، والرسائل، والإشعارات، والاشتراكات المباشرة.
- التصميم والتصنيع: المشاريع والرسومات والمكونات وإصداراتها وتعليقاتها والمواد والأدوات وتكوينات الآلة ومسارات الأدوات وسجلات تكلفة الإنتاج.
- خدمات التطبيق: الملفات وعناصر المكتبة وتسجيل/تكوين المكونات الإضافية ومفاتيح واجهة برمجة التطبيقات والتحليلات وسجلات الأنشطة وبيانات السوق وتكوين MCP وإدخالات القيمة الرئيسية المحلية.
- تاريخ المشروع: مستودعات Git، والكائنات والمراجع، وطلبات السحب والمراجعات، وتشغيل سير العمل.
ينشئ وجود الجدول نموذجًا للاستمرارية. تعتمد عمليات تكامل الشبكة وميزات التطبيق على معالجاتها وخدماتها الفعلية، وليس على وجودها على الطاولة وحده.
تخزين قيمة المفتاح المحلي
LocalKeyValue استمرار حالة التطبيق المتوافقة مع JSON. السايدكار KvStore يدعم الحصول على القائمة وتصفيتها وحذفها وتصفيتها بالبادئة. يجب أن تحتوي المفاتيح على نص بدون مسافة بيضاء وأن تكون 512 حرفًا على الأكثر. تسمح القيم بالقيم الخالية، والسلاسل، والقيم المنطقية، والأرقام المحدودة، والمصفوفات، والكائنات العادية؛ يتم رفض الدورات والوظائف والأرقام غير المحدودة والكائنات غير العادية.
تتضمن الإدخالات طابعًا زمنيًا للتحديث. Upserts تحل محل القيمة لنفس المفتاح. يتم فرز قائمة البادئات حسب المفتاح والمرشحات في الذاكرة. استخدم هذا المتجر للتفضيلات والسياق المساعد؛ تنتمي بيانات الاعتماد إلى خدمة بيانات الاعتماد المخصصة لهم.
الاغلاق والانتعاش
طلبات اللمسات النهائية لنطاق قاعدة البيانات PRAGMA wal_checkpoint(TRUNCATE) قبل إغلاق المقبض. يتم تسجيل نقطة تفتيش مزدحمة أو فشل إغلاق كتحذير حتى يمكن تشغيل أدوات الإنهاء المتبقية. يقوم مالك الاتصال، وليس معالجات HTTP الفردية، بإغلاق المقبض.
للحصول على نسخة احتياطية يدوية متسقة، قم بإيقاف التطبيق بشكل نظيف قبل نسخ دليل البيانات الخاص به، أو استخدم مرافق النسخ الاحتياطي الخاصة بـ SQLite أثناء تشغيله. يمكن أن تحتوي قاعدة البيانات المباشرة على حالة في ملف WAL الخاص بها. لفحص النسخة الاحتياطية قبل الترحيل، اعمل على نسخة واحتفظ بقاعدة البيانات الأصلية والنسخ الاحتياطية حتى يتم تأكيد الاسترداد.
مسؤوليات المستودع
احتفظ بإنشاء اتصال SQLite ومنطق الترحيل في هذه الحزمة. تستخدم مستودعات Sidecar خدمة قاعدة البيانات المتوفرة وتعيين فشل التخزين لأخطاء HTTP الخاصة بموردها. احتفظ بالحسابات الهندسية في المركز والأسرار في خدمات بيانات الاعتماد أو الرمز المميز. تحتوي النسخ الاحتياطية لقاعدة البيانات على بيانات المشروع والحساب وتحتاج إلى نفس عناصر التحكم في الوصول مثل دليل البيانات النشط.
فحص قاعدة البيانات دون تغييرها
بعد إيقاف التشغيل النظيف، استخدم SQLite CLI مقابل مسار قاعدة بيانات واضح. يتجنب وضع القراءة فقط إنشاء ملف فارغ جديد عن طريق الخطأ عندما يكون المسار خاطئًا. تقوم عمليات التحقق هذه بفحص البنية والاتساق دون الكشف عن صفوف الحساب أو بيانات الاعتماد.
sqlite3 -readonly /absolute/path/cadcamfun.db 'PRAGMA quick_check;'
sqlite3 -readonly /absolute/path/cadcamfun.db 'PRAGMA foreign_key_check;'
sqlite3 -readonly /absolute/path/cadcamfun.db "SELECT name FROM sqlite_master WHERE type = 'table' ORDER BY name;"
sqlite3 -readonly /absolute/path/cadcamfun.db 'SELECT name, applied_at FROM __drizzle_migrations ORDER BY id;' quick_check تقارير عادة ok; foreign_key_check إرجاع الصفوف فقط للانتهاكات. مجلة بدون name/applied_at تعد الأعمدة تنسيقًا قديمًا، ويجب أن يتم التوفيق بين رمز ترقية التطبيق قبل استخدام الاستعلام الأخير. تحقق من المسارات وهوية الترحيل قبل محاولة الإصلاحات.
يقوم التطبيق بتعيين فرض المفتاح الخارجي على اتصاله الخاص. يجب أن يقوم اتصال الصيانة المفتوح بشكل منفصل بتمكينه بشكل صريح قبل إجراء عمليات الكتابة المعتمدة؛ PRAGMA خاص بالاتصال.
مصدر: packages/db/src/index.ts, upgrade.ts، و database.test.ts.
استخدم قاعدة بيانات يمكن التخلص منها في التعليمات البرمجية
يعد نطاق الخدمة الكامل داخل الذاكرة مفيدًا لأمثلة المستودعات والتشخيصات المعزولة. يمتلك النطاق الاتصال ويطبق عمليات الترحيل المسجلة قبل أن يقرأ التأثير الخدمة.
import { Database, schema } from "@cadcamfun/db"
import { Effect } from "effect"
const migrationsFolder = new URL("../../packages/db/drizzle", import.meta.url).pathname
const program = Effect.gen(function* () {
const database = yield* Database
return yield* database.query("diagnostic.projects", (db) =>
db.select({ id: schema.projectTable.id }).from(schema.projectTable).all())
}).pipe(Effect.provide(Database.layer({ path: ":memory:", migrationsFolder })))
console.log(await Effect.runPromise(program)) // [] احفظ هذا البرنامج النصي باسم apps/sidecar/diagnostic.ts وتشغيل bun apps/sidecar/diagnostic.ts من جذر المستودع. توفر هذه الحزمة قاعدة البيانات وتبعيات التأثير، ويتم حل عنوان URL للترحيل من هذا الملف. دليل الترحيل المفقود أو الخاطئ لا يعادل مخطط تطبيق فارغ. الرذاذ query قد يقوم رد الاتصال بتشغيل استعلام متزامن أو إرجاع وعد؛ يقوم المساعد بتغليف حالات الفشل تحت ملصق العملية المرفق.
مصدر: packages/db/src/database.test.ts و index.ts.
تشخيص فشل التخزين
- لا يوجد مثل هذا الجدول: قم بتأكيد ملف قاعدة البيانات ومجلد الترحيل الدقيق. تسمح الخدمة بالفتح بدون عمليات ترحيل، ولكن يفشل الاستعلام عن جداول التطبيق بعد ذلك.
- فشل قيد المفتاح الخارجي: افحص المالك/المشروع/المورد المشار إليه. قيود الحذف خاصة بالمخطط: يتم تقييد حذف مستخدم لديه مشروع مملوك، بينما تتسلسل صفوف الجلسة عند حذف المستخدم.
- فشل النسخ الاحتياطي أثناء الترقية: تحقق من المساحة الحرة وحق الوصول للكتابة في قاعدة البيانات وأدلة النسخ الاحتياطي. فشل النسخ الاحتياطي يوقف الترحيل؛ لا تقم بحذف قاعدة البيانات الأصلية لتجاوزها.
- لا يتطابق دفتر يومية الترحيل القديم مع عمليات الترحيل المحلية: الحفاظ على قاعدة البيانات واستعادة مجموعة الترحيل المطابقة. قد تؤدي إعادة تسمية صفوف دفتر اليومية أو إزالتها إلى إخفاء سجل الترقية غير المتوافق.
- نقطة التفتيش مشغولة عند إيقاف التشغيل: افحص الاتصالات المفتوحة الأخرى قبل نسخ ملف قاعدة البيانات فقط. احتفظ بإخوة WAL/SHM حتى تكتمل نقطة تفتيش نظيفة أو نسخة احتياطية متسقة من SQLite.
تعد النسخ الاحتياطية للترحيل بمثابة نقاط استرداد للترقية المسبقة مع سياسة الاحتفاظ بخمسة ملفات، وليست نسخًا احتياطيًا مستمرًا للتعديلات اللاحقة. قم بعمل نسخة احتياطية من دليل البيانات الكامل بشكل منفصل وفقًا لمتطلبات استرداد التثبيت.
مصدر: packages/db/src/index.ts, upgrade.ts, schema.ts، و database.test.ts.
تاريخ الهجرة
يتم تطبيق عمليات الترحيل التي تم تسجيلها بترتيب المجلدات. يحمل كل مجلد أ migration.sql ومجموعة الرذاذ snapshot.json تستخدم لحساب الفرق التالي. يقوم صف دفتر اليومية بتخزين اسم المجلد وتجزئته والطابع الزمني للمجلد بالمللي ثانية (created_at)، ووقت ISO الذي تم تطبيقه فيه (applied_at).
| مجلد | مقاس | ما يخلق |
|---|---|---|
20261004223029_careful_monster_badoon | 771 سطر | تم تحويل المخطط الأساسي من نموذج Prisma القديم: الهوية والمؤسسات والمشاريع والرسومات والمكونات ومسارات الأدوات والمكتبات والتكاليف والسوق والمكونات الإضافية وتكوين MCP. لم تتغير أسماء الجداول والأعمدة منذ ذلك الحين dev.db تبقى البيانات قابلة للقراءة. |
20261008030518_redundant_dagger | 73 سطر | تاريخ المشروع: GitRepo, GitObject, GitRef, PullRequest, PullRequestReview, WorkflowRun. |
20261009012351_moaning_loki | 28 سطر | سجلات نواة الهندسة: MeshAsset و CadOperationLog. |
20261009171602_brown_mad_thinker | 5 سطر | LocalKeyValue (key المفتاح الأساسي للنص, value النص ليس فارغا، updatedAt عدد صحيح وليس فارغًا). |
تأتي أسماء المجلدات من drizzle-kit: طابع زمني بالتوقيت العالمي المنسق (UTC) متبوعًا باسم عشوائي. لا تقم مطلقًا بإعادة تسمية مجلد أو تحريره بمجرد تطبيقه في أي مكان؛ يحدد مخطط الترقية عمليات الترحيل المطبقة بالاسم، وبالنسبة للمجلات القديمة، حسب الطابع الزمني والتجزئة.
ترقية تدفق القرار
| الموقف | النسخ الاحتياطي | نتيجة |
|---|---|---|
| ملف جديد، تم توفير مجلد الترحيل | لا (الملف لم يكن موجودا قبل فتحه) | يتم تطبيق كافة عمليات الترحيل في معاملة واحدة |
| الملف موجود، دفتر اليومية محدث | لا | مفتوح كما هو؛ needed غير صحيح |
| الملف الموجود، في انتظار عمليات الترحيل | نعم قبل أي تغيير | تم تطبيق عمليات الترحيل المعلقة؛ تم إدراج صفوف دفتر اليومية مع applied_at |
الملف موجود، مجلة بدون name عمود | نعم | أعمدة name و applied_at تمت إضافتها، وتم ملء الصفوف، ثم تم تطبيق عمليات الترحيل المعلقة |
| لا يتطابق الصف القديم مع أي ترحيل محلي | لا يتم أخذ نسخة احتياطية: يفشل التخطيط أولاً | DatabaseError مع العملية migrate: "مجلة الترحيل القديمة لا تتطابق مع عمليات الترحيل المحلية" |
:memory: | أبداً | يتم تطبيق عمليات الترحيل في حالة إعطاء مجلد |
| لا يوجد مجلد للهجرات | أبداً | تم فتحه بدون إنشاء الجداول |
تعمل مطابقة إعادة التعبئة على النحو التالي: الصفوف القديمة created_at يتم اقتطاعه إلى ثوانٍ كاملة ومقارنته بالطابع الزمني لمجلد كل عملية ترحيل. إذا تطابقت عملية ترحيل واحدة بالضبط، فسيتم استخدامها. وإلا فإن التجزئة ستكسر التعادل، وكحل أخير يتم استخدام أي ترحيل بنفس التجزئة.
تشريح ملف النسخ الاحتياطي
backups/cadcamfun-20261015-034512.123-6f1c2d4e-8a90-4b7c-9e21-3f5a6b7c8d9e-pre-migrate.db
└ prefix ┘ └ UTC timestamp ┘ └ random UUID ┘ - البادئة هي اسم ملف قاعدة البيانات بدون
.db، متبوعة بشرطة. - الطابع الزمني هو UTC بدقة مللي ثانية. إذا كانت أحدث نسخة احتياطية موجودة لها نفس الطابع الزمني أو طابع زمني لاحق، فسيتم تعيين الطابع الجديد بـ 1 مللي ثانية بعده، وبالتالي فإن الترتيب المعجمي يساوي دائمًا ترتيب الإنشاء.
- اللقطة مكتوبة على
<name>.partialمعVACUUM INTO، ثم أعيدت تسميتها. يترك الحادث على الأكثر أ.partialالملف الذي تتم إزالته في ملفfinallyحاجز. - بعد إجراء نسخ احتياطي ناجح، يتم الاحتفاظ فقط بالملفات الخمسة الأحدث المطابقة للنمط الدقيق. لن يتم حذف الملفات التي تنسخها إلى الدليل بأسماء أخرى أبدًا.
VACUUM INTOتنتج قاعدة بيانات مدمجة ومكتفية ذاتيًا بدون وجود شقيق لـ WAL، بحيث يمكن فتح نسخة احتياطية مباشرة.
DATA="/absolute/path/to/data"
cp "$DATA/cadcamfun.db" "$DATA/cadcamfun.db.broken" # keep the failed state
rm -f "$DATA/cadcamfun.db-wal" "$DATA/cadcamfun.db-shm"
cp "$DATA/backups/cadcamfun-<timestamp>-<uuid>-pre-migrate.db" "$DATA/cadcamfun.db"
sqlite3 -readonly "$DATA/cadcamfun.db" 'PRAGMA quick_check;' # expect: ok استعادة التراجع عن المخطط والبيانات
النسخة الاحتياطية المستعادة هي الحالة التي كانت موجودة قبل الترقية مباشرةً. لا تتضمن التعديلات التي تم إجراؤها بعد تلك الترقية، وسيحاول الإطلاق التالي إجراء نفس الترحيل مرة أخرى. قم بإصلاح سبب الفشل قبل إعادة التشغيل.
أشكال الجدول الأساسية
هذه هي الجداول التي يقرأها محرر سطح المكتب والسجل والنواة في أغلب الأحيان. أسماء الأعمدة هي أسماء SQL؛ يعرضهم Drizzle تحت نفس المفاتيح.
| طاولة | أعمدة |
|---|---|
Project | id, name, description, createdAt, updatedAt, ownerId, organizationId, isPublic |
Drawing | id, name, description, data, thumbnail, createdAt, updatedAt, projectId |
Component | id, name, description, data, thumbnail, type, isPublic, createdAt, updatedAt, projectId |
Toolpath | id, name, description, data, type, operationType, gcode, thumbnail, isPublic, projectId, createdAt, updatedAt, createdBy, drawingId, materialId, toolId, machineConfigId |
GitRepo | projectId, head, remote, createdAt |
GitObject | projectId, oid, type, body |
GitRef | projectId, name, oid |
PullRequest | id, projectId, number, title, body, head, base, state, authorId, authorKind, mergeCommit, remoteNumber, createdAt, updatedAt |
WorkflowRun | id, projectId, workflow, event, ref, sha, status, events, startedAt, finishedAt |
MeshAsset | id, projectId, kind, inputs, stats, mesh, createdAt |
CadOperationLog | id, projectId, operation, meshAssetId, outcome, durationMs, inputs, error, traceId, spanId, createdAt |
LocalKeyValue | key, value, updatedAt |
يؤدي حذف المشروع إلى إزالة الرسومات والمكونات ومسارات الأدوات وكائنات السجل والمراجع وطلبات السحب وعمليات سير العمل وأصول الشبكة وسجلات التشغيل. تتالي صفوف الإصدار والتعليق من المورد الأصلي الخاص بها. أ CadOperationLog نجا الصف بعد حذف أصول الشبكة الخاصة به meshAssetId تم ضبطه على قيمة فارغة. لا تحتوي روابط مسار الأدوات للمواد والأدوات وتكوينات الماكينة على سلسلة متتالية، لذلك لا يمكن حذف المادة المرجعية عندما يشير مسار الأدوات إليها.
كتالوج الجدول الكامل
يحدد المخطط 60 الجداول. تم إنتاج القائمة أدناه من تعريفات جدول Drizzle: اسم SQL، والثابت المصدر، وعدد الأعمدة، وعدد الفهارس المعلنة، والمفاتيح الخارجية مع قاعدة الحذف الخاصة بها. "لا يوجد إجراء" هو الإعداد الافتراضي لـ SQLite: يفشل الحذف أثناء وجود الصفوف المرجعية (يتم فرض المفاتيح الخارجية على اتصال التطبيق).
| جدول SQL | يصدّر | كولز | معرفكس | مفاتيح خارجية |
|---|---|---|---|---|
Account | accountTable | 13 | 1 | userId → المستخدم (تتالي) |
ActivityLog | activityLogTable | 7 | 0 | userId → المستخدم (لا يوجد إجراء) |
AIAnalysisLog | aIAnalysisLogTable | 7 | 0 | userId → المستخدم (لا يوجد إجراء) |
ApiKey | apiKeyTable | 7 | 1 | userId → المستخدم (تتالي) |
authenticators | authenticatorTable | 8 | 0 | userId → المستخدم (تتالي) |
CadOperationLog | cadOperationLogTable | 11 | 1 | projectId → المشروع (تتالي)meshAssetId → MeshAsset (تعيين فارغ) |
Component | componentTable | 10 | 0 | projectId → المشروع (تتالي) |
ComponentComment | componentCommentTable | 6 | 0 | componentId → المكون (تتالي)userId → المستخدم (لا يوجد إجراء) |
ComponentVersion | componentVersionTable | 6 | 0 | componentId → المكون (تتالي)userId → المستخدم (لا يوجد إجراء) |
Conversation | conversationTable | 6 | 0 | organizationId → المنظمة (تتالي) |
ConversationParticipant | conversationParticipantTable | 5 | 1 | userId → المستخدم (تتالي)conversationId → المحادثة (تتالي) |
CostSettings | costSettingsTable | 11 | 0 | ownerId → المستخدم (لا يوجد إجراء)organizationId → المنظمة (لا يوجد إجراء) |
Drawing | drawingTable | 8 | 0 | projectId → المشروع (تتالي) |
DrawingVersion | drawingVersionTable | 5 | 0 | drawingId → الرسم (تتالي) |
FileUpload | fileUploadTable | 12 | 0 | — |
GitObject | gitObjectTable | 4 | 1 | projectId → المشروع (تتالي) |
GitRef | gitRefTable | 3 | 1 | projectId → المشروع (تتالي) |
GitRepo | gitRepoTable | 4 | 0 | projectId → المشروع (تتالي) |
LibraryItem | libraryItemTable | 14 | 0 | ownerId → المستخدم (لا يوجد إجراء)organizationId → المنظمة (لا يوجد إجراء) |
LocalKeyValue | localKeyValueTable | 3 | 0 | — |
MachineConfig | machineConfigTable | 9 | 0 | ownerId → المستخدم (لا يوجد إجراء) |
MarketplaceCategory | marketplaceCategoryTable | 10 | 1 | parentId → فئة السوق (لا يوجد إجراء) |
MarketplaceCollection | marketplaceCollectionTable | 10 | 1 | sellerId → MarketplaceSeller (لا يوجد إجراء) |
MarketplaceCollectionItem | marketplaceCollectionItemTable | 5 | 1 | collectionId → مجموعة Marketplace (تتالي)itemId → عنصر السوق (تتالي) |
MarketplaceItem | marketplaceItemTable | 30 | 5 | sellerId → MarketplaceSeller (لا يوجد إجراء) |
MarketplaceOrder | marketplaceOrderTable | 23 | 4 | buyerId → المستخدم (لا يوجد إجراء)sellerId → MarketplaceSeller (لا يوجد إجراء)itemId → عنصر السوق (لا يوجد إجراء) |
MarketplacePayout | marketplacePayoutTable | 12 | 1 | sellerId → MarketplaceSeller (لا يوجد إجراء) |
MarketplaceReview | marketplaceReviewTable | 12 | 2 | itemId → عنصر السوق (لا يوجد إجراء)buyerId → المستخدم (لا يوجد إجراء)orderId → طلب السوق (لا يوجد إجراء) |
MarketplaceSeller | marketplaceSellerTable | 19 | 0 | userId → المستخدم (لا يوجد إجراء) |
MarketplaceWishlist | marketplaceWishlistTable | 4 | 1 | userId → المستخدم (تتالي)itemId → عنصر السوق (تتالي) |
Material | materialTable | 9 | 0 | ownerId → المستخدم (لا يوجد إجراء)organizationId → المنظمة (لا يوجد إجراء) |
MaterialCost | materialCostTable | 10 | 0 | materialId → المادة (سلسلة)ownerId → المستخدم (لا يوجد إجراء)organizationId → المنظمة (لا يوجد إجراء) |
MCPServerConfig | mCPServerConfigTable | 11 | 1 | — |
MeshAsset | meshAssetTable | 7 | 1 | projectId → المشروع (تتالي) |
Message | messageTable | 8 | 1 | senderId → المستخدم (تتالي)conversationId → المحادثة (تتالي)fileId → تحميل الملف (تعيين فارغ) |
Notification | notificationTable | 12 | 0 | userId → المستخدم (تتالي)organizationId → المنظمة (تتالي)projectId → المشروع (تتالي)componentId → المكون (تتالي)messageId → الرسالة (تتالي) |
OperationCost | operationCostTable | 10 | 0 | ownerId → المستخدم (لا يوجد إجراء)organizationId → المنظمة (لا يوجد إجراء) |
Organization | organizationTable | 5 | 0 | — |
OrganizationInvitation | organizationInvitationTable | 7 | 0 | organizationId → المنظمة (تتالي) |
passkey | passkeyTable | 11 | 0 | userId → المستخدم (تتالي) |
PluginConfiguration | pluginConfigurationTable | 2 | 0 | pluginId → PluginRegistryEntry (تتالي) |
PluginRegistryEntry | pluginRegistryEntryTable | 9 | 0 | — |
ProductionCostEstimate | productionCostEstimateTable | 17 | 0 | toolpathId → مسار الأدوات (تتالي)operationCostId → تكلفة العملية (لا يوجد إجراء)ownerId → المستخدم (لا يوجد إجراء)organizationId → المنظمة (لا يوجد إجراء) |
Project | projectTable | 8 | 0 | ownerId → المستخدم (لا يوجد إجراء)organizationId → المنظمة (لا يوجد إجراء) |
PullRequest | pullRequestTable | 14 | 1 | projectId → المشروع (تتالي)authorId → المستخدم (لا يوجد إجراء) |
PullRequestReview | pullRequestReviewTable | 8 | 1 | pullRequestId → طلب السحب (تتالي)reviewerId → المستخدم (لا يوجد إجراء) |
PushSubscription | pushSubscriptionTable | 6 | 0 | userId → المستخدم (تتالي) |
Session | sessionTable | 8 | 0 | userId → المستخدم (تتالي) |
Subscription | subscriptionTable | 24 | 3 | referenceId → المستخدم (تتالي) |
Token | tokenTable | 8 | 2 | userId → المستخدم (تتالي) |
Tool | toolTable | 17 | 0 | ownerId → المستخدم (لا يوجد إجراء)organizationId → المنظمة (لا يوجد إجراء) |
Toolpath | toolpathTable | 17 | 0 | projectId → المشروع (تتالي)createdBy → المستخدم (لا يوجد إجراء)drawingId → الرسم (بدون إجراء)materialId → المادة (لا يوجد إجراء)toolId → الأداة (لا يوجد إجراء)machineConfigId → MachineConfig (لا يوجد إجراء) |
ToolpathComment | toolpathCommentTable | 6 | 0 | toolpathId → مسار الأدوات (تتالي)userId → المستخدم (لا يوجد إجراء) |
ToolpathVersion | toolpathVersionTable | 7 | 0 | toolpathId → مسار الأدوات (تتالي)userId → المستخدم (لا يوجد إجراء) |
ToolWearCost | toolWearCostTable | 10 | 0 | toolId → الأداة (تتالي)ownerId → المستخدم (لا يوجد إجراء)organizationId → المنظمة (لا يوجد إجراء) |
twoFactor | twoFactorTable | 4 | 0 | userId → المستخدم (تتالي) |
User | userTable | 17 | 0 | — |
UserOrganization | userOrganizationTable | 5 | 1 | userId → المستخدم (تتالي)organizationId → المنظمة (تتالي) |
verification_tokens | verificationTokenTable | 3 | 1 | — |
WorkflowRun | workflowRunTable | 10 | 1 | projectId → المشروع (تتالي) |
الكتابة بأمان
- قم بلف تغييرات البيانات المتعددة في معاملة Drizzle داخل واحدة
queryيتصل:database.query("op", (db) => db.transaction((tx) => ...)). متفرقqueryالمكالمات هي معاملات منفصلة. - قم بتسمية كل استعلام باسم عملية منقط وثابت (
projects.list,toolpaths.update). وهو السياق الوحيد أDatabaseErrorيحمل إلى جانب السبب، ويظهر في السجلات. - توليد معرفات مع
newId()(uUID) أو دع العمود الافتراضي يفعل ذلك؛ لا تبني معرفات من الأسماء. - التحقق من صحة أعمدة JSON عند قراءتها. لم يتم التحقق من نوع TypeScript المعلن بواسطة SQLite.
- يستخدم
LocalKeyValueمن خلال خدمة قيمة المفتاح السايدكار بدلاً من كتابة الصفوف مباشرة، لذلك يتم تطبيق التحقق من صحة المفتاح والقيمة.
import { Database, schema } from "@cadcamfun/db"
import { eq } from "drizzle-orm"
import { Effect } from "effect"
const renameProject = (id: string, name: string) => Effect.gen(function* () {
const database = yield* Database
return yield* database.query("projects.rename", (db) =>
db.transaction((tx) => {
const updated = tx.update(schema.projectTable)
.set({ name, updatedAt: new Date() })
.where(eq(schema.projectTable.id, id))
.returning().all()
if (updated.length === 0) throw new Error(`project ${id} not found`)
return updated[0]
}))
}) لإنشاء صفوف بمعرفات صريحة، استخدم schema.newId(); @cadcamfun/db يعيد تصدير وحدة المخطط كـ schema مساحة الاسم، وليس كأسماء المستوى الأعلى.