diff --git a/Conditionable.php b/Conditionable.php new file mode 100644 index 0000000..912b021 --- /dev/null +++ b/Conditionable.php @@ -0,0 +1,49 @@ +addCondition($col, $operator, $val, "AND"); + } + + public function andWhere(string $col, string|Operator $operator, mixed $val): self { + return $this->addCondition($col, $operator, $val, "AND"); + } + + public function orWhere(string $col, string|Operator $operator, mixed $val): self { + return $this->addCondition($col, $operator, $val, "OR"); + } + + protected function addCondition(string $col, string|Operator $operator, mixed $val, string $prefix): self { + $this->schema->requireColumn($col); + + // Convert the operator string to a ConditionOperator enum if needed. + if (is_string($operator)) + $operator = Operator::fromString($operator); + + $columnType = $this->schema->columnType($col); + $castedValue = $columnType->dbCast($val); + + if (!empty($this->conditions)) + $this->conditions[] = $prefix; + $this->conditions[] = "$col " . $operator->toString() . " $castedValue"; + + return $this; + } + + public function isConditioned(): bool { + return !empty($this->conditions); + } + + protected function combineConditions(): string { + if ($this->isConditioned()) + return implode(" ", $this->conditions); + return ""; + } +} diff --git a/Database.php b/Database.php new file mode 100644 index 0000000..c3d2ea4 --- /dev/null +++ b/Database.php @@ -0,0 +1,54 @@ +prefix; + + foreach ($tableName as &$name) + if (!str_starts_with($name, $dbPrefix)) + $name = $dbPrefix . $name; + } +} \ No newline at end of file diff --git a/Deletion.php b/Deletion.php new file mode 100644 index 0000000..97f3c38 --- /dev/null +++ b/Deletion.php @@ -0,0 +1,62 @@ +table = $table; + } + + /** + * Generates the SQL statement. + * @return string SQL query. + * @throws InvalidArgumentException + */ + public function toSql(): string { + $table = $this->table->name; + $whereClause = $this->combineConditions(); + + if (!$this->isConditioned()) + throw new InvalidArgumentException("Deletions need to be conditioned."); + + return esc_sql("DELETE FROM $table WHERE $whereClause"); + } + + /** + * Executes the DELETE query. + * @return int Number of affected rows. + * @throws Exception + */ + public function delete(): int { + global $wpdb; + $query = $this->toSql(); + $result = $wpdb->query($query); + + if ($result === false) + throw new Exception("Deletion failed: " . $wpdb->last_error . "."); + return intval($result); + } + + /** + * Clears all entries from the table. + * @return int Number of affected rows. + * @throws Exception + */ + public function truncate(): int { + global $wpdb; + $table = $this->table->name; + $query = esc_sql("TRUNCATE TABLE $table"); + $result = $wpdb->query($query); + + if ($result === false) + throw new Exception("Truncation failed: " . $wpdb->last_error . "."); + return intval($result); + } +} diff --git a/Insertion.php b/Insertion.php new file mode 100644 index 0000000..dd90f36 --- /dev/null +++ b/Insertion.php @@ -0,0 +1,84 @@ +table = $table; + } + + /** + * Adds a single column-value pair to the row. + * @param string $col Column name. + * @param mixed $val Value to insert. + * @return Insertion Current instance for method chaining. + * @throws InvalidArgumentException + */ + public function data(string $col, mixed $val): Insertion { + if (!isset($this->table->columns[$col])) + throw new InvalidArgumentException("Column '$col' does not exist."); + + $columnType = $this->table->columns[$col]['colType']; + $this->currentRow[$col] = $columnType->dbCast($val); + + return $this; + } + + /** + * Adds multiple column-value pairs to the row. + * @param array $data Associative array of column-value pairs. + * @return Insertion Current instance for method chaining. + * @throws InvalidArgumentException + */ + public function batchData(array $data): Insertion { + foreach ($data as $key => $value) + $this->data($key, $value); + return $this; + } + + /** + * Finalizes the current row and stacks it for insertion. + * @return Insertion Current instance for method chaining. + */ + public function stack(): Insertion { + if (!empty($this->currentRow)) + $this->stackForInsertion(); + return $this; + } + + private function stackForInsertion(): void { + $this->batchRows[] = $this->currentRow; + $this->currentRow = []; + } + + /** + * Executes the insertion of all batched rows into the database. + * @throws InvalidArgumentException + */ + public function insert(): bool { + global $wpdb; + + // Convert single to batch queries. + if (!empty($this->currentRow)) + $this->stackForInsertion(); + + if (empty($this->batchRows)) + throw new InvalidArgumentException("No data set for insertion."); + + foreach ($this->batchRows as $row) { + if (!empty($row)) { + $result = $wpdb->insert($this->table->name, $row); + if ($result === false) + return false; + } + } + + return true; + } +} \ No newline at end of file diff --git a/Migration.php b/Migration.php new file mode 100644 index 0000000..fbd0136 --- /dev/null +++ b/Migration.php @@ -0,0 +1,139 @@ +table = $table->copy(); + } + + public function addColumn(string $name, Type $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Migration { + $this->table->columns[$name] = [ + 'name' => $name, + 'type' => $type, + 'default' => $default, + 'isNullable' => $isNullable, + 'isUnique' => $isUnique + ]; + $this->columnsToAdd[] = $name; + return $this; + } + + public function modifyColumn(string $name, Type $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Migration { + if (!isset($this->table->columns[$name])) { + throw new InvalidArgumentException("Column $name does not exist."); + } + $this->table->columns[$name] = [ + 'name' => $name, + 'type' => $type, + 'default' => $default, + 'isNullable' => $isNullable, + 'isUnique' => $isUnique + ]; + $this->columnsToModify[] = $name; + return $this; + } + + public function dropColumn(string $name): Migration { + if (!isset($this->table->columns[$name])) { + throw new InvalidArgumentException("Column $name does not exist."); + } + unset($this->table->columns[$name]); + $this->columnsToDrop[] = $name; + return $this; + } + + public function changePrimaryKey(string $name, bool $autoInc = false): Migration { + if (!isset($this->table->columns[$name])) { + throw new InvalidArgumentException("Column $name does not exist."); + } + $this->table->primaryKey = [ + 'name' => $name, + 'autoInc' => $autoInc + ]; + $this->primaryKey = $name; + return $this; + } + + public function addForeignKey(string $column, string $referencedTable, string $referencedColumn, Propagation $onDelete, Propagation $onUpdate): Migration { + if (!isset($this->table->columns[$column])) { + throw new InvalidArgumentException("Column $column does not exist."); + } + $this->table->foreignKeys[$column] = [ + 'referencedTable' => $referencedTable, + 'referencedColumn' => $referencedColumn, + 'onDelete' => $onDelete, + 'onUpdate' => $onUpdate + ]; + $this->foreignKeysToAdd[] = $column; + return $this; + } + + public function dropForeignKey(string $name): Migration { + if (!isset($this->table->foreignKeys[$name])) { + throw new InvalidArgumentException("Foreign key $name does not exist."); + } + unset($this->table->foreignKeys[$name]); + $this->foreignKeysToDrop[] = $name; + return $this; + } + + public function toSql(): string { + $sql = "ALTER TABLE `{$this->table->name}` "; + $statements = []; + + foreach ($this->columnsToAdd as $name) { + $col = $this->table->columns[$name]; + $statements[] = "ADD COLUMN `{$col['name']}` {$col['type']->toString()}" . + ($col['isNullable'] ? "" : " NOT NULL") . + ($col['isUnique'] ? " UNIQUE" : "") . + ($col['default'] !== null ? " DEFAULT " . (is_string($col['default']) ? "'{$col['default']}'" : $col['default']) : ""); + } + + foreach ($this->columnsToModify as $name) { + $col = $this->table->columns[$name]; + $statements[] = "MODIFY COLUMN `{$col['name']}` {$col['type']->toString()}" . + ($col['isNullable'] ? "" : " NOT NULL") . + ($col['isUnique'] ? " UNIQUE" : "") . + ($col['default'] !== null ? " DEFAULT " . (is_string($col['default']) ? "'{$col['default']}'" : $col['default']) : ""); + } + + foreach ($this->columnsToDrop as $name) { + $statements[] = "DROP COLUMN `$name`"; + } + + foreach ($this->foreignKeysToDrop as $name) { + $statements[] = "DROP FOREIGN KEY `$name`"; + } + + foreach ($this->foreignKeysToAdd as $column) { + $fk = $this->table->foreignKeys[$column]; + $statements[] = "ADD CONSTRAINT `fk_{$column}` FOREIGN KEY (`$column`) REFERENCES `{$fk['referencedTable']}` (`{$fk['referencedColumn']}`) ON DELETE {$fk['onDelete']->toString()} ON UPDATE {$fk['onUpdate']->toString()}"; + } + + return $sql . implode(", ", $statements) . ";"; + } + + public function drop(): null { + + } + + public function migrate(): Schema { + global $wpdb; + $sql = $this->toSql(); + $wpdb->query($sql); + return $this->table; + } +} diff --git a/Query.php b/Query.php new file mode 100644 index 0000000..efeaf10 --- /dev/null +++ b/Query.php @@ -0,0 +1,109 @@ +schema = $table; + } + + public function select(string ...$cols): Query { + if (!empty($cols)) + $this->columns = $cols; + foreach ($cols as $col) + $this->schema->requireColumn($col); + return $this; + } + + public function orderBy(string $col, Order $order): Query { + $this->schema->requireColumn($col); + $this->orderBy = [ + 'name' => $col, + 'order' => $order + ]; + return $this; + } + + public function join(Schema $other, Join $join): Query { + $foreignKey = null; + if($this->schema->existsReference($other)) + $foreignKey = $this->schema->foreignKeys[$other->name]; + if ($other->existsReference($this->schema)) + $foreignKey = $other->foreignKeys[$this->schema->name]; + + if (is_null($foreignKey)) + throw new InvalidArgumentException('Joins can only applied to referencing columns.'); + + // TODO: Implement include instead of merge + $this->schema->include($other); + $this->joins[] = [ + 'table' => $other->name, + 'type' => $join + ]; + + return $this; + } + + protected function isOrdered(): bool { + return !empty($this->orderBy); + } + + protected function isJoined(): bool { + return !empty($this->joins); + } + + public function toSql(): string { + // Build the SELECT clause. + $columns = implode(", ", $this->columns); + $primaryTable = $this->schema->name; + $sqlStatement = "SELECT $columns FROM $primaryTable"; + + // Append join clauses, if any. + if ($this->isJoined()) { + foreach ($this->joins as $join) { + $sqlStatement .= " " . $join['type']->toString() . " NATURAL JOIN " . $join['table']; + } + } + + // Append the WHERE clause if conditions exist. + if ($this->isConditioned()) { + $whereClause = $this->combineConditions(); + $sqlStatement .= " WHERE $whereClause"; + } + + // Append the ORDER BY clause if ordering is set. + if ($this->isOrdered()) { + $orderClause = $this->orderBy['name'] . ' ' . $this->orderBy['order']; + $sqlStatement .= " ORDER BY $orderClause"; + } + + return esc_sql($sqlStatement); + } + + public function query(): array { + global $wpdb; + $query = $this->toSql(); + $results = $wpdb->get_results($query, ARRAY_A); + return $this->castResults($results); + } + + protected function castResults(array $results): array { + foreach ($results as &$row) + foreach ($row as $column => &$value) + if (isset($this->columnTypes[$column])) + $value = $this->columnTypes[$column]->valCast($value); + return $results; + } +} diff --git a/Schema.php b/Schema.php new file mode 100644 index 0000000..041b0b0 --- /dev/null +++ b/Schema.php @@ -0,0 +1,78 @@ +name = $name; + } + + public function requireColumn(string $col): void { + if (!$this->existsColumn($col)) + throw new InvalidArgumentException("Column '$col' is not defined."); + } + + public function existsColumn(string $col): bool { + return isset($this->columns[$col]); + } + + public function existsReference(Schema $schema): bool { + foreach ($this->foreignKeys as $foreignKey) + if ($foreignKey['table'] == $schema->name) + return true; + return false; + } + + public function columnType(string $col) { + return $this->columns[$col]['type']; + } + + public function primaryKey() { + return $this->columns['primary']['name']; + } + + /** + * Creates a deep copy of this instance. + * @return Schema + */ + public function copy(): Schema { + $copy = new Schema($this->name); + $copy->columns = genericDeepCopy($this->columns); + $copy->primaryKey = genericDeepCopy($this->primaryKey); + $copy->foreignKeys = genericDeepCopy($this->foreignKeys); + $copy->engine = $this->engine; + $copy->charset = $this->charset; + $copy->collation = $this->collation; + return $copy; + } + + public function include(Schema $other): void { + // Create a copy of the other schema. + $otherCopy = $other->copy(); + + // Add any column that isn't already defined. + foreach ($otherCopy->columns as $colName => $colDef) + if (!isset($this->columns[$colName])) + $this->columns[$colName] = $colDef; + + // Add any foreign key that doesn't already exist. + foreach ($other->foreignKeys as $colName => $foreignKey) + if (!isset($this->foreignKeys[$colName])) + $this->foreignKeys[$colName] = $foreignKey; + } +} diff --git a/Table.php b/Table.php new file mode 100644 index 0000000..6f438a9 --- /dev/null +++ b/Table.php @@ -0,0 +1,131 @@ +table = new Schema($tableName); + } + + public function column(string $name, Type $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Table { + $this->table->columns[$name] = [ + 'name' => $name, + 'default' => $default, + 'type' => $type, + 'isNullable' => $isNullable, + 'isUnique' => $isUnique + ]; + + return $this; + } + + public function primary(string $name, Type $type, bool $autoInc = false): Table { + if(isset($this->primaryKey)) + throw new InvalidArgumentException('Primary column already exists.'); + + $this->table->primaryKey = [ + 'name' => $name, + 'autoInc' => $autoInc + ]; + + return $this->column($name, $type); + } + + public function reference(Schema $foreignTable, Propagation $onDelete = Propagation::CASCADE, Propagation $onUpdate = Propagation::CASCADE): Table { + $name = $foreignTable->primaryKey(); + if(isset($this->columns[$name])) + throw new InvalidArgumentException('Column name already exists.'); + + $this->table->foreignKeys[$name] = [ + 'name' => $name, + 'table' => $foreignTable->name, + 'onDelete' => $onDelete, + 'onUpdate' => $onUpdate + ]; + + $this->table->columns[$name] = $foreignTable->columns[$name]; + return $this; + } + + public function engine(Engine $engine): Table { + $this->table->engine = $engine; + return $this; + } + + public function charset(Charset $charset): Table { + $this->table->charset = $charset; + return $this; + } + + public function collation(Collation $collation): Table { + $this->table->collation = $collation; + return $this; + } + + /** + * Generates the SQL statement. + * @return string SQL query. + * @throws InvalidArgumentException + */ + public function toSql(): string { + $primaryKey = $this->table->primaryKey(); + + $sql = "CREATE TABLE `{$this->table->name}` (\n"; + $sql .= " PRIMARY KEY (`$primaryKey`),\n"; + + foreach ($this->table->columns as $col) { + if ($col['name'] !== $primaryKey) { + $sql .= " `{$col['name']}` {$col['type']->toString()}"; + // Handle nulls, uniqueness, and defaults + if (!$col['isNullable']) + $sql .= " NOT NULL"; + if ($col['isUnique']) + $sql .= " UNIQUE"; + if ($col['default'] !== null) { + $default = is_string($col['default']) ? "'{$col['default']}'" : $col['default']; + $sql .= " DEFAULT $default"; + } + + $sql .= ",\n"; + } + } + + // Add secondary constraints if present + foreach ($this->table->foreignKeys as $key) { + $sql .= " FOREIGN KEY (`{$key['name']}`) REFERENCES `{$key['table']}` (`{$key['name']}`)"; + $sql .= " ON DELETE {$key['onDelete']->toString()} ON UPDATE {$key['onUpdate']->toString()},\n"; + } + + // Close the SQL string and add constraints + $sql = rtrim($sql, ",\n") . "\n) "; + $sql .= "ENGINE={$this->table->engine->toString()} "; + $sql .= "CHARSET={$this->table->charset->toString()} "; + $sql -= "COLLATE={$this->table->collation->toString()};"; + return esc_sql($sql); + } + + public function create(): Schema { + global $wpdb; + + if (empty($this->primaryKey)) + throw new InvalidArgumentException('A primary key must be defined.'); + $table_name = $wpdb->prefix . $this->table->name; + + if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") !== $table_name) { + $sql = $this->toSql(); + require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); + dbDelta($sql); + } + return $this->table; + } +} diff --git a/Update.php b/Update.php new file mode 100644 index 0000000..9e88c55 --- /dev/null +++ b/Update.php @@ -0,0 +1,69 @@ +table = $table; + } + + /** + * Sets a new value for a column. + * @param string $col Column name. + * @param mixed $val Value to set. + * @return self Current instance for method chaining. + * @throws InvalidArgumentException + */ + public function set(string $col, mixed $val): self { + $this->table->requireColumn($col); + + $columnType = $this->table->columnType($col); + $castedValue = $columnType->dbCast($val); + $this->values[$col] = $castedValue; + return $this; + } + + /** + * Generates the SQL statement. + * @return string SQL query. + * @throws InvalidArgumentException + */ + public function toSql(): string { + if (empty($this->values)) + throw new InvalidArgumentException("No values have been set for the Update."); + + $table = $this->table->name; + $setParts = []; + foreach ($this->values as $col => $value) + $setParts[] = "$col = $value"; + $setClause = implode(", ", $setParts); + + // FINAL SQL STATEMENT + $sqlStatement = "UPDATE $table SET $setClause"; + if($this->isConditioned()) { + $whereClause = $this->combineConditions(); + $sqlStatement .= " WHERE $whereClause"; + } + return esc_sql($sqlStatement); + } + + /** + * Executes the SQL UPDATE query. + * @return bool Returns true on success. + */ + public function update(): bool { + global $wpdb; + $query = $this->toSql(); + $result = $wpdb->query($query); + return boolval($result); + } +} diff --git a/build.php b/build.php new file mode 100644 index 0000000..6e17047 --- /dev/null +++ b/build.php @@ -0,0 +1,42 @@ + $value) + $copy[$key] = genericDeepCopy($value); + return $copy; + } + elseif (is_object($data)) { + // If the object supports a copy method. + if (method_exists($data, 'copy')) + return $data->copy(); + // Use PHP's clone as fallback. + return clone $data; + } + else { + // Scalar variables. + return $data; + } +} + +// Require all enums +require './enums/Propagation.php'; +require './enums/Operator.php'; +require './enums/Order.php'; +require './enums/Charset.php'; +require './enums/Collation.php'; +require './enums/Type.php'; +require './enums/Engine.php'; +require './enums/Join.php'; + +// Require all classes +require './Database.php'; +require './Conditionable.php'; +require './Deletion.php'; +require './Insertion.php'; +require './Migration.php'; +require './Query.php'; +require './Schema.php'; +require './Table.php'; +require './Update.php'; diff --git a/enums/Charset.php b/enums/Charset.php new file mode 100644 index 0000000..b2112a8 --- /dev/null +++ b/enums/Charset.php @@ -0,0 +1,40 @@ + 'utf8', + self::UTF8MB4 => 'utf8mb4', + self::LATIN1 => 'latin1', + self::ASCII => 'ascii', + self::UTF16 => 'utf16', + self::UTF32 => 'utf32', + self::LATIN2 => 'latin2', + self::LATIN5 => 'latin5', + self::CP1251 => 'cp1251', + self::CP850 => 'cp850', + self::TIS620 => 'tis620', + self::GREEK => 'greek', + self::HEBREW => 'hebrew', + self::BINARY => 'binary', + }; + } +} + diff --git a/enums/Collation.php b/enums/Collation.php new file mode 100644 index 0000000..2f1fa9d --- /dev/null +++ b/enums/Collation.php @@ -0,0 +1,32 @@ + 'utf8_general_ci', + self::UTF8_UNICODE_CI => 'utf8_unicode_ci', + self::UTF8_SPANISH_CI => 'utf8_spanish_ci', + self::UTF8MB4_UNICODE_CI => 'utf8mb4_unicode_ci', + self::UTF8MB4_GENERAL_CI => 'utf8mb4_general_ci', + self::UTF8MB4_UNICODE_520_CI => 'utf8mb4_unicode_520_ci', + self::LATIN1_SWEDISH_CI => 'latin1_swedish_ci', + self::UTF8MB4_BIN => 'utf8mb4_bin', + self::UTF8_BIN => 'utf8_bin', + self::LATIN1_BIN => 'latin1_bin', + }; + } +} + diff --git a/enums/Engine.php b/enums/Engine.php new file mode 100644 index 0000000..2f6bbb2 --- /dev/null +++ b/enums/Engine.php @@ -0,0 +1,15 @@ + 'InnoDB', + self::MYISAM => 'MyISAM', + }; + } +} \ No newline at end of file diff --git a/enums/Join.php b/enums/Join.php new file mode 100644 index 0000000..d15a617 --- /dev/null +++ b/enums/Join.php @@ -0,0 +1,20 @@ + 'INNER JOIN', + self::LEFT => 'LEFT JOIN', + self::RIGHT => 'RIGHT JOIN', + self::FULL => 'FULL JOIN', + }; + } +} + diff --git a/enums/Operator.php b/enums/Operator.php new file mode 100644 index 0000000..58433e4 --- /dev/null +++ b/enums/Operator.php @@ -0,0 +1,37 @@ + self::EQUAL, + '!=' => self::NOT_EQUAL, + '>' => self::GREATER, + '>=' => self::GREATER_EQUAL, + '<' => self::LESS, + '<=' => self::LESS_EQUAL, + default => throw new InvalidArgumentException("Invalid operator: $operator"), + }; + } + + public function toString(): string { + return match ($this) { + self::EQUAL => '=', + self::NOT_EQUAL => '!=', + self::GREATER => '>', + self::GREATER_EQUAL => '>=', + self::LESS => '<', + self::LESS_EQUAL => '<=', + }; + } +} diff --git a/enums/Order.php b/enums/Order.php new file mode 100644 index 0000000..8c29a3e --- /dev/null +++ b/enums/Order.php @@ -0,0 +1,16 @@ + 'ASC', + self::DESC => 'DESC', + }; + } +} + diff --git a/enums/Propagation.php b/enums/Propagation.php new file mode 100644 index 0000000..bc9e673 --- /dev/null +++ b/enums/Propagation.php @@ -0,0 +1,21 @@ + 'CASCADE', + self::SET_NULL => 'SET NULL', + self::NO_ACTION => 'NO ACTION', + self::RESTRICT => 'RESTRICT', + self::SET_DEFAULT => 'SET DEFAULT', + }; + } +} \ No newline at end of file diff --git a/enums/Type.php b/enums/Type.php new file mode 100644 index 0000000..ad36a6e --- /dev/null +++ b/enums/Type.php @@ -0,0 +1,46 @@ + (int) $value, + self::FLOAT => (float) $value, + self::STRING => (string) $value, + self::BOOL => filter_var($value, FILTER_VALIDATE_BOOLEAN), + self::ARRAY => is_array($value) ? $value : (json_decode($value, true) ?? []), + self::DATE => $value instanceof DateTime ? $value : (strtotime($value) ? new DateTime($value) : null), + }; + } + + public function dbCast(mixed $value): mixed { + return match ($this) { + self::INT => intval($value), + self::FLOAT => floatval($value), + self::STRING => esc_sql($value), + self::BOOL => filter_var($value, FILTER_VALIDATE_BOOLEAN) ? "TRUE" : "FALSE", + self::ARRAY => json_encode($value), + self::DATE => $value instanceof DateTime ? $value->format('Y-m-d H:i:s') : json_encode($value) + }; + } + + public function toString(): string { + return match ($this) { + self::INT => 'INTEGER', + self::FLOAT => 'FLOAT', + self::STRING => 'VARCHAR(255)', + self::BOOL => 'BOOLEAN', + self::ARRAY => 'JSON', + self::DATE => 'DATETIME', + }; + } +} diff --git a/index.php b/index.php new file mode 100644 index 0000000..ad71f1a --- /dev/null +++ b/index.php @@ -0,0 +1,53 @@ +primary('col-primary', Type::INT, autoInc: true) + ->column('col-one', Type::BOOL) + ->column('col-two', Type::STRING) + ->create(); + + $batches = [ + [ + ['col-one', true], + ['col-two', 'EXPLODING!!!'] + ], + [ + ['col-one', false], + ['col-two', 'EXPLODING!!!'] + ], + ]; + + $batchInsert = Database::makeInsertion($table); + foreach($batches as $batch) { + $batchInsert->batchData($batch)->stack(); + } + $batchInsert->insert(); + + Database::makeUpdate($table) + ->where('col-primary', '=', 1) + ->set('col-one', false) + ->update(); + + $results = Database::makeQuery($table) + ->select('col-primary', 'col-one') + ->where('col-one', '=', true) + ->orderBy('col-one', Order::DESC) + ->query(); +} +catch ( Exception $e ) { + echo $e->getMessage(); +}