Typeorm using class-transformer to change value in table - typeorm

I'm using Nest.js with Typeorm and library class-transformer:
import { Transform } from 'class-transformer';
#PrimaryGeneratedColumn()
#Transform(
({ value }) => `${value}/${moment().format('MM-YYYY')}`,
)
invoiceNumber: string;
I'm trying to generate somethink like this: 1/01-2022. But still I have only an number e.g 1 (without date).
How I can add date to incremented value?

You can use the transformer option.
Specifies a value transformer (or array of value transformers) that is to be used to (un)marshal this column when reading or writing to the database. In case of an array, the value transformers will be applied in the natural order from entityValue to databaseValue, and in reverse order from databaseValue to entityValue.
Source: TypeORM Documentation
transformer has two methods:
to: Used to marshal data when writing to the database.
from: Used to unmarshal data when reading from the database.
class YourClass {
#Column({
primary: true, // Marks column as primary
transformer: {
to(value) {
// Transform 'invoiceNumber'
return `${value}/${moment().format('MM-YYYY')}`;
}
from(value) {
// Do nothing
return value;
}
},
/* Other options... */
})
invoiceNumber: string;
}
Note that the decorator is no more #PrimaryGeneratedColumn but a "simple" #Column with primary option set to true.
The previous decorator is only used as a table-generated primary column.
Column it creates is primary and its value is auto-generated.

Related

Is there any way to reinitialize a mapping

I am trying to code a smart contract and I am using a mapping (address => bool) ; i make it true when a certain conditions meet. Now for another condition I want my mapping to reset and loose all of its data , i want it to be where it was in the beginning a empty mapping.
CODE IMAGE
Problem statement : I am setting all true for whoever voted using in my Dapp using a mapping ( address => bool ) now after voting is ended i want all my mapping values to be false , is there any efficient way to solve this
Thank you in advance..
Now for another condition I want my mapping to reset and loose all of its data , i want it to be where it was in the beginning a empty mapping.
The only way to reset mapping is to iterate through all the keys and set values to zero. This is not practical in Solidity.
Instead, you probably want to use mapping with the third layer and having data tuple of (version, key, value). Then just increment version when you want to do a full reset.
Alternatively you can do (key, version, value) and compare the version every time the key is read. This approach could be more gas efficient, as you are using the same storage lot when rewriting values.
I have found this as most feasible so far;
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.0 <0.9.0;
contract Map {
mapping (uint => uint)[] array;
function allocate(uint newMaps) public {
for (uint i = 0; i < newMaps; i++)
array.push();
}
function writeMap(uint map, uint key, uint value) public {
array[map][key] = value;
}
function readMap(uint map, uint key) public view returns (uint) {
return array[map][key];
}
function eraseMaps() public {
delete array;
}
}

typeorm assigning aliases are not being applied

I haven't been able to find a solution that works for me yet. Whenever I try to apply an alias to a column the column in question is omitted in the return value, all other fields are returned as expected and I've tried various different ways.
export class LeadsData {
constructor(
#InjectRepository(LeadsData, 'leads-legacy')
private readonly leadsDataRepo: Repository<LeadsData>
) {}
public async getData(lead: number): Promise<any> {
const q = await this.leadsDataRepo
.createQueryBuilder('leads-data')
.select('leads-data.user', 'updatedByUser')
.where('leads-data.lead = :lead', { lead })
.getMany()
console.log(q)
return q
}
}
this generates the following sql query:
SELECT `leads-data`.`user` AS 'updateByUser' FROM `leads-data` `leads-data` WHERE `leads-data`.`lead` = ?
When executing the raw query within the database I get the correct results to the query
however, the resulting payload from the query is []
from what I've read in the docs this should work
I should also clarify that if other columns are included then those columns are returned.

TypeORM createQueryBuilder where statement not respecting Enitity column name

I have a pre-existing database table that has a column with a name of account_number, however, I wanted to reference this column in my code as accountNumber instead.
I have the following entity where I set the column name for the property type of accountNumber to be account_number
import { ObjectType, Field } from 'type-graphql';
import { Entity, PrimaryGeneratedColumn, Column, BaseEntity } from 'typeorm';
#ObjectType()
#Entity({ database: 'main', name: 'account' })
class Account extends BaseEntity {
#Field(() => String)
#Column({ name: 'account_number' })
#PrimaryGeneratedColumn()
accountNumber!: string;
#Field(() => String)
#Column()
organisation!: string;
}
export default Account;
This is the query builder that I am having an issue with
await AccountRepository
.createQueryBuilder('a')
.where('a.`account_number` = :accountNumber', { accountNumber: "abc123" })
.getOne();
Expected Behavior
Query to resolve using the account_number column as is stated in the Column decorator.
SELECT `a`.`account_number` AS `a_accountNumber`,
`a`.`organisation` AS `a_organisation`
FROM `main`.`account` `a`
WHERE a.`account_number` = 'abc123'
Actual Behavior
However, it seems to want to use accountNumber instead of account_number even though I have set it as so in the Entity
SELECT `a`.`accountNumber` AS `a_accountNumber`,
`a`.`organisation` AS `a_organisation`
FROM `main`.`account` `a`
WHERE a.`account_number` = 'abc123'
It looks like you're doing the same thing as in this question:
Typeorm ignoring #column name of columns
I'm not clear if this is documented, but I think something is wrong with explicitly named PrimaryColumn() and PrimaryGeneratedColumn(). If you absolutely need the generated column, you should be able to use
#Column(name: 'account_number',
// "serial" type is equivalent to AI in PG
type: 'serial',
primary: true)
accountNumber: string;
(from here: https://github.com/typeorm/typeorm/issues/1517).
Also, you don't need the ! on a primary key, it's always going to be required.

How do I query all documents in a Firestore collection for all strings in an array? [duplicate]

From the docs:
You can also chain multiple where() methods to create more specific queries (logical AND).
How can I perform an OR query?
Example:
Give me all documents where the field status is open OR upcoming
Give me all documents where the field status == open OR createdAt <= <somedatetime>
OR isn't supported as it's hard for the server to scale it (requires keeping state to dedup). The work around is to issue 2 queries, one for each condition, and dedup on the client.
Edit (Nov 2019):
Cloud Firestore now supports IN queries which are a limited type of OR query.
For the example above you could do:
// Get all documents in 'foo' where status is open or upcmoming
db.collection('foo').where('status','in',['open','upcoming']).get()
However it's still not possible to do a general OR condition involving multiple fields.
With the recent addition of IN queries, Firestore supports "up to 10 equality clauses on the same field with a logical OR"
A possible solution to (1) would be:
documents.where('status', 'in', ['open', 'upcoming']);
See Firebase Guides: Query Operators | in and array-contains-any
suggest to give value for status as well.
ex.
{ name: "a", statusValue = 10, status = 'open' }
{ name: "b", statusValue = 20, status = 'upcoming'}
{ name: "c", statusValue = 30, status = 'close'}
you can query by ref.where('statusValue', '<=', 20) then both 'a' and 'b' will found.
this can save your query cost and performance.
btw, it is not fix all case.
I would have no "status" field, but status related fields, updating them to true or false based on request, like
{ name: "a", status_open: true, status_upcoming: false, status_closed: false}
However, check Firebase Cloud Functions. You could have a function listening status changes, updating status related properties like
{ name: "a", status: "open", status_open: true, status_upcoming: false, status_closed: false}
one or the other, your query could be just
...where('status_open','==',true)...
Hope it helps.
This doesn't solve all cases, but for "enum" fields, you can emulate an "OR" query by making a separate boolean field for each enum-value, then adding a where("enum_<value>", "==", false) for every value that isn't part of the "OR" clause you want.
For example, consider your first desired query:
Give me all documents where the field status is open OR upcoming
You can accomplish this by splitting the status: string field into multiple boolean fields, one for each enum-value:
status_open: bool
status_upcoming: bool
status_suspended: bool
status_closed: bool
To perform your "where status is open or upcoming" query, you then do this:
where("status_suspended", "==", false).where("status_closed", "==", false)
How does this work? Well, because it's an enum, you know one of the values must have true assigned. So if you can determine that all of the other values don't match for a given entry, then by deduction it must match one of the values you originally were looking for.
See also
in/not-in/array-contains-in: https://firebase.google.com/docs/firestore/query-data/queries#in_and_array-contains-any
!=: https://firebase.googleblog.com/2020/09/cloud-firestore-not-equal-queries.html
I don't like everyone saying it's not possible.
it is if you create another "hacky" field in the model to build a composite...
for instance, create an array for each document that has all logical or elements
then query for .where("field", arrayContains: [...]
you can bind two Observables using the rxjs merge operator.
Here you have an example.
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/merge';
...
getCombinatedStatus(): Observable<any> {
return Observable.merge(this.db.collection('foo', ref => ref.where('status','==','open')).valueChanges(),
this.db.collection('foo', ref => ref.where('status','==','upcoming')).valueChanges());
}
Then you can subscribe to the new Observable updates using the above method:
getCombinatedStatus.subscribe(results => console.log(results);
I hope this can help you, greetings from Chile!!
We have the same problem just now, luckily the only possible values for ours are A,B,C,D (4) so we have to query for things like A||B, A||C, A||B||C, D, etc
As of like a few months ago firebase supports a new query array-contains so what we do is make an array and we pre-process the OR values to the array
if (a) {
array addObject:#"a"
}
if (b) {
array addObject:#"b"
}
if (a||b) {
array addObject:#"a||b"
}
etc
And we do this for all 4! values or however many combos there are.
THEN we can simply check the query [document arrayContains:#"a||c"] or whatever type of condition we need.
So if something only qualified for conditional A of our 4 conditionals (A,B,C,D) then its array would contain the following literal strings: #["A", "A||B", "A||C", "A||D", "A||B||C", "A||B||D", "A||C||D", "A||B||C||D"]
Then for any of those OR combinations we can just search array-contains on whatever we may want (e.g. "A||C")
Note: This is only a reasonable approach if you have a few number of possible values to compare OR with.
More info on Array-contains here, since it's newish to firebase docs
If you have a limited number of fields, definitely create new fields with true and false like in the example above. However, if you don't know what the fields are until runtime, you have to just combine queries.
Here is a tags OR example...
// the ids of students in class
const students = [studentID1, studentID2,...];
// get all docs where student.studentID1 = true
const results = this.afs.collection('classes',
ref => ref.where(`students.${students[0]}`, '==', true)
).valueChanges({ idField: 'id' }).pipe(
switchMap((r: any) => {
// get all docs where student.studentID2...studentIDX = true
const docs = students.slice(1).map(
(student: any) => this.afs.collection('classes',
ref => ref.where(`students.${student}`, '==', true)
).valueChanges({ idField: 'id' })
);
return combineLatest(docs).pipe(
// combine results by reducing array
map((a: any[]) => {
const g: [] = a.reduce(
(acc: any[], cur: any) => acc.concat(cur)
).concat(r);
// filter out duplicates by 'id' field
return g.filter(
(b: any, n: number, a: any[]) => a.findIndex(
(v: any) => v.id === b.id) === n
);
}),
);
})
);
Unfortunately there is no other way to combine more than 10 items (use array-contains-any if < 10 items).
There is also no other way to avoid duplicate reads, as you don't know the ID fields that will be matched by the search. Luckily, Firebase has good caching.
For those of you that like promises...
const p = await results.pipe(take(1)).toPromise();
For more info on this, see this article I wrote.
J
OR isn't supported
But if you need that you can do It in your code
Ex : if i want query products where (Size Equal Xl OR XXL : AND Gender is Male)
productsCollectionRef
//1* first get query where can firestore handle it
.whereEqualTo("gender", "Male")
.addSnapshotListener((queryDocumentSnapshots, e) -> {
if (queryDocumentSnapshots == null)
return;
List<Product> productList = new ArrayList<>();
for (DocumentSnapshot snapshot : queryDocumentSnapshots.getDocuments()) {
Product product = snapshot.toObject(Product.class);
//2* then check your query OR Condition because firestore just support AND Condition
if (product.getSize().equals("XL") || product.getSize().equals("XXL"))
productList.add(product);
}
liveData.setValue(productList);
});
For Flutter dart language use this:
db.collection("projects").where("status", whereIn: ["public", "unlisted", "secret"]);
actually I found #Dan McGrath answer working here is a rewriting of his answer:
private void query() {
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection("STATUS")
.whereIn("status", Arrays.asList("open", "upcoming")) // you can add up to 10 different values like : Arrays.asList("open", "upcoming", "Pending", "In Progress", ...)
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot queryDocumentSnapshots, #Nullable FirebaseFirestoreException e) {
for (DocumentSnapshot documentSnapshot : queryDocumentSnapshots) {
// I assume you have a model class called MyStatus
MyStatus status= documentSnapshot.toObject(MyStatus.class);
if (status!= null) {
//do somthing...!
}
}
}
});
}

Using tablesorter custom parser only for filtering

I have a table with checkbox column for which filter is used so I can get only selected rows.
I've added custom parser for that column to use checkboxes' "checked" prop values for filtering.
The thing is that parser is added to column using 'sorter' property in 'headers' option for tablesorter initializer, so that when I click on some checkbox and trigger 'update' event, sorting is applied to checkbox column and selected rows are moved to the bottom of the table.
Is there a way to add parser to column so that it's used only for filtering, not for sorting?
UPD: I think I should clarify what I'm trying to do.
I have a custom parser for checkboxes that looks like the following:
var myCustomParser = {
id: 'myCustomParser',
is: function() { return false; },
format: function(cellText, table, cellNode, cellIndex) {
return $(cellNode).find('.checkbox-to-find').prop('checked') ? '1' : '0';
},
parsed: true,
type: 'text'
};
Then I add it to tablesorter and use in initializer:
$.tablesorter.addParser(myCustomParser);
//...
$table.tablesorter({
// ...
headers: {
0: {sorter: 'myCustomParser'}
},
//...
);
This enables filtering but sorting is also applied. I have a checkbox for selecting all rows in header cell for that column and when I click it sorting is applied and checkboxes are sorted.
This is what I use for now to disable sorting:
$table.tablesorter({
//...
textSorter: {
0: function() { return 0; }
},
headers: {
0: {sorter: 'myCustomParser'}
},
//...
);
Stub sorter practically disables sorting while leaving filter enabled. But this seems wrong. According to docs I can't use parser option for setting parser name. filter option also seems to be only for false and parsed values. I'd like to be able to do something like this:
$table.tablesorter({
// ...
headers: {
0: {parser: 'myCustomParser'}
},
//...
);
If this would enable parsing (and make filtering use these parsed values) while keeping sorting disabled, that would be great.
P.S. I've found out there's a parser for checkboxes in repo, but the question remains: how do I specify parser so that sorting is not enabled.
I am guessing that you are using my fork of tablesorter. If that is the case, setting the column to not sort does not stop the parser from processing the information in that column. Here is some information you may have missed in the documentation.
Column features (sort, filter or parsing) can be disabled using any of the methods within the associated section (they all do the same thing), in order of priority:
Disable sort (ref)
Parsing of column content still occurs
jQuery data data-sorter="false".
Metadata class="{ sorter: false }". This requires the metadata plugin.
Headers option headers : { 0 : { sorter: false } }.
Header (<th>) class name class="sorter-false".
Disable filter (ref)
jQuery data data-filter="false".
Metadata class="{ filter: false }". This requires the metadata plugin.
Headers option headers : { 0 : { filter: false } }.
Header (<th>) class name class="filter-false".
If using the "all" column external filter, the disabled column will be included in the query. You can exclude the disabled column by setting a range in the column attribute of the external filter (ref)
<input class="search" type="search" data-column="0-2,4,6-7">
Disable parsing (ref)
When parsing is disabled, both sorting and filtering are automatically disabled, and the column data stored within the cache is set to an empty string.
jQuery data data-parser="false".
Metadata class="{ parser: false }". This requires the metadata plugin.
Headers option headers : { 0 : { parser: false } }.
Header (<th>) class name class="parser-false".
Update: In your case, I would disable sorting (using any sorter methods above), then use a custom textExtraction function that targets the column containing checkboxes:
textExtraction : {
0 : function(node, table, cellIndex) {
return $(node).find('.checkbox-to-find').prop('checked') ? '1' : '0';
}
}

Resources