document.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. """主案、子方案和共享附件统一文档模型。"""
  2. from __future__ import annotations
  3. from datetime import datetime
  4. from sqlalchemy import (
  5. BigInteger,
  6. CheckConstraint,
  7. ForeignKey,
  8. Index,
  9. Integer,
  10. JSON,
  11. String,
  12. Text,
  13. text,
  14. )
  15. from sqlalchemy.orm import Mapped, mapped_column
  16. from sqlalchemy.dialects import mysql
  17. from dms.database.base import BusinessTableMixin
  18. from dms.extensions import db
  19. class Document(BusinessTableMixin, db.Model):
  20. __tablename__ = "doc_document"
  21. __table_args__ = (
  22. CheckConstraint(
  23. "document_type IN ('MAIN', 'SUB_PLAN', 'ATTACHMENT')",
  24. name="document_type",
  25. ),
  26. CheckConstraint(
  27. "document_status IN ('DRAFT', 'PUBLISHED', 'ARCHIVED')",
  28. name="document_status",
  29. ),
  30. CheckConstraint(
  31. "security_level IN "
  32. "('PUBLIC', 'INTERNAL', 'SECRET', 'CONFIDENTIAL', 'TOP_SECRET')",
  33. name="document_security_level",
  34. ),
  35. CheckConstraint(
  36. "visibility_type IN ('ALL_AUTHENTICATED', 'ORGANIZATION', 'CUSTOM')",
  37. name="document_visibility_type",
  38. ),
  39. CheckConstraint(
  40. "attachment_type IS NULL OR attachment_type IN "
  41. "('POLICY', 'WORK_STANDARD', 'TABLE', 'DIAGRAM', 'OTHER')",
  42. name="document_attachment_type",
  43. ),
  44. CheckConstraint(
  45. "content_extract_status IN "
  46. "('SUCCESS', 'EMPTY', 'UNSUPPORTED', 'FAILED')",
  47. name="document_content_extract_status",
  48. ),
  49. CheckConstraint(
  50. "("
  51. "document_type = 'MAIN' "
  52. "AND parent_document_id IS NULL "
  53. "AND category_id IS NOT NULL "
  54. "AND attachment_type IS NULL"
  55. ") OR ("
  56. "document_type = 'SUB_PLAN' "
  57. "AND parent_document_id IS NOT NULL "
  58. "AND root_document_id IS NOT NULL "
  59. "AND category_id IS NOT NULL "
  60. "AND attachment_type IS NULL"
  61. ") OR ("
  62. "document_type = 'ATTACHMENT' "
  63. "AND parent_document_id IS NULL "
  64. "AND root_document_id IS NULL "
  65. "AND category_id IS NULL "
  66. "AND attachment_type IS NOT NULL "
  67. "AND security_level = 'PUBLIC' "
  68. "AND visibility_type = 'ALL_AUTHENTICATED'"
  69. ")",
  70. name="document_type_shape",
  71. ),
  72. Index(
  73. "ix_doc_document_type_active_updated",
  74. "document_type",
  75. "is_deleted",
  76. "updated_at",
  77. ),
  78. Index(
  79. "ix_doc_document_parent_type_active",
  80. "parent_document_id",
  81. "document_type",
  82. "is_deleted",
  83. ),
  84. Index(
  85. "ix_doc_document_root_active",
  86. "root_document_id",
  87. "is_deleted",
  88. ),
  89. Index(
  90. "ix_doc_document_category_active",
  91. "category_id",
  92. "is_deleted",
  93. ),
  94. Index(
  95. "ix_doc_document_status_active",
  96. "document_status",
  97. "is_deleted",
  98. ),
  99. Index(
  100. "ix_doc_document_security_active",
  101. "security_level",
  102. "is_deleted",
  103. ),
  104. Index("ix_doc_document_file_hash", "file_hash"),
  105. Index(
  106. "ix_doc_document_creator_active",
  107. "created_by",
  108. "is_deleted",
  109. ),
  110. Index(
  111. "ix_doc_document_attachment_type_active_updated",
  112. "attachment_type",
  113. "is_deleted",
  114. "updated_at",
  115. ),
  116. Index(
  117. "ix_doc_document_file_extension_active_updated",
  118. "file_extension",
  119. "is_deleted",
  120. "updated_at",
  121. ),
  122. Index(
  123. "ix_doc_document_recycle_deleted",
  124. "is_deleted",
  125. "deleted_at",
  126. "id",
  127. ),
  128. )
  129. document_name: Mapped[str] = mapped_column(String(255), nullable=False)
  130. summary: Mapped[str | None] = mapped_column(Text, nullable=True)
  131. document_type: Mapped[str] = mapped_column(String(32), nullable=False)
  132. document_status: Mapped[str] = mapped_column(
  133. String(32),
  134. nullable=False,
  135. server_default=text("'DRAFT'"),
  136. )
  137. security_level: Mapped[str] = mapped_column(
  138. String(32),
  139. nullable=False,
  140. server_default=text("'INTERNAL'"),
  141. )
  142. visibility_type: Mapped[str] = mapped_column(
  143. String(32),
  144. nullable=False,
  145. server_default=text("'CUSTOM'"),
  146. )
  147. attachment_type: Mapped[str | None] = mapped_column(String(32), nullable=True)
  148. category_id: Mapped[int | None] = mapped_column(
  149. BigInteger,
  150. ForeignKey("doc_category.id", ondelete="RESTRICT"),
  151. nullable=True,
  152. )
  153. category_name: Mapped[str | None] = mapped_column(String(128), nullable=True)
  154. category_path: Mapped[str | None] = mapped_column(String(1000), nullable=True)
  155. parent_document_id: Mapped[int | None] = mapped_column(
  156. BigInteger,
  157. ForeignKey("doc_document.id", ondelete="RESTRICT"),
  158. nullable=True,
  159. )
  160. root_document_id: Mapped[int | None] = mapped_column(
  161. BigInteger,
  162. ForeignKey("doc_document.id", ondelete="RESTRICT"),
  163. nullable=True,
  164. )
  165. tags: Mapped[list[str] | None] = mapped_column(JSON, nullable=True)
  166. original_file_name: Mapped[str] = mapped_column(String(255), nullable=False)
  167. file_relative_path: Mapped[str] = mapped_column(String(1000), nullable=False)
  168. file_extension: Mapped[str] = mapped_column(String(20), nullable=False)
  169. mime_type: Mapped[str | None] = mapped_column(String(128), nullable=True)
  170. file_size: Mapped[int] = mapped_column(
  171. BigInteger,
  172. nullable=False,
  173. server_default=text("0"),
  174. )
  175. file_hash: Mapped[str] = mapped_column(String(64), nullable=False)
  176. child_count: Mapped[int] = mapped_column(
  177. Integer,
  178. nullable=False,
  179. server_default=text("0"),
  180. )
  181. attachment_count: Mapped[int] = mapped_column(
  182. Integer,
  183. nullable=False,
  184. server_default=text("0"),
  185. )
  186. view_count: Mapped[int] = mapped_column(
  187. BigInteger,
  188. nullable=False,
  189. server_default=text("0"),
  190. )
  191. download_count: Mapped[int] = mapped_column(
  192. BigInteger,
  193. nullable=False,
  194. server_default=text("0"),
  195. )
  196. search_text: Mapped[str | None] = mapped_column(mysql.LONGTEXT, nullable=True)
  197. content_text: Mapped[str | None] = mapped_column(mysql.LONGTEXT, nullable=True)
  198. content_extract_status: Mapped[str] = mapped_column(
  199. String(32),
  200. nullable=False,
  201. server_default=text("'UNSUPPORTED'"),
  202. )
  203. content_extracted_at: Mapped[datetime | None] = mapped_column(
  204. mysql.DATETIME(fsp=3),
  205. nullable=True,
  206. )
  207. created_by_name: Mapped[str | None] = mapped_column(String(64), nullable=True)
  208. updated_by_name: Mapped[str | None] = mapped_column(String(64), nullable=True)