Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

necrotic posted:

One of the biggest lessons to learn from that help is to work at breaking down what you are doing into smaller chunks. One big function doing a lot of stuff is generally a signal that it can be broken down into smaller "units of work" that each individually solve a smaller part of the larger problem.
But also don't go nuts with it. I know someone who insists that if a function is more than ten lines long you should break it into more functions, but really if it's just doing one sequential bunch of things it's fine to be lots of lines.

If you have a three-line *condition*, on the other hand, that's something that is probably worth making a little function for, because if nothing else if (thing.smellsBad()) is much easier to quickly understand in passing when you're reading your code later than if (thing.scentRatio>0.8 && thing.scentType==ScentType.Bad && !dog.hasNoNose).

Adbot
ADBOT LOVES YOU

Wheany
Mar 17, 2006

Spinyahahahahahahahahahahahaha!

Doctor Rope
One case where I will make completely trivial functions is when I'm filtering a collection. So if you have multple things in a list then instead of
JavaScript code:
const smellyThings = things.filter(thing => thing.scentRatio>0.8 && thing.scentType==ScentType.Bad)
I will do
JavaScript code:
const hasHighScent = thing => thing.scentRatio > 0.8;
const hasBadSmell = thing => thing.scentType == ScentType.Bad;

const smellyThings = things.filter(hasHighScent)
                           .filter(hasBadSmell)

necrotic
Aug 2, 2005
I owe my brother big time for this!
I would split into two filter calls with anonymous functions if it was a one off. If those specific filtering rules apply to multiple spots then yeah I’d define helper functions. For a one-off I’d argue that’s “too much”

KoRMaK
Jul 31, 2012



This feels like a really stupid question but I cant figure out what the transom I have to bridge is: I have a webpack that has sortablejs in it, and I'd like to be able to call sortablejs from the browser's dev tools console, just like i could when I was using jquery, so I can interactively play around with it. how do I do that? my full tech stack is rails and yarn based

necrotic
Aug 2, 2005
I owe my brother big time for this!

KoRMaK posted:

This feels like a really stupid question but I cant figure out what the transom I have to bridge is: I have a webpack that has sortablejs in it, and I'd like to be able to call sortablejs from the browser's dev tools console, just like i could when I was using jquery, so I can interactively play around with it. how do I do that? my full tech stack is rails and yarn based



If you’ve webpacked everything is in one module with a bespoke “require/import” to work in that one bundle.

The hacky stupid approach I will suggest is to do a window.sortablejs = require (…) somewhere in your sources to make the package available to the console.

There may be a better solution, I don’t know or care to look because bundling generally works this way.

import in web (as you are using in the console) is very specific to ES modules. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules

If your webpack can / is setup to spit out ESM that would work with import it may be changing the module name, but I haven’t really worked with ESM so don’t really know.

Edit: and you are seeing the original source with the webpack:// prefixes because of Source Maps. That is _not_ the actual JS that is executing in the browser, it’s mapping that browser file back to the original sources for debugging.

necrotic fucked around with this message at 19:19 on Feb 24, 2024

KoRMaK
Jul 31, 2012



necrotic posted:


The hacky stupid approach I will suggest is to do a window.sortablejs = require (…) somewhere in your sources to make the package available to the console.
debugging.
perfect! this makes a lot of sense. thank you!

code:
// app/javascript/packs/application.js
import Sortable from 'sortablejs';

window.sortablejs = Sortable

// dev tools console
sortablejs.get(demo1).toArray()
(5) ['3v8', '3ve', '4f9', '4g8', '44p']

Ima Computer
Oct 28, 2007

Stop all the downloading!

Help computer.
Alternative method: set a breakpoint in your JS code in a place where where that package is available. When the debugger hits the breakpoint and JS execution is paused, your console will have access to all variables in scope for the currently executing code.

KoRMaK
Jul 31, 2012



Ima Computer posted:

Alternative method: set a breakpoint in your JS code in a place where where that package is available. When the debugger hits the breakpoint and JS execution is paused, your console will have access to all variables in scope for the currently executing code.
Yes I had considered this but since you are at a breakpoint time is frozen and you can't interact with the rendered browser ui as you normally would.

necrotic
Aug 2, 2005
I owe my brother big time for this!

KoRMaK posted:

Yes I had considered this but since you are at a breakpoint time is frozen and you can't interact with the rendered browser ui as you normally would.

You should be able to assign whatever you want to a variable (possibly on the window again) and then resume with that approach.

KoRMaK
Jul 31, 2012



that's a very neat trick and has managed to dispell a lot of mystery around using node modules in my project that i just hadn't given a poo poo to dive into. now i understand how to grow another piece of my infra.


soooo long inline javascript

The Merkinman
Apr 22, 2007

I sell only quality merkins. What is a merkin you ask? Why, it's a wig for your genitals!
I was playing around with making a calendar, and I'm very confused about getDay(). I know 0 = Sun, it's not that.
Why is it putting in an ISO string makes the value 1 less than it should be?
JavaScript code:
const never = new Date('September 11, 2001').getDay();
// returns 2, which is Tuesday, which is correct
const forget = new Date('2001-09-11').getDay();
// returns 1 ???

MrMoo
Sep 14, 2000

lol, use Luxon DateTime for anything more than fetching the current time.

REF: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

quote:

Note: While the time value at the heart of a Date object is UTC, the basic methods to fetch the date and time or its components all work in the local (i.e. host system) time zone and offset.

The long form date is in the local timezone, the short form date is in UTC. NodeJS CLI is good for debugging this.
code:
> new Date('September 11, 2001')
2001-09-11T04:00:00.000Z
> new Date('2001-09-11')
2001-09-11T00:00:00.000Z

The Merkinman
Apr 22, 2007

I sell only quality merkins. What is a merkin you ask? Why, it's a wig for your genitals!

MrMoo posted:

lol, use Luxon DateTime for anything more than fetching the current time.

REF: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

The long form date is in the local timezone, the short form date is in UTC. NodeJS CLI is good for debugging this.
code:
> new Date('September 11, 2001')
2001-09-11T04:00:00.000Z
> new Date('2001-09-11')
2001-09-11T00:00:00.000Z

So because a time zone isn't defined, it's using a time zone where September 11, 2001 was a Monday? OK :confused:

go play outside Skyler
Nov 7, 2005


The Merkinman posted:

So because a time zone isn't defined, it's using a time zone where September 11, 2001 was a Monday? OK :confused:

No, it's because you are calling the function from a time zone where it was still monday september 10th in UTC time.

As another poster said, don't use JS Date object to parse a date. It's better to use something like moment or whatever the new hotness is.

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

go play outside Skyler posted:

As another poster said, don't use JS Date object to parse a date. It's better to use something like moment or whatever the new hotness is.

don't use moment in new code. https://momentjs.com/docs/#/-project-status/

it's funny because there were all these years of "don't use raw dates, use moment", and now it's luxon. oh well.

AlphaKeny1
Feb 17, 2006

https://dev.to/zachgoll/a-complete-guide-to-javascript-dates-and-why-your-date-is-off-by-1-day-fi1

I believe this article covers it.

And yeah don't use javascript date objects, use some library like moment.js

edit: nm don't use moment

Obfuscation
Jan 1, 2008
Good luck to you, I know you believe in hell
Does anyone know why Temporal is still not ready?

necrotic
Aug 2, 2005
I owe my brother big time for this!
Death by committee ?

MrMoo
Sep 14, 2000

Obfuscation posted:

Does anyone know why Temporal is still not ready?

Blame Microsoft for wanting a 1601 epoch and 100ns units? It has to be something esoteric, probably more related to the multitude of complex calendaring schemes. There are two polyfills though:

https://github.com/js-temporal/temporal-polyfill#readme
https://github.com/fullcalendar/temporal-polyfill#readme

I was impressed a lot of nice stuff has been hitting V8 recently:

https://v8.dev/blog/holiday-season-2023#:~:text=New%20JavaScript%20features

MrMoo fucked around with this message at 20:57 on Mar 19, 2024

Harriet Carker
Jun 2, 2009

Bruegels Fuckbooks posted:

don't use moment in new code. https://momentjs.com/docs/#/-project-status/

it's funny because there were all these years of "don't use raw dates, use moment", and now it's luxon. oh well.

I like date-fns myself!

camoseven
Dec 30, 2005

RODOLPHONE RINGIN'
Big Day.js fan here

Doktor Avalanche
Dec 30, 2008

would using the regular Date lib with only UTC avoid these kinds of mixups? that's what we do at my job.

biznatchio
Mar 31, 2001


Buglord

Doktor Avalanche posted:

would using the regular Date lib with only UTC avoid these kinds of mixups? that's what we do at my job.

In general yes... until someone does new Date('September 11, 2001') with the crazy expectation that it will act the same as new Date('2001-09-11').

The standard Javascript Date object is fundamentally flawed. The only advisable way to use it is delete globalThis.Date.

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

biznatchio posted:

In general yes... until someone does new Date('September 11, 2001') with the crazy expectation that it will act the same as new Date('2001-09-11').

The standard Javascript Date object is fundamentally flawed. The only advisable way to use it is delete globalThis.Date.

Date.parse in particular is hella hosed up. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#examples

Some highlights:
1. Non standard date strings were allowed to be implementation specific, so there's no guarantee they work the same between any browser.
2. There's no parameter for the expected format of the date string, or region of the date string, so it's up to the browser implementation to guess from the content of the string which date format it is - which is great when it tries to parse a string like 9-11-2001, which could easily parse as December 9, 2001 in some parts of the world.

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense
Writing my own SQL ORM, I have a schema like this:

JavaScript code:

export default createSchema({
    tables: [
        {
            name: 'Address',
            columns: [
                { name: 'id', type: 'uuid', auto: true },
                { name: 'userId', type: 'uuid' },
                { name: 'name', type: 'string', nullable: true },
                { name: 'city', type: 'string' },
            ],
            indexes: [
                { type: 'primary', column: 'id' },
                { type: 'unique', column: 'userId' },
            ],
            foreignKeys: [
                { table: 'User', id: 'id', column: 'userId', onUpdateDelete: 'cascade' },
            ],
        },
        {
            name: 'Pet',
            columns: [
                { name: 'id', type: 'uuid', auto: true },
                { name: 'userId', type: 'uuid' },
                { name: 'name', type: 'string' },
                { name: 'type', type: 'enum', values: ['dog', 'cat', 'fish'] },
            ],
            indexes: [
                { type: 'primary', column: 'id' },
            ],
            foreignKeys: [
                { table: 'User', id: 'id', column: 'userId', onUpdateDelete: 'cascade' },
            ],
        },
        {
            name: 'User',
            columns: [
                { name: 'id', type: 'uuid', auto: true },
                { name: 'name', type: 'string' },
            ],
            indexes: [
                { type: 'primary', column: 'id' },
            ],
        },
    ],
});
And that's great and I might have types therefore that look like this:

JavaScript code:
export interface DbAddress {
    id: string;
    userId: string;
    name: string | null;
    city: string;
    user?: DbUser;
}

export interface DbPet {
    id: string;
    userId: string;
    name: string;
    type: 'dog' | 'cat' | 'fish';
    user?: DbUser;
}

export interface DbUser {
    id: string;
    name: string;
    address?: DbAddress;
    pets?: DbPet[];
}
But the only way I have really figured out how to get that schema to become these types is to actually programmatically generate a types.ts file. Which is ok, I am doing that I'm just working out what is the best solution. For one thing it means I'm generating a file inside of the node_modules directory, which doesn't seem right. I think prisma does that but just because prisma does it doesn't mean it's necessarily the best solution.

I've played around with putting the generated types in the project directory but I'm having a lot of problems when it comes to using those types inside my module, I'm effectively forced to use dynamic imports which are asynchronous.

I asked copilot and it says I can do funny things with typescript like this:

JavaScript code:
// Utility function to dynamically create a type based on a JavaScript array of strings
function createDynamicType(keys: string[]): Record<string, string | number> {
    const result: Record<string, string | number> = {};
    keys.forEach(key => {
        result[key] = 'string'; // You can customize the type here based on your requirements
    });
    return result;
}

// Example usage with a JavaScript array of strings
const dynamicKeysArray = ['id', 'name', 'age'];
type DynamicObject = typeof createDynamicType(dynamicKeysArray);

// Now DynamicObject is equivalent to { id: string, name: string, age: string }
const myData: DynamicObject = {
    id: '123',
    name: 'John',
    age: '25'
};
But I haven't worked out how to use this knowledge or if it's a sensible approach, or if I can make it dynamically reference other dynamically generated types. What is best, I'm leaning towards my generate a types file in node_modules approach.

Nolgthorn fucked around with this message at 02:28 on Mar 21, 2024

N.Z.'s Champion
Jun 8, 2003

Yam Slacker
I don't know but many validators (eg Zod) have code schema -> TS without generating type files so for simple cases it seems possible to avoid it. Do you really need to generate type files?

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense
It would be really cool if I could figure out how not to. One of the problems with generating the types file is that my orm can only really support one database at a time without risking types mapping over one another.

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense
Having trouble getting anything else to work but I found a solution to the "only one database" problem. Have schema include a type prefix:

JavaScript code:
export default createSchema({
    typePrefix: 'Db',
    tables: [
        {
Then the generated code:

JavaScript code:
export type DbKey = 'Db';
export type DbTableKey = 'User' | 'Address' | 'Pet';

// MAPS
export type DbUtil = { [K in DbKey]: DbTableMap[K] };

interface DbTableMap {
    Db: { row: DbTableRow, options: DbTableOptions, where: DbTableWhere, select: DbTableSelect, include: DbTableInclude };
}
type DbTableRow = { [K in DbTableKey]: DbTableRowMap[K]; };
type DbTableOptions = { [K in DbTableKey]: DbTableOptionsMap[K]; };
type DbTableWhere = { [K in DbTableKey]: DbTableWhereMap[K]; };
type DbTableSelect = { [K in DbTableKey]: DbTableSelectMap[K]; };
type DbTableInclude = { [K in DbTableKey]: DbTableIncludeMap[K]; };

interface DbTableRowMap {
    User: DbUserRow;
    Address: DbAddressRow;
    Pet: DbPetRow;
}

etc
Then I can access the type using:

JavaScript code:
DbUtil['Db']['options']['User']
Or something like that.

It's sort of like I definitely have to use generics, I can't just lookup types using strings in my code... generics is how I did it originally but I thought I'd try and find a way to remove the litany of generics everywhere in the codebase.

Nolgthorn fucked around with this message at 13:30 on Mar 21, 2024

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense
Perhaps in an effort to go crazy I have made a little bit of headway regarding inferred types.

JavaScript code:
const mySchema = {
    tables: [
        {
            name: 'Address',
            columns: [
                { name: 'id', type: 'uuid', auto: true },
                { name: 'userId', type: 'uuid' },
                { name: 'name', type: 'string', nullable: true },
                { name: 'city', type: 'string' },
            ],
            indexes: [
                { type: 'primary', column: 'id' },
                { type: 'unique', column: 'userId' },
            ],
            foreignKeys: [
                { table: 'User', id: 'id', column: 'userId', onUpdateDelete: 'cascade' },
            ],
        },
        {
            name: 'Pet',
            columns: [
                { name: 'id', type: 'uuid', auto: true },
                { name: 'userId', type: 'uuid' },
                { name: 'name', type: 'string' },
                { name: 'type', type: 'enum', values: ['dog', 'cat', 'fish'] },
            ],
            indexes: [
                { type: 'primary', column: 'id' },
            ],
            foreignKeys: [
                { table: 'User', id: 'id', column: 'userId', onUpdateDelete: 'cascade' },
            ],
        },
        {
            name: 'User',
            columns: [
                { name: 'id', type: 'uuid', auto: true },
                { name: 'name', type: 'string' },
            ],
            indexes: [
                { type: 'primary', column: 'id' },
            ],
        },
    ],
} as const;

type Schema = typeof mySchema;
type Table = Schema['tables'][number];
type Column = Table['columns'][number];

type TypeMapping = {
    boolean: boolean;
    date: Date;
    datetime: Date;
    enum: string;
    integer: number;
    string: string;
    text: string;
    time: Date;
    uuid: string;
};

type ColumnType<T extends Column> = T extends { type: 'enum', values: readonly string[] }
    ? T['values'][number]
    : TypeMapping[T['type']];

type NullableType<T extends Column> = T extends { nullable: true }
    ? ColumnType<T> | null
    : ColumnType<T>;

type TableType<T extends Table> = {
    [K in T['columns'][number]['name']]: NullableType<Extract<T['columns'][number], { name: K }>>
};

type User = TableType<Extract<Table, { name: 'User' }>>;
type Address = TableType<Extract<Table, { name: 'Address' }>>;
type Pet = TableType<Extract<Table, { name: 'Pet' }>>;

const address: Address = {
    id: 'a-uuid',
    userId: 'a-uuid',
    name: null,
    city: 'a-string',
};

const pet: Pet = {
    id: 'a-uuid',
    userId: 'a-uuid',
    name: 'a-string',
    type: 'dog',
};

const user: User = {
    id: 'a-uuid',
    name: 'a-string',
};
The trick is to use `as const` on the schema object. This allows all kinds of inference operations because typescript then knows that the data doesn't change, `T extends { name: 'userId' }` isn't going to suddenly have any of the possible keys from other objects of the array, it's got the keys that's on it's object.

However this is about as far as I can go.

I am using `createSchema(mySchema)` to provide the user with types while building the object. There isn't any way at least that I've found to have `createSchema` accept an object of a specific type and also have that object be of type const.

JavaScript code:
export function createSchema (schema: TSchemaOptions) {
    return schema;
}
Like, you can only use as const when the object is defined. So, I dunno a bit of an ugly user experience if I require the user to say `createSchema({} as const)` but also it eliminates type checking which is the entire point of the function. This function the way it's written eliminates any possibility of the object being of type const. Which is what it needs to be. Other libraries seem to have this figured out but I haven't figured out how to read their codebases.

So that's a roadblock.

The other big setback is that I still need my Address type to have a user parameter that maps to the User type. Also visa-versa. In code I'm figuring out what these associations are with a sweet javascript function that calculates all of them.

But I can't use that... because then I'm no longer in type world. It's like I have to look at the Address table referencing the User table and then that means the User type should have a address parameter.

Almost like instead of having the user define foreign keys, I should be doing that programmatically and instead have them define what all the relationships between tables are. A massive change largely just so that I can more easily negotiate types. Furthermore I'm really not certain what happens if the Address object type infers a User object type which infers a Address object type.

Isn't that gonna spin my cpus into the stratosphere?

Nolgthorn fucked around with this message at 11:27 on Mar 26, 2024

Osmosisch
Sep 9, 2007

I shall make everyone look like me! Then when they trick each other, they will say "oh that Coyote, he is the smartest one, he can even trick the great Coyote."



Grimey Drawer
So you're just doing this as an exercise right? Because otherwise Sequelize exists and mostly does what you want, I think?

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense
Why did I think I shouldn't use sequelize, I thought a long time ago everyone switched to knex. Then it was prisma and now drizzle. Ultimately you're correct we don't need it but when I built my own testing framework for example I learned a heck of a lot. When I built my own web framework that has been the most useful thing ever, it's the best node web framework out there in my opinion. At least when it comes to apis and simple sites, it can't do the fancy things that next can do but it's really easy to use and does everything I need, it's the only one out there that does cors properly.

Ultimately, I learned a lot, and this sql orm is the same. Although, my sabbatical is ending and I don't think I'm going to finish it in time. It's turned out to be about 10 times harder than a web framework to make.

Nolgthorn fucked around with this message at 11:08 on Mar 26, 2024

Osmosisch
Sep 9, 2007

I shall make everyone look like me! Then when they trick each other, they will say "oh that Coyote, he is the smartest one, he can even trick the great Coyote."



Grimey Drawer
I mean, in my opinion ORMs are cursed anyway, especially the ones that encourage active-record stuff. I think repository methods that do regular queries combined with proper result type checking with e.g. Zod are a cleaner way to interact with your DB, and have the added benefit of letting you already get out of db-land and into domain logic.

That said, even if it's an exercise I think you could probably get more guidance on your path by peeking at the source code for Sequelize and Zod than from me trying to parse what you're doing and giving targeted advice. Either way, respect for trying something out and posting about it, it's interesting to read!

Polio Vax Scene
Apr 5, 2009



Given I have a bunch of rectangular coordinates for blocks of text, what would be the best way to add them as selectable text blocks to a page and ensure their text content fits within the coordinates best it can?

Nolgthorn
Jan 30, 2001

The pendulum of the mind alternates between sense and nonsense
You have to do something like render it on the page with no height or width, measure it, then adjust the size using a percentage. There's no easy way to do it because different fonts and operating systems and browsers and etc.

Adbot
ADBOT LOVES YOU

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Nolgthorn posted:

You have to do something like render it on the page with no height or width, measure it, then adjust the size using a percentage. There's no easy way to do it because different fonts and operating systems and browsers and etc.
I *think* you can do it render-measuring in a hidden element to avoid creating screen jitter. If not, there's definitely TextMetrics from a CanvasRenderingContext2D.measureText() you can use for this. My experience is the least problematic way to get to a good font size for some constraints is to start with a maximum and minimum acceptable size and binary search for the best fit to within a precision tolerance. i.e. binary search until the difference between "largest one that fit" and "smallest one that was too big" is less than some arbitrary threshold, then use the "largest one that fit" value.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply