# Multi-user CRUD: Valid, Problem, or Error?

## Introduction:

Ever used Dropbox with some other people and you both modified the same file? Ever had a multi-user application with a relational database, and two people were modifying (or worse, one was deleting and the other modifying) the same object? Well, let's simulate that with this challenge (sort-of).

For the sake of this challenge, we only have two users and either one or two relevant files. Both users have in general privileges to CRUD (Create, Read, Update, and Delete) all files.

## Challenge:

### Input:

We'll have a few inputs (input format is flexible, and any reasonable format is allowed):

1) Locking mode (on/off): Kinda the difference between optimistic and pessimistic concurrency locking.
Both users are allowed to CRUD (Create, Read, Update, and Delete) everything, but sometimes errors or problems can occur. Depending on the locking mode a problem when turned off, could be an error when turned on. This is explained below in the Output section.

2 & 3) Two user-actions. These actions always consist of two things: What the user does (Create, Read, Update, or Delete) and for which file.

### Output:

We'll have three possible outputs:

1. Valid: Both actions by both users can be done simultaneously without any issues occurring.
2. Error: Both actions by both users cannot be done simultaneously and causes an error for one of the users (which user is irrelevant for this challenge). This can occur when:
• one user Reads or Updates a file, which the other user Deletes;
• both users Update the same file with locking mode turned on;
• a user Creates a file, which the other user Reads/Updates/Deletes (this means the file already exists, so it cannot be Created);
• both users Create the same file.
3. Problem: Both actions by both users can be done simultaneously, but can cause unexpected problems. This can occur when:
• both users Update a file when locking mode is turned off;
• one user Updates a file, which the other user Reads;
• both users Delete the same file (practically this will causes an error for the second user, but since it will still be deleted like the user wants, it will be a problem instead of an error for the sake of this challenge)

## Challenge Rules:

• All input and output is flexible, and everyone should state which one they've used in their answer!
Example inputs: 0/1 for locking mode & 31 (third action: Update; file: 1) & 21 (second action: Read; file: 1); true/false for locking mode & ['C','A'] (action: Create; file: A) & ['D','B'] (action: Delete; file: B); etc.
Example outputs: null/true/false (null = valid; true = error; false = problem); -1/0/1 (-1 = error; 0 = problem; 1 = valid); etc. The three possible outputs have to be unique and distinct for the three output-type, though.
• What the files are called is irrelevant, which can also be seen with the input-examples above. So feel free to use any type of file name in your answers consisting of a single (ASCII) letter or digit. They do have to be consistent across all your test cases however, so you can't use A/B in one test case and 1/2 in another.
• The four actions for CRUD have to be unique and consistent values as well. So you cannot use 'D'/'C' in one test case, and then 4/1 in another test case.
• You can assume that the file chosen by a user always exists when they want to Read, Update, or Delete it.

## General rules:

• This is , so shortest answer in bytes wins.
Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
• Standard rules apply for your answer with default I/O rules, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters and return-type, full programs. Your call.
• Default Loopholes are forbidden.
• If possible, please add a link with a test for your code (i.e. TIO).
• Also, adding an explanation for your answer is highly recommended.

## All possible test cases (where the actions can be in either input-order†):

: You should support all (up to four) variations of the test cases below. So if a test case states action1: Create file A; action2: Update file B, that test case should also hold the same results for action1: Create file B; action2: Update file A; action1: Update file B; action2: Create file A; and action1: Update file A; action2: Create file B.

Valid use-cases:

locking mode: either;  action1: Create file A;  action2: Create file B
locking mode: either;  action1: Create file A;  action2: Read file B
locking mode: either;  action1: Create file A;  action2: Update file B
locking mode: either;  action1: Create file A;  action2: Delete file B
locking mode: either;  action1: Read file A;    action2: Read file A
locking mode: either;  action1: Read file A;    action2: Read file B
locking mode: either;  action1: Read file A;    action2: Update file B
locking mode: either;  action1: Read file A;    action2: Delete file B
locking mode: either;  action1: Update file A;  action2: Update file B
locking mode: either;  action1: Update file A;  action2: Delete file B
locking mode: either;  action1: Delete file A;  action2: Delete file B

Error use-cases:

locking mode: either;  action1: Create file A;  action2: Create file A
locking mode: either;  action1: Create file A;  action2: Read file A
locking mode: either;  action1: Create file A;  action2: Update file A
locking mode: either;  action1: Create file A;  action2: Delete file A
locking mode: either;  action1: Read file A;    action2: Delete file A
locking mode: on;      action1: Update file A;  action2: Update file A
locking mode: either;  action1: Update file A;  action2: Delete file A

Problem use-cases:

locking mode: either;  action1: Read file A;    action2: Update file A
locking mode: off;     action1: Update file A;  action2: Update file A
locking mode: either;  action1: Delete file A;  action2: Delete file A

• I feel like there will be a 1 byte solution if I can just come up with the right input/output methods (maybe some kind of bit masking) – Expired Data Jul 4 at 9:32
• @ExpiredData Altered a few parts of the possible outputs, that they have to be consistent, but not necessarily unique. And also that the inputs have to be consistent. – Kevin Cruijssen Jul 4 at 9:35
• @Arnauld Ah, I excluded all B/B cases in my counting, since I deemed them similar as A/A. That's where the difference is coming from. But I guess that thinking is incorrectly if you have a specific value for the files.. – Kevin Cruijssen Jul 4 at 12:52

# JavaScript (ES6), 36 bytes

### Without a lookup table

(m,a,f,A,F)=>f-F?2:a^A?a*A&8:a&4?m:a


Try it online!

### I/O

• Locking mode ($$\m\$$): $$\0\$$ = On, $$\8\$$ = Off
• Actions ($$\a\$$ and $$\A\$$): $$\0\$$ = Create, $$\2\$$ = Read, $$\4\$$ = Update, $$\8\$$ = Delete
• Files ($$\f\$$ and $$\F\$$): any integers
• Output: $$\0\$$ = Error, $$\2\$$ = Valid, $$\8\$$ = Problem

### How?

If the files are different, all operations are safe and we just return $$\2\$$ (valid).

If the files are identical, we need to return:

• $$\2\$$ (valid) if we have two read operations
• $$\8\$$ (problem) if we have two delete operations, or one update and one read
• $$\m\$$ (either problem or error) if we have two update operations
• $$\0\$$ (error) for everything else

Using a $$\4\times4\$$ CRUD matrix (which is symmetric by definition), we can see that the above values can be computed with:

$$\underbrace{\text{a ^ A}}_{a\neq A?}\text{ ? }\color{blue}{\text{a * A & 8}}\text{ : }\underbrace{\text{a & 4}}_{\text{update?}}\text{ ? }\color{red}{\text{m}} : \color{magenta}{\text{a}}$$

$$\begin{array}{cc|cccc} &&\text{C}&\text{R}&\text{U}&\text{D}\\ &&0&2&4&8\\ \hline \text{C}&0&\color{magenta}{0}&\color{blue}{0}&\color{blue}{0}&\color{blue}{0}\\ \text{R}&2&\color{blue}{0}&\color{magenta}{2}&\color{blue}{8}&\color{blue}{0}\\ \text{U}&4&\color{blue}{0}&\color{blue}{8}&\color{red}{\text{m}}&\color{blue}{0}\\ \text{D}&8&\color{blue}{0}&\color{blue}{0}&\color{blue}{0}&\color{magenta}{8} \end{array}$$

# JavaScript (ES6),  46 45  40 bytes

### With a lookup table

(m,a,f,A,F)=>f-F?0:[m,1,1,0][a*2+A*9&23]


Try it online!

### I/O

• Locking mode: undefined = On, $$\1\$$ = Off
• Actions: $$\0\$$ = Update, $$\1\$$ = Read, $$\2\$$ = Create, $$\3\$$ = Delete
• Files: any integers
• Output: undefined = Error, $$\0\$$ = Valid, $$\1\$$ = Problem

# Retina 0.8.2, 53 bytes

^(.)(?!\1).+|..RR.
V
..DD.
P
..UUL
E
.+[CD].+
E
..+
P


Try it online! Link includes test suite. Takes input as a string of 5 characters, two characters representing the file names, then two characters from CRUD, then L or U (locked/unlocked), and outputs one of VPE (valid/problem/error). Explanation:

^(.)(?!\1).+|..RR.
V


Different file names are always valid, as are two reads. Annoyingly, this is the only test that forces me to use a header. (It would cost an extra byte to make the header unnecessary.)

..DD.
P


Two deletes are always a problem.

..UUL
E


Two locked updates are an error.

.+[CD].+
E


Any other creates or deletes are an error.

..+
P


Everything else is a problem.

# Octave, 96 bytes

@(a,b,c)[a(1)!=b(1)|a(2)+b(2)==20,mod((m=a+b+c)(2),10010)<1|mod(m(2),1020000)<1|mod(m(2),200)<1]


Try it online!

Definitely can be shorter, but I don't have time right now to do that

File 1 = 0
File 2 = 1
Delete = 100
Create = 1000
Update = 10000
Lock on = 100000
Lock off = 1000000

Valid Values:
[1 0]

Problem Values:
[0 1]

Invalid Values:
[0 0]


Input as a = [file, action], b = [file2, action2], c = lock