Schedule posts to Bluesky with Cloudflare workers. skyscheduler.work
cf tool bsky-tool cloudflare bluesky schedule bsky service social-media cloudflare-workers

more db improvements

drop unused index, comment the other indexes. use select distinct

+729 -16
+1
migrations/0012_reflective_ogun.sql
··· 1 + DROP INDEX `scheduledDate_idx`;
+705
migrations/meta/0012_snapshot.json
··· 1 + { 2 + "version": "6", 3 + "dialect": "sqlite", 4 + "id": "87a69bf8-f8c0-48e2-be3f-9b83db7dfc04", 5 + "prevId": "3d0b193e-28cc-4b00-960f-e0b3d822ab7d", 6 + "tables": { 7 + "accounts": { 8 + "name": "accounts", 9 + "columns": { 10 + "id": { 11 + "name": "id", 12 + "type": "text", 13 + "primaryKey": true, 14 + "notNull": true, 15 + "autoincrement": false 16 + }, 17 + "account_id": { 18 + "name": "account_id", 19 + "type": "text", 20 + "primaryKey": false, 21 + "notNull": true, 22 + "autoincrement": false 23 + }, 24 + "provider_id": { 25 + "name": "provider_id", 26 + "type": "text", 27 + "primaryKey": false, 28 + "notNull": true, 29 + "autoincrement": false 30 + }, 31 + "user_id": { 32 + "name": "user_id", 33 + "type": "text", 34 + "primaryKey": false, 35 + "notNull": true, 36 + "autoincrement": false 37 + }, 38 + "access_token": { 39 + "name": "access_token", 40 + "type": "text", 41 + "primaryKey": false, 42 + "notNull": false, 43 + "autoincrement": false 44 + }, 45 + "refresh_token": { 46 + "name": "refresh_token", 47 + "type": "text", 48 + "primaryKey": false, 49 + "notNull": false, 50 + "autoincrement": false 51 + }, 52 + "id_token": { 53 + "name": "id_token", 54 + "type": "text", 55 + "primaryKey": false, 56 + "notNull": false, 57 + "autoincrement": false 58 + }, 59 + "access_token_expires_at": { 60 + "name": "access_token_expires_at", 61 + "type": "integer", 62 + "primaryKey": false, 63 + "notNull": false, 64 + "autoincrement": false 65 + }, 66 + "refresh_token_expires_at": { 67 + "name": "refresh_token_expires_at", 68 + "type": "integer", 69 + "primaryKey": false, 70 + "notNull": false, 71 + "autoincrement": false 72 + }, 73 + "scope": { 74 + "name": "scope", 75 + "type": "text", 76 + "primaryKey": false, 77 + "notNull": false, 78 + "autoincrement": false 79 + }, 80 + "password": { 81 + "name": "password", 82 + "type": "text", 83 + "primaryKey": false, 84 + "notNull": false, 85 + "autoincrement": false 86 + }, 87 + "created_at": { 88 + "name": "created_at", 89 + "type": "integer", 90 + "primaryKey": false, 91 + "notNull": true, 92 + "autoincrement": false, 93 + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" 94 + }, 95 + "updated_at": { 96 + "name": "updated_at", 97 + "type": "integer", 98 + "primaryKey": false, 99 + "notNull": true, 100 + "autoincrement": false 101 + } 102 + }, 103 + "indexes": { 104 + "accounts_userId_idx": { 105 + "name": "accounts_userId_idx", 106 + "columns": [ 107 + "user_id" 108 + ], 109 + "isUnique": false 110 + } 111 + }, 112 + "foreignKeys": { 113 + "accounts_user_id_users_id_fk": { 114 + "name": "accounts_user_id_users_id_fk", 115 + "tableFrom": "accounts", 116 + "tableTo": "users", 117 + "columnsFrom": [ 118 + "user_id" 119 + ], 120 + "columnsTo": [ 121 + "id" 122 + ], 123 + "onDelete": "cascade", 124 + "onUpdate": "no action" 125 + } 126 + }, 127 + "compositePrimaryKeys": {}, 128 + "uniqueConstraints": {}, 129 + "checkConstraints": {} 130 + }, 131 + "sessions": { 132 + "name": "sessions", 133 + "columns": { 134 + "id": { 135 + "name": "id", 136 + "type": "text", 137 + "primaryKey": true, 138 + "notNull": true, 139 + "autoincrement": false 140 + }, 141 + "expires_at": { 142 + "name": "expires_at", 143 + "type": "integer", 144 + "primaryKey": false, 145 + "notNull": true, 146 + "autoincrement": false 147 + }, 148 + "token": { 149 + "name": "token", 150 + "type": "text", 151 + "primaryKey": false, 152 + "notNull": true, 153 + "autoincrement": false 154 + }, 155 + "created_at": { 156 + "name": "created_at", 157 + "type": "integer", 158 + "primaryKey": false, 159 + "notNull": true, 160 + "autoincrement": false, 161 + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" 162 + }, 163 + "updated_at": { 164 + "name": "updated_at", 165 + "type": "integer", 166 + "primaryKey": false, 167 + "notNull": true, 168 + "autoincrement": false 169 + }, 170 + "ip_address": { 171 + "name": "ip_address", 172 + "type": "text", 173 + "primaryKey": false, 174 + "notNull": false, 175 + "autoincrement": false 176 + }, 177 + "user_agent": { 178 + "name": "user_agent", 179 + "type": "text", 180 + "primaryKey": false, 181 + "notNull": false, 182 + "autoincrement": false 183 + }, 184 + "user_id": { 185 + "name": "user_id", 186 + "type": "text", 187 + "primaryKey": false, 188 + "notNull": true, 189 + "autoincrement": false 190 + } 191 + }, 192 + "indexes": { 193 + "sessions_token_unique": { 194 + "name": "sessions_token_unique", 195 + "columns": [ 196 + "token" 197 + ], 198 + "isUnique": true 199 + }, 200 + "sessions_userId_idx": { 201 + "name": "sessions_userId_idx", 202 + "columns": [ 203 + "user_id" 204 + ], 205 + "isUnique": false 206 + } 207 + }, 208 + "foreignKeys": { 209 + "sessions_user_id_users_id_fk": { 210 + "name": "sessions_user_id_users_id_fk", 211 + "tableFrom": "sessions", 212 + "tableTo": "users", 213 + "columnsFrom": [ 214 + "user_id" 215 + ], 216 + "columnsTo": [ 217 + "id" 218 + ], 219 + "onDelete": "cascade", 220 + "onUpdate": "no action" 221 + } 222 + }, 223 + "compositePrimaryKeys": {}, 224 + "uniqueConstraints": {}, 225 + "checkConstraints": {} 226 + }, 227 + "users": { 228 + "name": "users", 229 + "columns": { 230 + "id": { 231 + "name": "id", 232 + "type": "text", 233 + "primaryKey": true, 234 + "notNull": true, 235 + "autoincrement": false 236 + }, 237 + "name": { 238 + "name": "name", 239 + "type": "text", 240 + "primaryKey": false, 241 + "notNull": true, 242 + "autoincrement": false 243 + }, 244 + "email": { 245 + "name": "email", 246 + "type": "text", 247 + "primaryKey": false, 248 + "notNull": true, 249 + "autoincrement": false 250 + }, 251 + "email_verified": { 252 + "name": "email_verified", 253 + "type": "integer", 254 + "primaryKey": false, 255 + "notNull": true, 256 + "autoincrement": false 257 + }, 258 + "image": { 259 + "name": "image", 260 + "type": "text", 261 + "primaryKey": false, 262 + "notNull": false, 263 + "autoincrement": false 264 + }, 265 + "created_at": { 266 + "name": "created_at", 267 + "type": "integer", 268 + "primaryKey": false, 269 + "notNull": true, 270 + "autoincrement": false 271 + }, 272 + "updated_at": { 273 + "name": "updated_at", 274 + "type": "integer", 275 + "primaryKey": false, 276 + "notNull": true, 277 + "autoincrement": false 278 + }, 279 + "username": { 280 + "name": "username", 281 + "type": "text", 282 + "primaryKey": false, 283 + "notNull": false, 284 + "autoincrement": false 285 + }, 286 + "display_username": { 287 + "name": "display_username", 288 + "type": "text", 289 + "primaryKey": false, 290 + "notNull": false, 291 + "autoincrement": false 292 + }, 293 + "bsky_app_pass": { 294 + "name": "bsky_app_pass", 295 + "type": "text", 296 + "primaryKey": false, 297 + "notNull": true, 298 + "autoincrement": false 299 + }, 300 + "pds": { 301 + "name": "pds", 302 + "type": "text", 303 + "primaryKey": false, 304 + "notNull": true, 305 + "autoincrement": false, 306 + "default": "'https://bsky.social'" 307 + } 308 + }, 309 + "indexes": { 310 + "users_email_unique": { 311 + "name": "users_email_unique", 312 + "columns": [ 313 + "email" 314 + ], 315 + "isUnique": true 316 + }, 317 + "users_username_unique": { 318 + "name": "users_username_unique", 319 + "columns": [ 320 + "username" 321 + ], 322 + "isUnique": true 323 + } 324 + }, 325 + "foreignKeys": {}, 326 + "compositePrimaryKeys": {}, 327 + "uniqueConstraints": {}, 328 + "checkConstraints": {} 329 + }, 330 + "verifications": { 331 + "name": "verifications", 332 + "columns": { 333 + "id": { 334 + "name": "id", 335 + "type": "text", 336 + "primaryKey": true, 337 + "notNull": true, 338 + "autoincrement": false 339 + }, 340 + "identifier": { 341 + "name": "identifier", 342 + "type": "text", 343 + "primaryKey": false, 344 + "notNull": true, 345 + "autoincrement": false 346 + }, 347 + "value": { 348 + "name": "value", 349 + "type": "text", 350 + "primaryKey": false, 351 + "notNull": true, 352 + "autoincrement": false 353 + }, 354 + "expires_at": { 355 + "name": "expires_at", 356 + "type": "integer", 357 + "primaryKey": false, 358 + "notNull": true, 359 + "autoincrement": false 360 + }, 361 + "created_at": { 362 + "name": "created_at", 363 + "type": "integer", 364 + "primaryKey": false, 365 + "notNull": true, 366 + "autoincrement": false, 367 + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" 368 + }, 369 + "updated_at": { 370 + "name": "updated_at", 371 + "type": "integer", 372 + "primaryKey": false, 373 + "notNull": true, 374 + "autoincrement": false, 375 + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" 376 + } 377 + }, 378 + "indexes": { 379 + "verifications_identifier_idx": { 380 + "name": "verifications_identifier_idx", 381 + "columns": [ 382 + "identifier" 383 + ], 384 + "isUnique": false 385 + } 386 + }, 387 + "foreignKeys": {}, 388 + "compositePrimaryKeys": {}, 389 + "uniqueConstraints": {}, 390 + "checkConstraints": {} 391 + }, 392 + "posts": { 393 + "name": "posts", 394 + "columns": { 395 + "uuid": { 396 + "name": "uuid", 397 + "type": "text", 398 + "primaryKey": true, 399 + "notNull": true, 400 + "autoincrement": false 401 + }, 402 + "content": { 403 + "name": "content", 404 + "type": "text", 405 + "primaryKey": false, 406 + "notNull": true, 407 + "autoincrement": false 408 + }, 409 + "scheduled_date": { 410 + "name": "scheduled_date", 411 + "type": "integer", 412 + "primaryKey": false, 413 + "notNull": true, 414 + "autoincrement": false 415 + }, 416 + "posted": { 417 + "name": "posted", 418 + "type": "integer", 419 + "primaryKey": false, 420 + "notNull": false, 421 + "autoincrement": false, 422 + "default": false 423 + }, 424 + "postNow": { 425 + "name": "postNow", 426 + "type": "integer", 427 + "primaryKey": false, 428 + "notNull": false, 429 + "autoincrement": false, 430 + "default": false 431 + }, 432 + "embedContent": { 433 + "name": "embedContent", 434 + "type": "text", 435 + "primaryKey": false, 436 + "notNull": true, 437 + "autoincrement": false, 438 + "default": "(json_array())" 439 + }, 440 + "uri": { 441 + "name": "uri", 442 + "type": "text", 443 + "primaryKey": false, 444 + "notNull": false, 445 + "autoincrement": false 446 + }, 447 + "cid": { 448 + "name": "cid", 449 + "type": "text", 450 + "primaryKey": false, 451 + "notNull": false, 452 + "autoincrement": false 453 + }, 454 + "contentLabel": { 455 + "name": "contentLabel", 456 + "type": "text", 457 + "primaryKey": false, 458 + "notNull": true, 459 + "autoincrement": false, 460 + "default": "'None'" 461 + }, 462 + "created_at": { 463 + "name": "created_at", 464 + "type": "integer", 465 + "primaryKey": false, 466 + "notNull": true, 467 + "autoincrement": false, 468 + "default": "CURRENT_TIMESTAMP" 469 + }, 470 + "updated_at": { 471 + "name": "updated_at", 472 + "type": "integer", 473 + "primaryKey": false, 474 + "notNull": false, 475 + "autoincrement": false 476 + }, 477 + "user": { 478 + "name": "user", 479 + "type": "text", 480 + "primaryKey": false, 481 + "notNull": true, 482 + "autoincrement": false 483 + } 484 + }, 485 + "indexes": { 486 + "user_idx": { 487 + "name": "user_idx", 488 + "columns": [ 489 + "user" 490 + ], 491 + "isUnique": false 492 + }, 493 + "postedUpdate_idx": { 494 + "name": "postedUpdate_idx", 495 + "columns": [ 496 + "updated_at", 497 + "posted" 498 + ], 499 + "isUnique": false, 500 + "where": "posted = 1" 501 + }, 502 + "postedUUID_idx": { 503 + "name": "postedUUID_idx", 504 + "columns": [ 505 + "uuid", 506 + "posted" 507 + ], 508 + "isUnique": false 509 + }, 510 + "postNowScheduledDatePosted_idx": { 511 + "name": "postNowScheduledDatePosted_idx", 512 + "columns": [ 513 + "posted", 514 + "scheduled_date", 515 + "postNow" 516 + ], 517 + "isUnique": false, 518 + "where": "posted = 0 and postNow <> 1" 519 + } 520 + }, 521 + "foreignKeys": { 522 + "posts_user_users_id_fk": { 523 + "name": "posts_user_users_id_fk", 524 + "tableFrom": "posts", 525 + "tableTo": "users", 526 + "columnsFrom": [ 527 + "user" 528 + ], 529 + "columnsTo": [ 530 + "id" 531 + ], 532 + "onDelete": "cascade", 533 + "onUpdate": "no action" 534 + } 535 + }, 536 + "compositePrimaryKeys": {}, 537 + "uniqueConstraints": {}, 538 + "checkConstraints": {} 539 + }, 540 + "reposts": { 541 + "name": "reposts", 542 + "columns": { 543 + "id": { 544 + "name": "id", 545 + "type": "integer", 546 + "primaryKey": true, 547 + "notNull": true, 548 + "autoincrement": true 549 + }, 550 + "post_uuid": { 551 + "name": "post_uuid", 552 + "type": "text", 553 + "primaryKey": false, 554 + "notNull": true, 555 + "autoincrement": false 556 + }, 557 + "scheduled_date": { 558 + "name": "scheduled_date", 559 + "type": "integer", 560 + "primaryKey": false, 561 + "notNull": true, 562 + "autoincrement": false 563 + } 564 + }, 565 + "indexes": { 566 + "repost_scheduledDate_idx": { 567 + "name": "repost_scheduledDate_idx", 568 + "columns": [ 569 + "scheduled_date" 570 + ], 571 + "isUnique": false 572 + }, 573 + "repost_postid_idx": { 574 + "name": "repost_postid_idx", 575 + "columns": [ 576 + "post_uuid" 577 + ], 578 + "isUnique": false 579 + } 580 + }, 581 + "foreignKeys": { 582 + "reposts_post_uuid_posts_uuid_fk": { 583 + "name": "reposts_post_uuid_posts_uuid_fk", 584 + "tableFrom": "reposts", 585 + "tableTo": "posts", 586 + "columnsFrom": [ 587 + "post_uuid" 588 + ], 589 + "columnsTo": [ 590 + "uuid" 591 + ], 592 + "onDelete": "cascade", 593 + "onUpdate": "no action" 594 + } 595 + }, 596 + "compositePrimaryKeys": {}, 597 + "uniqueConstraints": {}, 598 + "checkConstraints": {} 599 + }, 600 + "violations": { 601 + "name": "violations", 602 + "columns": { 603 + "id": { 604 + "name": "id", 605 + "type": "integer", 606 + "primaryKey": true, 607 + "notNull": true, 608 + "autoincrement": true 609 + }, 610 + "user": { 611 + "name": "user", 612 + "type": "text", 613 + "primaryKey": false, 614 + "notNull": true, 615 + "autoincrement": false 616 + }, 617 + "tosViolation": { 618 + "name": "tosViolation", 619 + "type": "integer", 620 + "primaryKey": false, 621 + "notNull": false, 622 + "autoincrement": false, 623 + "default": false 624 + }, 625 + "userPassInvalid": { 626 + "name": "userPassInvalid", 627 + "type": "integer", 628 + "primaryKey": false, 629 + "notNull": false, 630 + "autoincrement": false, 631 + "default": false 632 + }, 633 + "accountSuspended": { 634 + "name": "accountSuspended", 635 + "type": "integer", 636 + "primaryKey": false, 637 + "notNull": false, 638 + "autoincrement": false, 639 + "default": false 640 + }, 641 + "accountGone": { 642 + "name": "accountGone", 643 + "type": "integer", 644 + "primaryKey": false, 645 + "notNull": false, 646 + "autoincrement": false, 647 + "default": false 648 + }, 649 + "mediaTooBig": { 650 + "name": "mediaTooBig", 651 + "type": "integer", 652 + "primaryKey": false, 653 + "notNull": false, 654 + "autoincrement": false, 655 + "default": false 656 + }, 657 + "created_at": { 658 + "name": "created_at", 659 + "type": "integer", 660 + "primaryKey": false, 661 + "notNull": true, 662 + "autoincrement": false, 663 + "default": "CURRENT_TIMESTAMP" 664 + } 665 + }, 666 + "indexes": { 667 + "violations_user_idx": { 668 + "name": "violations_user_idx", 669 + "columns": [ 670 + "user" 671 + ], 672 + "isUnique": false 673 + } 674 + }, 675 + "foreignKeys": { 676 + "violations_user_users_id_fk": { 677 + "name": "violations_user_users_id_fk", 678 + "tableFrom": "violations", 679 + "tableTo": "users", 680 + "columnsFrom": [ 681 + "user" 682 + ], 683 + "columnsTo": [ 684 + "id" 685 + ], 686 + "onDelete": "cascade", 687 + "onUpdate": "no action" 688 + } 689 + }, 690 + "compositePrimaryKeys": {}, 691 + "uniqueConstraints": {}, 692 + "checkConstraints": {} 693 + } 694 + }, 695 + "views": {}, 696 + "enums": {}, 697 + "_meta": { 698 + "schemas": {}, 699 + "tables": {}, 700 + "columns": {} 701 + }, 702 + "internal": { 703 + "indexes": {} 704 + } 705 + }
+7
migrations/meta/_journal.json
··· 85 85 "when": 1767906142896, 86 86 "tag": "0011_sticky_silver_sable", 87 87 "breakpoints": true 88 + }, 89 + { 90 + "idx": 12, 91 + "version": "6", 92 + "when": 1767915051459, 93 + "tag": "0012_reflective_ogun", 94 + "breakpoints": true 88 95 } 89 96 ] 90 97 }
-7
package-lock.json
··· 21 21 "just-safe-get": "^4.2.0", 22 22 "just-split": "^3.2.0", 23 23 "just-truncate": "^2.2.0", 24 - "just-unique": "^4.2.0", 25 24 "uuid": "^13.0.0", 26 25 "zod": "^4.3.5" 27 26 }, ··· 3998 3997 "version": "2.2.0", 3999 3998 "resolved": "https://registry.npmjs.org/just-truncate/-/just-truncate-2.2.0.tgz", 4000 3999 "integrity": "sha512-s7RX8ARl3SBPBPT5z9BRh4pNtHfmWIOiG3OiOisON8gPXjAhKaL9SFgUhGdrwcr6PpQQR6otNrRzCgbozi9qpQ==", 4001 - "license": "MIT" 4002 - }, 4003 - "node_modules/just-unique": { 4004 - "version": "4.2.0", 4005 - "resolved": "https://registry.npmjs.org/just-unique/-/just-unique-4.2.0.tgz", 4006 - "integrity": "sha512-cxQGGUiit6CGUpuuiezY8N4m1wgF4o7127rXEXDFcxeDUFfdV7gSkwA26Fe2wWBiNQq2SZOgN4gSmMxB/StA8Q==", 4007 4000 "license": "MIT" 4008 4001 }, 4009 4002 "node_modules/kleur": {
-1
package.json
··· 39 39 "just-safe-get": "^4.2.0", 40 40 "just-split": "^3.2.0", 41 41 "just-truncate": "^2.2.0", 42 - "just-unique": "^4.2.0", 43 42 "uuid": "^13.0.0", 44 43 "zod": "^4.3.5" 45 44 },
+3
src/auth/index.ts
··· 77 77 }, 78 78 plugins: [ 79 79 username({ 80 + /* we do our own normalization in the zod schemas */ 81 + usernameNormalization: false, 82 + displayUsernameNormalization: false, 80 83 minUsernameLength: BSKY_MIN_USERNAME_LENGTH, 81 84 maxUsernameLength: BSKY_MAX_USERNAME_LENGTH 82 85 })
+8 -2
src/db/app.schema.ts
··· 23 23 .notNull() 24 24 .references(() => users.id, { onDelete: "cascade" }), 25 25 }, (table) => [ 26 - index("scheduledDate_idx").on(table.scheduledDate), 26 + // finding posts by user 27 27 index("user_idx").on(table.userId), 28 + // for purging posted posts after a set time 28 29 index("postedUpdate_idx") 29 30 .on(table.updatedAt, table.posted) 30 - .where(sql`posted = 1`), /* eq function will not work */ 31 + .where(sql`posted = 1`), 32 + // for db pruning and parity with the PDS 31 33 index("postedUUID_idx").on(table.uuid, table.posted), 34 + // cron job 32 35 index("postNowScheduledDatePosted_idx") 33 36 .on(table.posted, table.scheduledDate, table.postNow) 34 37 .where(sql`posted = 0 and postNow <> 1`), ··· 41 44 .references(() => posts.uuid, {onDelete: "cascade"}), 42 45 scheduledDate: integer('scheduled_date', { mode: 'timestamp_ms' }).notNull(), 43 46 }, (table) => [ 47 + // cron queries 44 48 index("repost_scheduledDate_idx").on(table.scheduledDate), 49 + // used for left joining and matching with posts field 45 50 index("repost_postid_idx").on(table.uuid) 46 51 ]); 47 52 ··· 59 64 .default(sql`CURRENT_TIMESTAMP`) 60 65 .notNull(), 61 66 }, (table) => [ 67 + // joining and querying against the table's data 62 68 index("violations_user_idx").on(table.userId) 63 69 ]);
+5 -6
src/utils/dbQuery.ts
··· 10 10 import has from "just-has"; 11 11 import isEmpty from "just-is-empty"; 12 12 import truncate from "just-truncate"; 13 - import unique from "just-unique"; 14 13 import { v4 as uuidv4, validate as uuidValid } from 'uuid'; 15 14 import { posts, reposts, violations } from "../db/app.schema"; 16 15 import { accounts, users } from "../db/auth.schema"; ··· 228 227 const db: DrizzleD1Database = drizzle(env.DB); 229 228 // TODO: this could probably be left joined to some degree 230 229 // but it currently doesn't have a high read count 231 - const query = db.select({uuid: reposts.uuid}).from(reposts) 230 + const query = db.selectDistinct({uuid: reposts.uuid}).from(reposts) 232 231 .where(lte(reposts.scheduledDate, givenDate)); 233 232 const violationsQuery = db.select({data: violations.userId}).from(violations); 234 233 const results = await db.select({uri: posts.uri, cid: posts.cid, userId: posts.userId }) ··· 372 371 export const purgePostedPosts = async (env: Bindings): Promise<number> => { 373 372 const db: DrizzleD1Database = drizzle(env.DB); 374 373 const dateString = `datetime('now', '-${MAX_HOLD_DAYS_BEFORE_PURGE} days')`; 375 - const dbQuery = await db.select({ data: posts.uuid }).from(posts).leftJoin(reposts, eq(posts.uuid, reposts.uuid)) 374 + const dbQuery = await db.selectDistinct({ data: posts.uuid }).from(posts).leftJoin(reposts, eq(posts.uuid, reposts.uuid)) 376 375 .where( 377 376 and( 378 - isNull(reposts.uuid), 379 377 and( 380 378 eq(posts.posted, true), lte(posts.updatedAt, sql`${dateString}`) 381 - ) 379 + ), 380 + isNull(reposts.uuid) 382 381 ) 383 382 ).all(); 384 - const postsToDelete = unique(dbQuery.map((item) => { return item.data })); 383 + const postsToDelete = dbQuery.map((item) => { return item.data }); 385 384 return await deletePosts(env, postsToDelete); 386 385 } 387 386