Skip to content

Commit

Permalink
leetcode: Add 1141
Browse files Browse the repository at this point in the history
  • Loading branch information
XuShaohua committed Aug 1, 2024
1 parent db72d9b commit 512c59e
Show file tree
Hide file tree
Showing 17 changed files with 317 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DATABASE_URL=postgres://leetcode:leetcode-password@localhost/leetcode
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/db
12 changes: 12 additions & 0 deletions src/leetcode/1141.user-activity-for-the-past-30-days-i/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "lc-1141-user-activity-for-the-past-30-days-i"
version = "0.1.0"
edition = "2021"
publish = false

[dependencies]
diesel = { version = "2.2.0", default-features = false, features = [ "chrono", "postgres", "r2d2" ] }
dotenvy = "0.15.7"
env_logger = "0.11.3"
log = "0.4.21"
r2d2 = "0.8.10"
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# For documentation on how to configure this file,
# see https://diesel.rs/guides/configuring-diesel-cli

[print_schema]
file = "src/schema.rs"
custom_type_derives = ["diesel::query_builder::QueryId", "Clone"]

[migrations_directory]
dir = "/home/shaohua/dev/rust/TheAlgorithms/src/leetcode/1141.user-activity-for-the-past-30-days-i/migrations"
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
version: "3.0"
services:
leetcode_db:
image: postgres:15.3
restart: always
ports:
- 127.0.0.1:5432:5432
environment:
POSTGRES_PASSWORD: leetcode-password
POSTGRES_USER: leetcode
POSTGRES_DB: leetcode
volumes:
- ./db:/var/lib/postgresql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

#

[问题描述](https://leetcode.com/problems/)
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
-- This file was automatically created by Diesel to setup helper functions
-- and other internal bookkeeping. This file is safe to edit, any future
-- changes will be added to existing projects as new migrations.

DROP FUNCTION IF EXISTS diesel_manage_updated_at(_tbl regclass);
DROP FUNCTION IF EXISTS diesel_set_updated_at();
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
-- This file was automatically created by Diesel to setup helper functions
-- and other internal bookkeeping. This file is safe to edit, any future
-- changes will be added to existing projects as new migrations.




-- Sets up a trigger for the given table to automatically set a column called
-- `updated_at` whenever the row is modified (unless `updated_at` was included
-- in the modified columns)
--
-- # Example
--
-- ```sql
-- CREATE TABLE users (id SERIAL PRIMARY KEY, updated_at TIMESTAMP NOT NULL DEFAULT NOW());
--
-- SELECT diesel_manage_updated_at('users');
-- ```
CREATE OR REPLACE FUNCTION diesel_manage_updated_at(_tbl regclass) RETURNS VOID AS $$
BEGIN
EXECUTE format('CREATE TRIGGER set_updated_at BEFORE UPDATE ON %s
FOR EACH ROW EXECUTE PROCEDURE diesel_set_updated_at()', _tbl);
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION diesel_set_updated_at() RETURNS trigger AS $$
BEGIN
IF (
NEW IS DISTINCT FROM OLD AND
NEW.updated_at IS NOT DISTINCT FROM OLD.updated_at
) THEN
NEW.updated_at := current_timestamp;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- This file should undo anything in `up.sql`
DROP TABLE activity;
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-- Your SQL goes here
CREATE TYPE ACTIVITY_TYPES AS ENUM('open_session', 'end_session', 'scroll_down', 'send_message');

CREATE TABLE IF NOT EXISTS activity (
id SERIAL PRIMARY KEY,
user_id int NOT NULL,
session_id int NOT NULL,
activity_date date NOT NULL,
activity_type ACTIVITY_TYPES
);

INSERT INTO Activity (user_id, session_id, activity_date, activity_type) VALUES ('1', '1', '2019-07-20', 'open_session');
INSERT INTO Activity (user_id, session_id, activity_date, activity_type) VALUES ('1', '1', '2019-07-20', 'scroll_down');
INSERT INTO Activity (user_id, session_id, activity_date, activity_type) VALUES ('1', '1', '2019-07-20', 'end_session');
INSERT INTO Activity (user_id, session_id, activity_date, activity_type) VALUES ('2', '4', '2019-07-20', 'open_session');
INSERT INTO Activity (user_id, session_id, activity_date, activity_type) VALUES ('2', '4', '2019-07-21', 'send_message');
INSERT INTO Activity (user_id, session_id, activity_date, activity_type) VALUES ('2', '4', '2019-07-21', 'end_session');
INSERT INTO Activity (user_id, session_id, activity_date, activity_type) VALUES ('3', '2', '2019-07-21', 'open_session');
INSERT INTO Activity (user_id, session_id, activity_date, activity_type) VALUES ('3', '2', '2019-07-21', 'send_message');
INSERT INTO Activity (user_id, session_id, activity_date, activity_type) VALUES ('3', '2', '2019-07-21', 'end_session');
INSERT INTO Activity (user_id, session_id, activity_date, activity_type) VALUES ('4', '3', '2019-06-25', 'open_session');
INSERT INTO Activity (user_id, session_id, activity_date, activity_type) VALUES ('4', '3', '2019-06-25', 'end_session');
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*
* Copyright (c) 2024 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
* Use of this source is governed by General Public License that can be found
* in the LICENSE file.
*/

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

SELECT activity_date AS day, COUNT(DISTINCT user_id) AS active_users
FROM activity
WHERE activity_date > '2019-06-27' AND activity_date <= '2019-07-27'
GROUP BY activity_date;

37 changes: 37 additions & 0 deletions src/leetcode/1141.user-activity-for-the-past-30-days-i/src/db.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright (c) 2024 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
// Use of this source is governed by General Public License that can be found
// in the LICENSE file.

use diesel::pg::PgConnection;
use diesel::r2d2::{ConnectionManager, Pool};

use crate::error::{Error, ErrorKind};

pub type DbPool = Pool<ConnectionManager<PgConnection>>;

/// Create postgres database connection pool.
///
/// # Errors
///
/// Returns error if:
/// - No `DATABASE_URL` is set in current environment.
/// - Failed to connect to database.
pub fn get_connection_pool() -> Result<DbPool, Error> {
let url = std::env::var("DATABASE_URL").map_err(|err| {
Error::from_string(
ErrorKind::ConfigError,
format!("DATABASE_URL is not set in environment, err: {err:?}"),
)
})?;
let manager = ConnectionManager::<PgConnection>::new(&url);

Pool::builder()
.test_on_check_out(true)
.build(manager)
.map_err(|err| {
Error::from_string(
ErrorKind::DbConnError,
format!("Failed to create connection pool, url: {url}, err: {err:?}"),
)
})
}
117 changes: 117 additions & 0 deletions src/leetcode/1141.user-activity-for-the-past-30-days-i/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// Copyright (c) 2022 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
// Use of this source is governed by GNU General Public License
// that can be found in the LICENSE file.

#![allow(clippy::enum_variant_names)]

use diesel::result::DatabaseErrorKind;
use std::fmt::{Display, Formatter};
use std::io;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ErrorKind {
ConfigError,

DbConnError,
DbGeneralError,
DbUniqueViolationError,
DbForeignKeyViolationError,
DbNotFoundError,

IoError,
}

unsafe impl Send for ErrorKind {}

#[derive(Debug, Clone)]
pub struct Error {
kind: ErrorKind,
message: String,
}

impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}: {}", self.kind, self.message)
}
}

impl std::error::Error for Error {}

#[allow(dead_code)]
impl Error {
#[must_use]
pub fn new(kind: ErrorKind, message: &str) -> Self {
Self {
kind,
message: message.to_owned(),
}
}

#[must_use]
pub const fn from_string(kind: ErrorKind, message: String) -> Self {
Self { kind, message }
}

#[must_use]
pub const fn kind(&self) -> ErrorKind {
self.kind
}

#[must_use]
pub fn message(&self) -> &str {
&self.message
}
}

impl From<io::Error> for Error {
fn from(err: io::Error) -> Self {
Self::from_string(ErrorKind::IoError, err.to_string())
}
}

impl From<r2d2::Error> for Error {
fn from(err: r2d2::Error) -> Self {
Self::from_string(ErrorKind::DbConnError, format!("r2d2 err: {err}"))
}
}

impl From<diesel::result::Error> for Error {
fn from(err: diesel::result::Error) -> Self {
match &err {
diesel::result::Error::DatabaseError(kind, _info) => match kind {
DatabaseErrorKind::UniqueViolation => {
Self::from_string(ErrorKind::DbUniqueViolationError, err.to_string())
}
DatabaseErrorKind::ForeignKeyViolation => {
Self::from_string(ErrorKind::DbForeignKeyViolationError, err.to_string())
}
_ => Self::from_string(ErrorKind::DbGeneralError, err.to_string()),
},
diesel::result::Error::NotFound => {
Self::from_string(ErrorKind::DbNotFoundError, err.to_string())
}
_ => Self::from_string(ErrorKind::DbGeneralError, err.to_string()),
}
}
}

impl From<std::num::ParseIntError> for Error {
fn from(err: std::num::ParseIntError) -> Self {
Self::from_string(ErrorKind::ConfigError, err.to_string())
}
}

impl From<std::ffi::OsString> for Error {
fn from(err: std::ffi::OsString) -> Self {
Self::from_string(
ErrorKind::ConfigError,
format!("OsString to String err: {err:?}"),
)
}
}

impl From<dotenvy::Error> for Error {
fn from(err: dotenvy::Error) -> Self {
Self::from_string(ErrorKind::ConfigError, format!("dotenv err: {err:?}"))
}
}
25 changes: 25 additions & 0 deletions src/leetcode/1141.user-activity-for-the-past-30-days-i/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) 2024 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
// Use of this source is governed by General Public License that can be found
// in the LICENSE file.

use diesel::connection::SimpleConnection;
use std::env;
use std::fs;

mod db;
mod error;

use error::Error;

fn main() -> Result<(), Error> {
dotenvy::dotenv()?;
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));

let pool = db::get_connection_pool()?;
let mut conn = pool.get()?;
for arg in env::args().skip(1) {
let sql_content: String = fs::read_to_string(arg)?;
conn.batch_execute(&sql_content)?;
}
Ok(())
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @generated automatically by Diesel CLI.

pub mod sql_types {
#[derive(diesel::query_builder::QueryId, Clone, diesel::sql_types::SqlType)]
#[diesel(postgres_type(name = "activity_types"))]
pub struct ActivityTypes;
}

diesel::table! {
use diesel::sql_types::*;
use super::sql_types::ActivityTypes;

activity (id) {
id -> Int4,
user_id -> Int4,
session_id -> Int4,
activity_date -> Date,
activity_type -> Nullable<ActivityTypes>,
}
}

0 comments on commit 512c59e

Please sign in to comment.